From 70ffaead720155c1fc8924b6165d805dccc28b54 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 14:40:47 -0400 Subject: [PATCH 01/99] chore(mobile): target Sepolia for the EVM surface --- mobile/env.example | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/mobile/env.example b/mobile/env.example index ba00dd7e..e950e136 100644 --- a/mobile/env.example +++ b/mobile/env.example @@ -1,3 +1,7 @@ +# Copy to `.env`. Changes need `pnpm --prefix mobile start --reset-cache` AND a +# rebuild: react-native-dotenv inlines `@env` at Babel transform time, so a +# reload alone picks up nothing. An installed APK has the old values bundled in. + # WalletConnect Project ID # Get your project ID from https://dashboard.reown.com/ REOWN_PROJECT_ID=your_project_id_here @@ -9,10 +13,38 @@ REOWN_PROJECT_ID=your_project_id_here # Metro dev server (http://localhost:8081, http://127.0.0.1:8081, http://YOUR_LAN_IP:8081), # and native bundle IDs if the dashboard asks for them (e.g. com.cryptopets on Android). -# CryptoPets Solana (same program as web `VITE_CRYPTOPETS_PROGRAM_ID`) +# Backend API. Android emulator → host is 10.0.2.2. Physical device → your LAN IP. +API_URL=http://localhost:3001 + +# --- EVM (v2) --- +# Chain id the addresses below live on: 31337 Hardhat, 11155111 Sepolia, +# 84532 Base Sepolia. Mobile targets Sepolia because that is the only network +# with a live PetCore and GameLogic; see docs/plan-mobile-frontend-parity.md +# Phase 0.1. This is a deliberate divergence from frontend, which lists only +# Base Sepolia in its CHAINS. +EVM_CHAIN_ID=11155111 + +# Sepolia (11155111) v2 deployment. Verified on-chain 2026-08-05: PetCore and +# GameLogic are both live proxies, and GameLogic.petCore()/gameConfig() point +# back at the two addresses below. +# Known gap: this GameLogic implementation predates the Pyth Entropy starter +# mint, so entropy() reverts and creating a pet fails. Reads, level up, train, +# rename and transfer all work. The fix is +# `pnpm --prefix contracts/ethereum upgrade:game-logic:sepolia`. +PETCORE_ADDRESS=0x0BB0e03259Cf9DA7B0A3e258e2D17d68D7be9d33 +GAMELOGIC_ADDRESS=0xaDEC55D3b9B2517D37C4bAbbb0dDc9F34de256ee +GAMECONFIG_ADDRESS=0xc8acCDc7D20B85326D586A7Fc861453E6550cCef + +# Optional Hardhat/Anvil RPC override for chain 31337. Unset: Android emulator +# uses 10.0.2.2, iOS simulator uses 127.0.0.1. +# HARDHAT_RPC_URL=http://192.168.1.5:8545 + +# Legacy v1 single-contract address. Superseded by PETCORE_ADDRESS above and +# removed once nothing imports contractConfig.ts (plan Phase 1.3). +CONTRACT_ADDRESS=0x0000000000000000000000000000000000000000 + +# --- Solana --- +# Same program id as frontend `VITE_CRYPTOPETS_PROGRAM_ID` CRYPTOPETS_PROGRAM_ID= # Optional; default public devnet RPC if empty # CRYPTOPETS_SOLANA_RPC=https://api.devnet.solana.com - -API_URL=http://localhost:3001 -CONTRACT_ADDRESS=0x0000000000000000000000000000000000000000 From 0b5d937bf8e91245c37ddd24fc3c3cad3f46ac60 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 14:57:13 -0400 Subject: [PATCH 02/99] feat(mobile): add the v2 chain constants --- mobile/__tests__/ethereumNetworks.test.ts | 67 +++++++++++++++++++++++ mobile/env.d.ts | 5 ++ mobile/jest.config.js | 6 ++ mobile/src/constants/ethereumNetworks.ts | 65 +++++++++++++++++++++- 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 mobile/__tests__/ethereumNetworks.test.ts diff --git a/mobile/__tests__/ethereumNetworks.test.ts b/mobile/__tests__/ethereumNetworks.test.ts new file mode 100644 index 00000000..192e8ef9 --- /dev/null +++ b/mobile/__tests__/ethereumNetworks.test.ts @@ -0,0 +1,67 @@ +/** + * `react-native-dotenv` inlines `@env` at Babel transform time, so `TARGET_CHAIN_ID` + * is a literal baked in from whichever `.env` this machine has and asserting a value + * for it would only test the local file. `resolveTargetChainId` is the parsing it + * wraps, and that is checked directly. + */ + +import { sepolia } from 'wagmi/chains'; + +import { + CHAINS, + EVM_SWITCHER_CHAINS, + TARGET_CHAIN_ID, + getNativeTokenSymbol, + isSupportedChain, + resolveTargetChainId, +} from '../src/constants/ethereumNetworks'; + +describe('resolveTargetChainId', () => { + it('parses a chain id', () => { + expect(resolveTargetChainId('11155111')).toBe(sepolia.id); + expect(resolveTargetChainId('31337')).toBe(31337); + }); + + it('falls back to Sepolia when unset or empty', () => { + expect(resolveTargetChainId(undefined)).toBe(sepolia.id); + expect(resolveTargetChainId('')).toBe(sepolia.id); + }); + + it('falls back rather than returning NaN for a malformed value', () => { + expect(resolveTargetChainId('sepolia')).toBe(sepolia.id); + expect(resolveTargetChainId('1.5')).toBe(sepolia.id); + }); +}); + +describe('TARGET_CHAIN_ID', () => { + it('is a chain the app has contracts on', () => { + expect(isSupportedChain(TARGET_CHAIN_ID)).toBe(true); + }); +}); + +describe('CHAINS', () => { + it('puts the target chain first, because wagmi defaults to chains[0]', () => { + expect(CHAINS[0].chain.id).toBe(sepolia.id); + }); + + it('omits chains with no deployment', () => { + // Mainnet is offered by the switcher but has no contracts, so switching to + // it must read as unsupported rather than as silently failing reads. + expect(EVM_SWITCHER_CHAINS.some((c) => c.chain.id === 1)).toBe(true); + expect(isSupportedChain(1)).toBe(false); + }); + + it('does not treat an unknown chain as supported', () => { + expect(isSupportedChain(84532)).toBe(false); + expect(isSupportedChain(undefined)).toBe(false); + }); +}); + +describe('getNativeTokenSymbol', () => { + it('resolves known chains and defaults to ETH', () => { + expect(getNativeTokenSymbol(sepolia.id)).toBe('ETH'); + expect(getNativeTokenSymbol(31337)).toBe('ETH'); + expect(getNativeTokenSymbol(999999)).toBe('ETH'); + expect(getNativeTokenSymbol(undefined)).toBe('ETH'); + }); +}); diff --git a/mobile/env.d.ts b/mobile/env.d.ts index 52670e69..9d90f018 100644 --- a/mobile/env.d.ts +++ b/mobile/env.d.ts @@ -3,6 +3,11 @@ declare module '@env' { export const API_URL: string; /** Deployed CryptoPets contract (same as frontend VITE_CONTRACT_ADDRESS). */ export const CONTRACT_ADDRESS: string; + /** + * Chain id the contracts are deployed on. Unset falls back to Sepolia; see + * `src/constants/ethereumNetworks.ts`. + */ + export const EVM_CHAIN_ID: string | undefined; /** * Optional Hardhat/Anvil JSON-RPC URL for chain 31337 (e.g. `http://192.168.1.5:8545` on a physical device). * If unset: Android emulator uses `10.0.2.2`; iOS simulator uses `127.0.0.1`. diff --git a/mobile/jest.config.js b/mobile/jest.config.js index 80b7ab06..a1eacd75 100644 --- a/mobile/jest.config.js +++ b/mobile/jest.config.js @@ -5,4 +5,10 @@ module.exports = { // it, jest cannot parse it, and nothing under test reads from it. '^@walletconnect/react-native-compat$': '/__mocks__/walletconnectCompat.js', }, + // wagmi and viem ship ESM only. Metro handles that; jest does not, and the + // react-native preset's default pattern skips everything in node_modules except + // react-native itself, so anything importing `wagmi/chains` dies on `export *`. + transformIgnorePatterns: [ + 'node_modules/(?!(?:@react-native|react-native|wagmi|@wagmi|viem|ox|abitype)/)', + ], }; diff --git a/mobile/src/constants/ethereumNetworks.ts b/mobile/src/constants/ethereumNetworks.ts index 410a1223..a47fec43 100644 --- a/mobile/src/constants/ethereumNetworks.ts +++ b/mobile/src/constants/ethereumNetworks.ts @@ -1,5 +1,6 @@ import type { Chain } from 'viem'; import { mainnet, sepolia } from 'wagmi/chains'; +import { EVM_CHAIN_ID } from '@env'; import { hardhatLocal } from '../ethereumChains'; /** Display metadata aligned with `frontend/src/constants/chains/ethereum.ts`. */ @@ -10,7 +11,69 @@ export type EvmNetworkOption = { isTestnet: boolean; }; -/** Networks exposed in AppKit / wagmi — same three as in `AppKitConfig`. */ +/** + * Parses `EVM_CHAIN_ID` into a chain id, falling back to Sepolia. + * + * Exported for its test: `react-native-dotenv` inlines `@env` at Babel transform + * time, so `TARGET_CHAIN_ID` below is a literal baked in from whatever `.env` the + * machine happens to have. Only this function can be checked deterministically. + * + * A malformed value falls back rather than yielding `NaN`, which would make + * `isSupportedChain` false forever and read as a wallet problem, not a typo. + */ +export function resolveTargetChainId(raw: string | undefined): number { + if (!raw) return sepolia.id; + const parsed = Number(raw); + return Number.isInteger(parsed) ? parsed : sepolia.id; +} + +/** + * The chain this build's contracts are deployed on, mirroring frontend's + * `TARGET_CHAIN_ID`. Sepolia rather than frontend's Base Sepolia: it is the only + * network with a live PetCore and GameLogic. See + * `docs/plan-mobile-frontend-parity.md` Phase 0.1 for why the two diverge. + */ +export const TARGET_CHAIN_ID = resolveTargetChainId(EVM_CHAIN_ID); + +/** + * Every chain the game can actually be played on, target chain first. + * + * Order matters: wagmi treats `chains[0]` as its default, so whatever sits first + * is the chain RPC reads fall back to before a wallet reports a usable one. + * + * Chains without a deployment are deliberately absent, which is why Ethereum + * mainnet appears in `EVM_SWITCHER_CHAINS` below but not here: offering one + * would let a player switch to a network where every contract read silently + * fails. + */ +export const CHAINS: EvmNetworkOption[] = [ + { chain: sepolia, name: 'Sepolia', symbol: 'ETH', isTestnet: true }, + ...(__DEV__ + ? [{ chain: hardhatLocal, name: 'Hardhat Local', symbol: 'ETH', isTestnet: true }] + : []), +]; + +export const CHAIN_SYMBOLS: { [key: number]: string } = { + 31337: 'ETH', // Hardhat Local + 11155111: 'ETH', // Sepolia +}; + +export const getNativeTokenSymbol = (chainId?: number): string => { + if (!chainId) return 'ETH'; + return CHAIN_SYMBOLS[chainId] || 'ETH'; +}; + +/** True when the wallet's current chain is one the app has contracts on. */ +export const isSupportedChain = (chainId: number | undefined): boolean => + chainId !== undefined && CHAINS.some((c) => c.chain.id === chainId); + +/** + * Networks exposed in AppKit / wagmi — same three as in `AppKitConfig`. + * + * Wider than `CHAINS` on purpose: this is what the switcher lists, and it still + * offers mainnet, where nothing is deployed. Narrowing it belongs with the rest + * of the network-switcher work in plan Phase 5, not here. + */ export const EVM_SWITCHER_CHAINS: EvmNetworkOption[] = [ { chain: hardhatLocal, name: 'Hardhat Local', symbol: 'ETH', isTestnet: true }, { chain: mainnet, name: 'Ethereum', symbol: 'ETH', isTestnet: false }, From 99151bba093e1e4c6abae927a2be612276dac150 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 15:07:48 -0400 Subject: [PATCH 03/99] feat(mobile): add the v2 ABIs and contract surface --- mobile/__tests__/contracts.test.ts | 51 + mobile/env.d.ts | 7 + mobile/env.example | 22 +- mobile/src/chains/ethereum/contracts.ts | 58 + mobile/src/chains/ethereum/gameConfigAbi.json | 977 +++++++++++ mobile/src/chains/ethereum/gameLogicAbi.json | 647 +++++++ mobile/src/chains/ethereum/petCoreAbi.json | 1504 +++++++++++++++++ 7 files changed, 3256 insertions(+), 10 deletions(-) create mode 100644 mobile/__tests__/contracts.test.ts create mode 100644 mobile/src/chains/ethereum/contracts.ts create mode 100644 mobile/src/chains/ethereum/gameConfigAbi.json create mode 100644 mobile/src/chains/ethereum/gameLogicAbi.json create mode 100644 mobile/src/chains/ethereum/petCoreAbi.json diff --git a/mobile/__tests__/contracts.test.ts b/mobile/__tests__/contracts.test.ts new file mode 100644 index 00000000..564a2acc --- /dev/null +++ b/mobile/__tests__/contracts.test.ts @@ -0,0 +1,51 @@ +/** + * Guards the ABI copy. The JSONs are copied verbatim from `frontend/src/chains/ethereum/` + * rather than regenerated, so nothing mechanical keeps them in step with that source; a + * truncated or stale copy would break every read at runtime with a decode error rather + * than at build time. + * + * Addresses are asserted by shape, not value: `react-native-dotenv` inlines `@env` at + * Babel transform time, so the values here come from whichever `.env` this machine has. + */ + +import type { AbiFunction } from 'viem'; + +import { evmContracts } from '../src/chains/ethereum/contracts'; + +const fnNames = (abi: readonly unknown[]): string[] => + (abi as AbiFunction[]).filter((e) => e.type === 'function').map((e) => e.name); + +describe('evmContracts', () => { + it('exposes the three v2 units', () => { + expect(Object.keys(evmContracts)).toEqual(['petCore', 'gameLogic', 'gameConfig']); + }); + + it.each(['petCore', 'gameLogic', 'gameConfig'] as const)('%s has an address and an abi', (key) => { + const contract = evmContracts[key]; + expect(contract.address).toMatch(/^0x[0-9a-fA-F]{40}$/); + expect(contract.abi.length).toBeGreaterThan(0); + }); + + it('carries the PetCore surface the pet hooks read', () => { + expect(fnNames(evmContracts.petCore.abi)).toEqual( + expect.arrayContaining(['getByOwner', 'getPet', 'totalPets', 'levelUp', 'changeName']), + ); + }); + + it('carries the entropy-era GameLogic surface', () => { + // The older Sepolia stack's GameLogic predates this and reverts on entropy(). + // If these ever go missing, the ABI has been copied from a pre-entropy build. + expect(fnNames(evmContracts.gameLogic.abi)).toEqual( + expect.arrayContaining(['entropy', 'requestMintStarter', 'settleMint', 'requestCreateFromDNA']), + ); + }); + + it('has no battleFee, because battles left the chain', () => { + // §L Phase 6 retired GameConfig.battleFee with the on-chain battle path. + // Its return would mean the ABI came from a pre-retirement build. + expect(fnNames(evmContracts.gameConfig.abi)).not.toContain('battleFee'); + expect(fnNames(evmContracts.gameConfig.abi)).toEqual( + expect.arrayContaining(['breedFee', 'levelUpFee', 'trainFee', 'baseMintFee']), + ); + }); +}); diff --git a/mobile/env.d.ts b/mobile/env.d.ts index 9d90f018..7b3b5bf4 100644 --- a/mobile/env.d.ts +++ b/mobile/env.d.ts @@ -8,6 +8,13 @@ declare module '@env' { * `src/constants/ethereumNetworks.ts`. */ export const EVM_CHAIN_ID: string | undefined; + /** + * v2 contract addresses. Each falls back to the live Sepolia deployment in + * `src/chains/ethereum/contracts.ts`, the same one frontend defaults to. + */ + export const PETCORE_ADDRESS: string | undefined; + export const GAMELOGIC_ADDRESS: string | undefined; + export const GAMECONFIG_ADDRESS: string | undefined; /** * Optional Hardhat/Anvil JSON-RPC URL for chain 31337 (e.g. `http://192.168.1.5:8545` on a physical device). * If unset: Android emulator uses `10.0.2.2`; iOS simulator uses `127.0.0.1`. diff --git a/mobile/env.example b/mobile/env.example index e950e136..a7e1b00f 100644 --- a/mobile/env.example +++ b/mobile/env.example @@ -24,16 +24,18 @@ API_URL=http://localhost:3001 # Base Sepolia in its CHAINS. EVM_CHAIN_ID=11155111 -# Sepolia (11155111) v2 deployment. Verified on-chain 2026-08-05: PetCore and -# GameLogic are both live proxies, and GameLogic.petCore()/gameConfig() point -# back at the two addresses below. -# Known gap: this GameLogic implementation predates the Pyth Entropy starter -# mint, so entropy() reverts and creating a pet fails. Reads, level up, train, -# rename and transfer all work. The fix is -# `pnpm --prefix contracts/ethereum upgrade:game-logic:sepolia`. -PETCORE_ADDRESS=0x0BB0e03259Cf9DA7B0A3e258e2D17d68D7be9d33 -GAMELOGIC_ADDRESS=0xaDEC55D3b9B2517D37C4bAbbb0dDc9F34de256ee -GAMECONFIG_ADDRESS=0xc8acCDc7D20B85326D586A7Fc861453E6550cCef +# Sepolia (11155111) v2 deployment, the same one frontend's contracts.ts falls +# back to. Verified on-chain 2026-08-05: all three live, PetCore answers +# name()="CryptoPets", GameLogic.petCore()/gameConfig() point back at the other +# two, and GameLogic.entropy() resolves to Pyth Entropy V2, so starter minting +# works. totalPets() is 0, so mint one rather than expecting a populated roster. +# +# There is an older Sepolia stack at 0x0BB0e0…9d33 / 0xaDEC55…56ee holding 5 +# pets, but its GameLogic predates the entropy wiring and minting reverts there. +# Leaving these unset is fine: contracts.ts defaults to exactly these values. +PETCORE_ADDRESS=0xD94B02fC6238AcE5c0Fd767bFf8f5A1FCD9B59DB +GAMELOGIC_ADDRESS=0x87E3E1e3EB22eC45fB99715BdF91911697997Be4 +GAMECONFIG_ADDRESS=0xE16e0e982D390C4F826D00Fc0E771846a002F10B # Optional Hardhat/Anvil RPC override for chain 31337. Unset: Android emulator # uses 10.0.2.2, iOS simulator uses 127.0.0.1. diff --git a/mobile/src/chains/ethereum/contracts.ts b/mobile/src/chains/ethereum/contracts.ts new file mode 100644 index 00000000..5c11e6c0 --- /dev/null +++ b/mobile/src/chains/ethereum/contracts.ts @@ -0,0 +1,58 @@ +import type { Abi } from 'viem'; +import { PETCORE_ADDRESS, GAMELOGIC_ADDRESS, GAMECONFIG_ADDRESS } from '@env'; + +import petCoreAbi from './petCoreAbi.json'; +import gameLogicAbi from './gameLogicAbi.json'; +import gameConfigAbi from './gameConfigAbi.json'; + +/** + * v2 EVM contract surface, mirroring `frontend/src/chains/ethereum/contracts.ts`. + * The monolithic v1 contract is split into three units: + * - PetCore (proxy) — ERC-721 storage, mint, rename, level/XP, cooldowns, marriage. + * - GameLogic (proxy) — async breed/mint (request → settle) + entropy wiring. + * - GameConfig — tunable fees / cooldowns / XP-curve / skill params (read for UI). + * + * CombatSim is deliberately absent: battles are resolved by the backend and replayed + * from the signed receipt (§L Phase 6), so no client ever calls the on-chain sim. + * + * The ABI JSONs are copied verbatim from frontend rather than regenerated, so the + * two apps decode identical call data. + * + * Addresses come from env and fall back to the same Sepolia (11155111) deployment + * frontend defaults to. Verified on-chain 2026-08-05: all three are live, PetCore + * answers name()="CryptoPets", GameLogic.petCore()/gameConfig() point back at the + * other two, and GameLogic.entropy() resolves to Pyth Entropy V2. + * + * Not to be confused with the older Sepolia stack at 0x0BB0e0…9d33 / 0xaDEC55…56ee, + * which holds 5 pets but whose GameLogic predates the entropy wiring, so minting a + * starter reverts there. See `docs/plan-mobile-frontend-parity.md` Phase 0.1. + */ +const SEPOLIA_PETCORE = '0xD94B02fC6238AcE5c0Fd767bFf8f5A1FCD9B59DB'; +const SEPOLIA_GAMELOGIC = '0x87E3E1e3EB22eC45fB99715BdF91911697997Be4'; +const SEPOLIA_GAMECONFIG = '0xE16e0e982D390C4F826D00Fc0E771846a002F10B'; + +interface EvmContract { + address: `0x${string}`; + abi: Abi; +} + +const petCoreContract: EvmContract = { + address: (PETCORE_ADDRESS || SEPOLIA_PETCORE) as `0x${string}`, + abi: petCoreAbi.abi as Abi, +}; + +const gameLogicContract: EvmContract = { + address: (GAMELOGIC_ADDRESS || SEPOLIA_GAMELOGIC) as `0x${string}`, + abi: gameLogicAbi.abi as Abi, +}; + +const gameConfigContract: EvmContract = { + address: (GAMECONFIG_ADDRESS || SEPOLIA_GAMECONFIG) as `0x${string}`, + abi: gameConfigAbi.abi as Abi, +}; + +export const evmContracts = { + petCore: petCoreContract, + gameLogic: gameLogicContract, + gameConfig: gameConfigContract, +} as const; diff --git a/mobile/src/chains/ethereum/gameConfigAbi.json b/mobile/src/chains/ethereum/gameConfigAbi.json new file mode 100644 index 00000000..34cc74de --- /dev/null +++ b/mobile/src/chains/ethereum/gameConfigAbi.json @@ -0,0 +1,977 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "BaseMintFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "BloodlustBpsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "BreedCooldownBaseUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "BreedFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "CunningCritCapUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "FuryDmgMultUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "FuryHpThresholdUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "cap", + "type": "uint8" + } + ], + "name": "GenerationCapUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "LevelUpFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "MarriageCooldownUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "level", + "type": "uint32" + } + ], + "name": "MaxLevelUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "NewbornCooldownUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "tier", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "size", + "type": "uint8" + } + ], + "name": "PoolSizeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "ttl", + "type": "uint256" + } + ], + "name": "ProposalTTLUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "SageMdefMultUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "ShellDefMultUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "StudFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "SwiftCritBonusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "TankHpMultUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "TrainCooldownUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "TrainFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint32", + "name": "xp", + "type": "uint32" + } + ], + "name": "TrainXpUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "baseMintFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bloodlustBps", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "breedCooldownBase", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "breedFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "cunningCritCap", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "furyDmgMult", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "furyHpThreshold", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "generationCap", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "levelUpFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "marriageCooldown", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxLevel", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxNameLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "newbornCooldown", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "name": "poolSizes", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proposalTTL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sageMdefMult", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "setBaseMintFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setBloodlustBps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "setBreedCooldownBase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "setBreedFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setCunningCritCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setFuryDmgMult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setFuryHpThreshold", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "cap", + "type": "uint8" + } + ], + "name": "setGenerationCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "setLevelUpFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "setMarriageCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "level", + "type": "uint32" + } + ], + "name": "setMaxLevel", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "setNewbornCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "tier", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "size", + "type": "uint8" + } + ], + "name": "setPoolSize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "ttl", + "type": "uint256" + } + ], + "name": "setProposalTTL", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setSageMdefMult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setShellDefMult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "setStudFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setSwiftCritBonus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint16", + "name": "value", + "type": "uint16" + } + ], + "name": "setTankHpMult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cooldown", + "type": "uint256" + } + ], + "name": "setTrainCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "fee", + "type": "uint256" + } + ], + "name": "setTrainFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "xp", + "type": "uint32" + } + ], + "name": "setTrainXp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "shellDefMult", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "studFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "swiftCritBonus", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tankHpMult", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trainCooldown", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trainFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "trainXp", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/mobile/src/chains/ethereum/gameLogicAbi.json b/mobile/src/chains/ethereum/gameLogicAbi.json new file mode 100644 index 00000000..a3db0342 --- /dev/null +++ b/mobile/src/chains/ethereum/gameLogicAbi.json @@ -0,0 +1,647 @@ +{ + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "petId1", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "petId2", + "type": "uint256" + } + ], + "name": "BreedRandomnessRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "childId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "studFeePaidTo", + "type": "address" + } + ], + "name": "BreedSettled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "config", + "type": "address" + } + ], + "name": "GameConfigUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "MintRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "MintSettled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "xpGained", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newXp", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newLevel", + "type": "uint32" + } + ], + "name": "Trained", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "sequence", + "type": "uint64" + }, + { + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "randomNumber", + "type": "bytes32" + } + ], + "name": "_entropyCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "cancelBreed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "cancelMint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "entropy", + "outputs": [ + { + "internalType": "contract IEntropyV2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gameConfig", + "outputs": [ + { + "internalType": "contract GameConfig", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "entropy_", + "type": "address" + }, + { + "internalType": "address", + "name": "petCore_", + "type": "address" + }, + { + "internalType": "address", + "name": "gameConfig_", + "type": "address" + }, + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "pendingStudFees", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "petBreedRequestId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "petCore", + "outputs": [ + { + "internalType": "contract PetCore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "petId2", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name_", + "type": "string" + } + ], + "name": "requestCreateFromDNA", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + } + ], + "name": "requestMintStarter", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "gameConfig_", + "type": "address" + } + ], + "name": "setGameConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "settleBreed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "settleMint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "train", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawStudFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/mobile/src/chains/ethereum/petCoreAbi.json b/mobile/src/chains/ethereum/petCoreAbi.json new file mode 100644 index 00000000..dc98a51c --- /dev/null +++ b/mobile/src/chains/ethereum/petCoreAbi.json @@ -0,0 +1,1504 @@ +{ + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "CallerRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "config", + "type": "address" + } + ], + "name": "GameConfigUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + } + ], + "name": "MarriageAccepted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "MarriageDissolved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + } + ], + "name": "MarriageProposed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "dna", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "rarity", + "type": "uint8" + } + ], + "name": "NewPet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "newLevel", + "type": "uint32" + } + ], + "name": "PetLevelUp", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "newName", + "type": "string" + } + ], + "name": "PetNameChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + } + ], + "name": "PetTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "DNA_DIGITS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DNA_MODULUS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME_CHANGE_LEVEL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + } + ], + "name": "acceptMarriage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "amount", + "type": "uint32" + } + ], + "name": "addXp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "authorizeCaller", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "authorizedCallers", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + } + ], + "name": "cancelProposal", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "newName_", + "type": "string" + } + ], + "name": "changeName", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + } + ], + "name": "clearStaleMarriage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "uint256", + "name": "dna", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "rarity", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "generation", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "parent1Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "parent2Id", + "type": "uint256" + } + ], + "name": "createPet", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "divorce", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "gameConfig", + "outputs": [ + { + "internalType": "contract GameConfig", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "getBreedInfo", + "outputs": [ + { + "internalType": "uint8", + "name": "generation", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "breedCount", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "parent1Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "parent2Id", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner_", + "type": "address" + } + ], + "name": "getByOwner", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "getPet", + "outputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "uint256", + "name": "dna", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "level", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "readyTime", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarity", + "type": "uint8" + }, + { + "internalType": "uint32", + "name": "xp", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "generation", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "breedCount", + "type": "uint8" + }, + { + "internalType": "uint32", + "name": "breedReadyAt", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "trainReadyAt", + "type": "uint32" + }, + { + "internalType": "uint16", + "name": "speciesId", + "type": "uint16" + }, + { + "internalType": "uint256", + "name": "parent1Id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "parent2Id", + "type": "uint256" + } + ], + "internalType": "struct PetCore.Pet", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "getPetStats", + "outputs": [ + { + "internalType": "uint32", + "name": "level", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "rarity", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "incrementBreedCount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "incrementWalletMintCount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "gameConfig_", + "type": "address" + }, + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "isBreedReady", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + } + ], + "name": "isMarriageValid", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "isReady", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "isTrainReady", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "levelUp", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "marriageCooldownUntil", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "marriageOf", + "outputs": [ + { + "internalType": "uint256", + "name": "spouseId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "ownerSnapshot", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "marriageProposal", + "outputs": [ + { + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + }, + { + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "mintTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petIdA", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "petIdB", + "type": "uint256" + } + ], + "name": "proposeMarriage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "revokeCaller", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cooldownSeconds", + "type": "uint256" + } + ], + "name": "setCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "gameConfig_", + "type": "address" + } + ], + "name": "setGameConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalPets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cooldownSeconds", + "type": "uint256" + } + ], + "name": "triggerBreedCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "petId", + "type": "uint256" + } + ], + "name": "triggerTrainCooldown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "walletMintCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} From ed5229ec85aca4c6ef0d84b87c014ccebcd11a65 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 15:15:15 -0400 Subject: [PATCH 04/99] refactor(mobile): swap petsContractParams to PetsEvmConfig --- mobile/src/contractConfig.ts | 16 - mobile/src/contracts/ethereumAbi.json | 1091 ------------------------- mobile/src/petsContractParams.ts | 28 +- 3 files changed, 19 insertions(+), 1116 deletions(-) delete mode 100644 mobile/src/contractConfig.ts delete mode 100644 mobile/src/contracts/ethereumAbi.json diff --git a/mobile/src/contractConfig.ts b/mobile/src/contractConfig.ts deleted file mode 100644 index 5b50fdf4..00000000 --- a/mobile/src/contractConfig.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { CONTRACT_ADDRESS as ENV_CONTRACT_ADDRESS } from '@env'; - -function parseAddress(raw: string | undefined): `0x${string}` | undefined { - if (!raw || typeof raw !== 'string') { - return undefined; - } - const t = raw.trim(); - if (!/^0x[a-fA-F0-9]{40}$/.test(t)) { - return undefined; - } - return t as `0x${string}`; -} - -export const CONTRACT_ADDRESS = parseAddress(ENV_CONTRACT_ADDRESS); - -export const isContractConfigured = CONTRACT_ADDRESS !== undefined; diff --git a/mobile/src/contracts/ethereumAbi.json b/mobile/src/contracts/ethereumAbi.json deleted file mode 100644 index e39dc9f7..00000000 --- a/mobile/src/contracts/ethereumAbi.json +++ /dev/null @@ -1,1091 +0,0 @@ -{ - "abi": [ - { - "inputs": [ - { - "internalType": "uint256", - "name": "vrfSubscriptionId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "vrfKeyHash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "vrfCoordinator", - "type": "address" - }, - { - "internalType": "bool", - "name": "vrfNativePayment", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ERC721IncorrectOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ERC721InsufficientApproval", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC721InvalidApprover", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "ERC721InvalidOperator", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ERC721InvalidOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC721InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC721InvalidSender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ERC721NonexistentToken", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "have", - "type": "address" - }, - { - "internalType": "address", - "name": "want", - "type": "address" - } - ], - "name": "OnlyCoordinatorCanFulfill", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "have", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "coordinator", - "type": "address" - } - ], - "name": "OnlyOwnerOrCoordinator", - "type": "error" - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "childId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - } - ], - "name": "BreedFulfilled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "petId1", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "petId2", - "type": "uint256" - } - ], - "name": "BreedRandomnessRequested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "vrfCoordinator", - "type": "address" - } - ], - "name": "CoordinatorSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "OwnershipTransferRequested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "PetTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [], - "name": "LEVEL_UP_FEE", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "MAX_NAME_LENGTH", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "NAME_CHANGE_LEVEL", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_petId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_targetId", - "type": "uint256" - } - ], - "name": "attack", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_id1", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_id2", - "type": "uint256" - } - ], - "name": "battle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "battleLogic", - "outputs": [ - { - "internalType": "contract Battle", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "breeding", - "outputs": [ - { - "internalType": "contract Breeding", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "string", - "name": "_newName", - "type": "string" - } - ], - "name": "changeName", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "_name", - "type": "string" - } - ], - "name": "createRandom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "getBattleStats", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "", - "type": "uint16" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "getById", - "outputs": [ - { - "components": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "uint256", - "name": "dna", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "level", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "readyTime", - "type": "uint32" - }, - { - "internalType": "uint16", - "name": "winCount", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "lossCount", - "type": "uint16" - }, - { - "internalType": "uint8", - "name": "rarity", - "type": "uint8" - } - ], - "internalType": "struct Inventory.Pet", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "getByOwner", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "getStats", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - }, - { - "internalType": "uint16", - "name": "", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "", - "type": "uint16" - }, - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getTotalCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "inventory", - "outputs": [ - { - "internalType": "contract Inventory", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "levelUp", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "petBreedRequestId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } - ], - "name": "rawFulfillRandomWords", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_petId1", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_petId2", - "type": "uint256" - }, - { - "internalType": "string", - "name": "_name", - "type": "string" - } - ], - "name": "requestCreateFromDNA", - "outputs": [ - { - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "s_vrfCoordinator", - "outputs": [ - { - "internalType": "contract IVRFCoordinatorV2Plus", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_vrfCoordinator", - "type": "address" - } - ], - "name": "setCoordinator", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "utils", - "outputs": [ - { - "internalType": "contract Utils", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] -} \ No newline at end of file diff --git a/mobile/src/petsContractParams.ts b/mobile/src/petsContractParams.ts index 187d0cc3..12dce343 100644 --- a/mobile/src/petsContractParams.ts +++ b/mobile/src/petsContractParams.ts @@ -1,10 +1,20 @@ -import type { Abi } from 'viem'; -import { CONTRACT_ADDRESS, isContractConfigured } from './contractConfig'; -import ethereumAbi from './contracts/ethereumAbi.json'; +import type { PetsEvmConfig } from '@shared/core'; -/** Arguments for `usePetsContract` from `@shared/core`. */ -export const petsContractParams = { - contractAddress: CONTRACT_ADDRESS, - abi: ethereumAbi.abi as Abi, - enabled: isContractConfigured, -} as const; +import { evmContracts } from './chains/ethereum/contracts'; +import { TARGET_CHAIN_ID } from './constants/ethereumNetworks'; + +/** + * v2 EVM contract config for `PetsConfigProvider` from `@shared/core`, mirroring + * `frontend/src/petsContractParams.ts`. + * + * `chainId` is always set here, where frontend leaves it `undefined` when its env + * var is absent. `TARGET_CHAIN_ID` already resolves its own fallback, so read + * hooks get an explicit chain to target regardless of which one the wallet is on. + */ +export const petsContractParams: PetsEvmConfig = { + petCore: evmContracts.petCore, + gameLogic: evmContracts.gameLogic, + gameConfig: evmContracts.gameConfig, + enabled: true, + chainId: TARGET_CHAIN_ID, +}; From 7f23ab5d214970d3b2f0be45ab595c73ad72de62 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 15:40:58 -0400 Subject: [PATCH 05/99] feat(mobile): read pets through the v2 adapter layer --- mobile/App.tsx | 7 +- mobile/__tests__/App.test.tsx | 1 + mobile/src/AppContent.tsx | 83 ++++++++++++------------ mobile/src/components/CreatePetModal.tsx | 57 +++++++--------- mobile/src/components/PetList.tsx | 46 +++---------- 5 files changed, 77 insertions(+), 117 deletions(-) diff --git a/mobile/App.tsx b/mobile/App.tsx index bb96ae24..e196c57d 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -3,11 +3,12 @@ import "@walletconnect/react-native-compat"; import { AppKitProvider } from '@reown/appkit-react-native'; import { WagmiProvider } from 'wagmi'; import { QueryClientProvider } from '@tanstack/react-query'; -import { queryClient, ApiClientProvider, AuthProvider } from '@shared/core'; +import { queryClient, ApiClientProvider, AuthProvider, PetsConfigProvider } from '@shared/core'; import { appKit, wagmiConfig } from './src/AppKitConfig'; import AppRoot from './src/AppContent.tsx'; import { API_URL } from './config'; +import { petsContractParams } from './src/petsContractParams'; import { SolanaAppKitAnchorBridge } from './src/solana/SolanaAppKitAnchorBridge'; export default function App() { @@ -18,7 +19,9 @@ export default function App() { - + + + diff --git a/mobile/__tests__/App.test.tsx b/mobile/__tests__/App.test.tsx index 2bcd04de..f8d91124 100644 --- a/mobile/__tests__/App.test.tsx +++ b/mobile/__tests__/App.test.tsx @@ -20,6 +20,7 @@ jest.mock('@shared/core', () => ({ queryClient: {}, ApiClientProvider: passthrough, AuthProvider: passthrough, + PetsConfigProvider: passthrough, })); jest.mock('../src/AppKitConfig', () => ({appKit: {}, wagmiConfig: {}})); jest.mock('../src/solana/SolanaAppKitAnchorBridge', () => ({ diff --git a/mobile/src/AppContent.tsx b/mobile/src/AppContent.tsx index c438d288..9308ca88 100644 --- a/mobile/src/AppContent.tsx +++ b/mobile/src/AppContent.tsx @@ -10,13 +10,12 @@ import { } from 'react-native'; import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'; import { AppKit } from '@reown/appkit-react-native'; -import { useAuth, usePetsContract } from '@shared/core'; +import { useAuth, useCreatePet, usePetList } from '@shared/core'; import { useAccount } from 'wagmi'; import ConnectButton from './components/ConnectButton'; import EthereumNetworkSwitcher from './components/EthereumNetworkSwitcher'; import CreatePetModal from './components/CreatePetModal'; import PetList from './components/PetList'; -import { petsContractParams } from './petsContractParams'; import { neon, neonGlow } from './theme/neon'; function AppRoot() { @@ -31,24 +30,33 @@ function AppRoot() { function AppContent() { const { isAuthenticated } = useAuth(); const { isConnected } = useAccount(); - const pets = usePetsContract(petsContractParams); + const pets = usePetList(); const [refreshing, setRefreshing] = useState(false); const [createModalVisible, setCreateModalVisible] = useState(false); const insets = useSafeAreaInsets(); + const closeCreateModal = useCallback(() => { + setCreateModalVisible(false); + }, []); + + // EVM minting is two-phase (requestMintStarter, then settleMint once Pyth + // Entropy reveals), so the list is only worth re-reading once onSuccess fires. + const createPet = useCreatePet({ + onSuccess: () => { + closeCreateModal(); + pets.refetch(); + }, + }); + const handleRefreshPets = useCallback(async () => { setRefreshing(true); try { - await pets.refetchPetIds(); + await pets.refetch(); } finally { setRefreshing(false); } }, [pets]); - const closeCreateModal = useCallback(() => { - setCreateModalVisible(false); - }, []); - return ( {/* Header */} @@ -69,49 +77,38 @@ function AppContent() { isConnected ? ( Welcome back! - {pets.isContractConfigured ? ( - - setCreateModalVisible(true)} - activeOpacity={0.85} - > - Create - - - {refreshing ? ( - - ) : ( - Refresh - )} - - - ) : null} + + setCreateModalVisible(true)} + activeOpacity={0.85} + > + Create + + + {refreshing ? ( + + ) : ( + Refresh + )} + + ) : ( diff --git a/mobile/src/components/CreatePetModal.tsx b/mobile/src/components/CreatePetModal.tsx index cc17bf43..d894ca9b 100644 --- a/mobile/src/components/CreatePetModal.tsx +++ b/mobile/src/components/CreatePetModal.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { ActivityIndicator, KeyboardAvoidingView, @@ -12,57 +12,40 @@ import { useWindowDimensions, View, } from 'react-native'; +import type { CreatePetArgs, PetMutationResult } from '@shared/core'; import { neon, neonGlow } from '../theme/neon'; type Props = { visible: boolean; onClose: () => void; - isContractConfigured: boolean; - createRandomPet: (name: string) => void; - isWritePending: boolean; - writeError: Error | null | undefined; - isConfirming: boolean; - txHash: `0x${string}` | undefined; + createPet: PetMutationResult; }; -export default function CreatePetModal({ - visible, - onClose, - isContractConfigured, - createRandomPet, - isWritePending, - writeError, - isConfirming, - txHash, -}: Props) { +export default function CreatePetModal({ visible, onClose, createPet }: Props) { + const { mutate, isPending, error, hash, isAwaitingFulfillment, isSettling, reset } = createPet; const [name, setName] = useState(''); - const prevTxHash = useRef(undefined); const { width } = useWindowDimensions(); const cardWidth = Math.min(400, width - 48); useEffect(() => { if (visible) { setName(''); + reset(); } - }, [visible]); + }, [visible, reset]); - useEffect(() => { - if (prevTxHash.current && !txHash) { - setName(''); - onClose(); - } - prevTxHash.current = txHash; - }, [txHash, onClose]); - - const busy = isWritePending || isConfirming; - const canSubmit = isContractConfigured && name.trim().length > 0 && !busy; + // EVM minting spans three waits: the request tx, Pyth Entropy revealing, then + // the settle tx. All of them mean "keep the sheet locked and spinning". + const busy = isPending || isAwaitingFulfillment === true || isSettling === true; + const canSubmit = name.trim().length > 0 && !busy; const handleSubmit = () => { const trimmed = name.trim(); if (!trimmed) { return; } - createRandomPet(trimmed); + // `mutate` captures its own errors into `error`, so it never rejects. + mutate({ name: trimmed }); }; return ( @@ -121,21 +104,25 @@ export default function CreatePetModal({ - {isWritePending ? 'Confirm in wallet…' : 'Confirming…'} + {isPending + ? 'Confirm in wallet…' + : isAwaitingFulfillment + ? 'Rolling traits…' + : 'Minting…'} ) : ( Create pet )} - {writeError ? ( + {error ? ( - {writeError instanceof Error ? writeError.message : String(writeError)} + {error instanceof Error ? error.message : String(error)} ) : null} - {txHash && !writeError ? ( + {hash && !error ? ( - {isConfirming ? 'Transaction submitted…' : 'Done — refreshing list…'} + {busy ? 'Transaction submitted…' : 'Done — refreshing list…'} ) : null} diff --git a/mobile/src/components/PetList.tsx b/mobile/src/components/PetList.tsx index 4c5c79a0..ebb410b9 100644 --- a/mobile/src/components/PetList.tsx +++ b/mobile/src/components/PetList.tsx @@ -7,53 +7,26 @@ import { Text, View, } from 'react-native'; -import type { Pet } from '@shared/core'; +import { getRarityColor, getRarityName, type Pet } from '@shared/core'; import { neon, neonGlow } from '../theme/neon'; type Props = { pets: Pet[]; - petIds: bigint[]; isLoading: boolean; - contractError: Error | null | undefined; - isContractConfigured: boolean; + error: Error | null; onRefresh: () => void; refreshing: boolean; - getRarityName: (rarity: number) => string; - getRarityColor: (rarity: number) => string; }; -export default function PetList({ - pets, - petIds, - isLoading, - contractError, - isContractConfigured, - onRefresh, - refreshing, - getRarityName, - getRarityColor, -}: Props) { - if (!isContractConfigured) { - return ( - - Contract not configured - - Set CONTRACT_ADDRESS in your mobile `.env` to match the deployed CryptoPets address (same as - frontend `VITE_CONTRACT_ADDRESS`), then restart Metro. - - - ); - } - - if (contractError) { - const message = - contractError instanceof Error ? contractError.message : String(contractError); +export default function PetList({ pets, isLoading, error, onRefresh, refreshing }: Props) { + if (error) { + const message = error instanceof Error ? error.message : String(error); return ( Could not load pets {message} - Check that your wallet network matches the contract (e.g. Hardhat Local for local deploy). + Check that your wallet is on the network the contracts are deployed to. ); @@ -102,11 +75,10 @@ export default function PetList({ } > Your pets - {pets.map((pet, index) => { - const id = petIds[index]; + {pets.map((pet) => { const rarityColor = getRarityColor(pet.rarity); return ( - + {pet.name} @@ -115,7 +87,7 @@ export default function PetList({ - {id !== undefined && ID #{id.toString()}} + ID #{pet.id} Level {pet.level} W {pet.winCount} · L {pet.lossCount} From 86a2f65e425c6a07117f1c455cf82471da783483 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 15:54:41 -0400 Subject: [PATCH 06/99] feat(mobile): add a toast provider and the error hooks bound to it --- mobile/App.tsx | 5 +- mobile/__tests__/toast.test.tsx | 194 +++++++++++++++++++++++++++ mobile/src/components/ui/toast.tsx | 149 ++++++++++++++++++++ mobile/src/hooks/useNotifyError.ts | 20 +++ mobile/src/hooks/usePetErrorToast.ts | 58 ++++++++ mobile/src/hooks/useTxErrorToast.ts | 33 +++++ 6 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 mobile/__tests__/toast.test.tsx create mode 100644 mobile/src/components/ui/toast.tsx create mode 100644 mobile/src/hooks/useNotifyError.ts create mode 100644 mobile/src/hooks/usePetErrorToast.ts create mode 100644 mobile/src/hooks/useTxErrorToast.ts diff --git a/mobile/App.tsx b/mobile/App.tsx index e196c57d..273cb7bb 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -9,6 +9,7 @@ import { appKit, wagmiConfig } from './src/AppKitConfig'; import AppRoot from './src/AppContent.tsx'; import { API_URL } from './config'; import { petsContractParams } from './src/petsContractParams'; +import { ToastProvider } from './src/components/ui/toast'; import { SolanaAppKitAnchorBridge } from './src/solana/SolanaAppKitAnchorBridge'; export default function App() { @@ -20,7 +21,9 @@ export default function App() { - + + + diff --git a/mobile/__tests__/toast.test.tsx b/mobile/__tests__/toast.test.tsx new file mode 100644 index 00000000..9e90ef98 --- /dev/null +++ b/mobile/__tests__/toast.test.tsx @@ -0,0 +1,194 @@ +/** + * Covers the toast provider and the three app-local hooks bound to it. The point of + * the RN provider is that `useNotifyError` / `usePetErrorToast` / `useTxErrorToast` + * port over from frontend unchanged, so these assert the wiring rather than the + * error parsing: `usePetError` and `useTxError` live in `@shared/core` and are + * mocked here, since reaching the real ones means booting the chain adapter. + */ + +import React from 'react'; +import { Text } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; + +const mockUsePetError = jest.fn(); +const mockUseTxError = jest.fn(); +jest.mock('@shared/core', () => ({ + usePetError: (...args: unknown[]) => mockUsePetError(...args), + useTxError: (...args: unknown[]) => mockUseTxError(...args), +})); + +import { ToastProvider, useToast } from '../src/components/ui/toast'; +import { useNotifyError } from '../src/hooks/useNotifyError'; +import { usePetErrorToast } from '../src/hooks/usePetErrorToast'; +import { useTxErrorToast } from '../src/hooks/useTxErrorToast'; + +/** Every string rendered in the tree, so assertions do not depend on layout. */ +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => { + const walk = (node: unknown): string => { + if (typeof node === 'string') return node; + if (Array.isArray(node)) return node.map(walk).join(' '); + if (node && typeof node === 'object' && 'children' in node) { + return walk((node as { children: unknown }).children); + } + return ''; + }; + return walk(tree.toJSON()); +}; + +const renderInProvider = async (Component: React.FC) => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create( + + + , + ); + }); + return tree; +}; + +beforeEach(() => { + // Fake timers throughout: the 5200ms auto-dismiss otherwise outlives the test + // that started it and fires a setState into a later one, which surfaces as an + // act() warning and a failure in whichever test happens to be running. + jest.useFakeTimers(); + jest.spyOn(console, 'error').mockImplementation(() => {}); + mockUsePetError.mockReset(); + mockUseTxError.mockReset(); +}); + +afterEach(() => { + jest.useRealTimers(); + jest.restoreAllMocks(); +}); + +describe('ToastProvider', () => { + it('throws when useToast is called outside it', () => { + const Orphan = () => { + useToast(); + return null; + }; + expect(() => + ReactTestRenderer.act(() => { + ReactTestRenderer.create(); + }), + ).toThrow('useToast must be used within ToastProvider'); + }); + + it('renders a toast for each tone', async () => { + const Fixture = () => { + const toast = useToast(); + return ( + { + toast.error('went wrong'); + toast.info('heads up'); + toast.success('all good'); + }} + > + go + + ); + }; + const tree = await renderInProvider(Fixture); + expect(textOf(tree)).not.toContain('went wrong'); + + await ReactTestRenderer.act(() => { + tree.root.findByType(Text).props.onPress(); + }); + + const rendered = textOf(tree); + expect(rendered).toContain('went wrong'); + expect(rendered).toContain('heads up'); + expect(rendered).toContain('all good'); + }); + + it('auto-dismisses', async () => { + const Fixture = () => { + const toast = useToast(); + return toast.error('temporary')}>go; + }; + const tree = await renderInProvider(Fixture); + await ReactTestRenderer.act(() => { + tree.root.findByType(Text).props.onPress(); + }); + expect(textOf(tree)).toContain('temporary'); + + await ReactTestRenderer.act(() => { + jest.advanceTimersByTime(5200); + }); + expect(textOf(tree)).not.toContain('temporary'); + }); +}); + +describe('useNotifyError', () => { + it('shows the message and logs the raw error', async () => { + const raw = new Error('revert 0x123'); + const Fixture = () => { + const notify = useNotifyError(); + return notify('Could not level up', raw, 'level-up')}>go; + }; + const tree = await renderInProvider(Fixture); + await ReactTestRenderer.act(() => { + tree.root.findByType(Text).props.onPress(); + }); + + expect(textOf(tree)).toContain('Could not level up'); + expect(console.error).toHaveBeenCalledWith('[level-up]', raw); + }); +}); + +describe('usePetErrorToast', () => { + it('fires a toast when a pet action fails', async () => { + mockUsePetError.mockReturnValue({ + message: 'Not enough ETH', + isUserRejection: false, + isContractError: true, + }); + const Fixture = () => { + usePetErrorToast(new Error('insufficient funds'), null, null, 'fallback'); + return null; + }; + const tree = await renderInProvider(Fixture); + expect(textOf(tree)).toContain('Not enough ETH'); + }); + + it('stays quiet when there is no error', async () => { + mockUsePetError.mockReturnValue({ + message: null, + isUserRejection: false, + isContractError: false, + }); + const Fixture = () => { + usePetErrorToast(null, null, null, 'fallback'); + return null; + }; + const tree = await renderInProvider(Fixture); + expect(textOf(tree)).toBe(''); + }); +}); + +describe('useTxErrorToast', () => { + it('fires a toast when a write fails', async () => { + mockUseTxError.mockReturnValue({ message: 'Transaction failed', isUserRejection: false }); + const Fixture = () => { + useTxErrorToast(new Error('reverted')); + return null; + }; + const tree = await renderInProvider(Fixture); + expect(textOf(tree)).toContain('Transaction failed'); + }); + + it('routes a user rejection to info rather than error', async () => { + // Tone is what separates "you cancelled" from "something broke"; a rejection + // shown in the error tone reads as a fault the player has to act on. + mockUseTxError.mockReturnValue({ message: 'You rejected the request', isUserRejection: true }); + const Fixture = () => { + useTxErrorToast(new Error('User rejected')); + return null; + }; + const tree = await renderInProvider(Fixture); + expect(textOf(tree)).toContain('You rejected the request'); + expect(console.error).toHaveBeenCalled(); + }); +}); diff --git a/mobile/src/components/ui/toast.tsx b/mobile/src/components/ui/toast.tsx new file mode 100644 index 00000000..0d71bbe6 --- /dev/null +++ b/mobile/src/components/ui/toast.tsx @@ -0,0 +1,149 @@ +import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { Pressable, StyleSheet, Text, View } from 'react-native'; + +import { neon, neonGlow } from '../../theme/neon'; + +/** + * RN equivalent of `frontend/src/components/ui/toast`. The context value is the + * same shape on purpose, so `useNotifyError`, `usePetErrorToast` and + * `useTxErrorToast` port across unchanged. + * + * Rendered as an absolutely positioned overlay rather than a portal, since RN has + * no document to portal into. It sits outside `SafeAreaProvider` (matching + * frontend's provider order, where `ToastProvider` wraps the router), so the + * bottom offset is a fixed inset rather than a measured one. + */ +export type ToastTone = 'error' | 'info' | 'success'; + +export type ToastInput = { + message: string; + tone?: ToastTone; +}; + +type ToastRecord = ToastInput & { + id: string; +}; + +type ToastContextValue = { + show: (input: ToastInput) => void; + error: (message: string) => void; + info: (message: string) => void; + success: (message: string) => void; +}; + +const ToastContext = createContext(null); + +const AUTO_DISMISS_MS = 5200; + +const TONE_COLOR: Record = { + error: neon.danger, + info: neon.cyan, + success: neon.success, +}; + +/** Stands in for `crypto.randomUUID`, which RN does not provide. */ +let nextToastId = 0; + +export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [toasts, setToasts] = useState([]); + const timersRef = useRef[]>([]); + + const dismiss = useCallback((id: string) => { + setToasts((current) => current.filter((toast) => toast.id !== id)); + }, []); + + const show = useCallback( + ({ message, tone = 'error' }: ToastInput) => { + const id = String(++nextToastId); + setToasts((current) => [...current, { id, message, tone }]); + timersRef.current.push(setTimeout(() => dismiss(id), AUTO_DISMISS_MS)); + }, + [dismiss], + ); + + // A pending timer fires into an unmounted provider on a fast reload otherwise. + useEffect( + () => () => { + timersRef.current.forEach(clearTimeout); + timersRef.current = []; + }, + [], + ); + + const value = useMemo( + () => ({ + show, + error: (message) => show({ message, tone: 'error' }), + info: (message) => show({ message, tone: 'info' }), + success: (message) => show({ message, tone: 'success' }), + }), + [show], + ); + + return ( + + {children} + {toasts.length > 0 && ( + + {toasts.map((toast) => { + const color = TONE_COLOR[toast.tone ?? 'error']; + return ( + + {toast.message} + dismiss(toast.id)} + hitSlop={8} + accessibilityRole="button" + accessibilityLabel="Dismiss notification" + > + × + + + ); + })} + + )} + + ); +}; + +export const useToast = (): ToastContextValue => { + const context = useContext(ToastContext); + if (!context) { + throw new Error('useToast must be used within ToastProvider'); + } + return context; +}; + +const styles = StyleSheet.create({ + viewport: { + position: 'absolute', + left: 16, + right: 16, + bottom: 32, + }, + toast: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: neon.bgPanel, + borderWidth: 1, + borderRadius: 12, + paddingHorizontal: 14, + paddingVertical: 12, + marginTop: 8, + }, + message: { + flex: 1, + fontSize: 14, + lineHeight: 20, + }, + dismiss: { + fontSize: 22, + fontWeight: '700', + marginLeft: 12, + }, +}); diff --git a/mobile/src/hooks/useNotifyError.ts b/mobile/src/hooks/useNotifyError.ts new file mode 100644 index 00000000..5dccf05b --- /dev/null +++ b/mobile/src/hooks/useNotifyError.ts @@ -0,0 +1,20 @@ +import { useCallback } from 'react'; + +import { useToast } from '../components/ui/toast'; + +/** Logs technical details to the console and shows a friendly toast to the user. */ +export const useNotifyError = () => { + const toast = useToast(); + + return useCallback( + (message: string, rawError?: unknown, context = 'action') => { + if (rawError !== undefined) { + console.error(`[${context}]`, rawError); + } else { + console.error(`[${context}]`, message); + } + toast.error(message); + }, + [toast], + ); +}; diff --git a/mobile/src/hooks/usePetErrorToast.ts b/mobile/src/hooks/usePetErrorToast.ts new file mode 100644 index 00000000..ffbdd048 --- /dev/null +++ b/mobile/src/hooks/usePetErrorToast.ts @@ -0,0 +1,58 @@ +import { useEffect, useRef } from 'react'; +import { usePetError } from '@shared/core'; + +import { useToast } from '../components/ui/toast'; + +/** + * Maps pet-action errors to friendly toast messages. + * Raw transaction / contract errors are logged to the console only. + */ +export const usePetErrorToast = ( + mutationError: Error | null | undefined, + receiptError: Error | null | undefined, + validationError: string | null, + fallbackMessage: string, +): void => { + const toast = useToast(); + const display = usePetError(mutationError, receiptError, validationError, fallbackMessage); + const lastKeyRef = useRef(null); + + useEffect(() => { + if (!display.message) { + lastKeyRef.current = null; + return; + } + + const key = [ + validationError ?? '', + mutationError?.message ?? '', + receiptError?.message ?? '', + display.message, + ].join('|'); + + if (key === lastKeyRef.current) return; + lastKeyRef.current = key; + + if (receiptError) { + console.error('[pet-action] receipt error:', receiptError); + } else if (mutationError) { + console.error('[pet-action] mutation error:', mutationError); + } else if (validationError) { + console.error('[pet-action] validation error:', validationError); + } + + if (display.isUserRejection) { + toast.info(display.message); + return; + } + + toast.error(display.message); + }, [ + display.message, + display.isUserRejection, + mutationError, + receiptError, + validationError, + toast, + ]); +}; diff --git a/mobile/src/hooks/useTxErrorToast.ts b/mobile/src/hooks/useTxErrorToast.ts new file mode 100644 index 00000000..6ae23589 --- /dev/null +++ b/mobile/src/hooks/useTxErrorToast.ts @@ -0,0 +1,33 @@ +import { useEffect, useRef } from 'react'; +import { useTxError } from '@shared/core'; + +import { useToast } from '../components/ui/toast'; + +export const useTxErrorToast = ( + writeError: unknown, + fallback = 'Transaction failed. Please try again.', +) => { + const parsed = useTxError(writeError, fallback); + const toast = useToast(); + const lastKeyRef = useRef(null); + + useEffect(() => { + if (!parsed) { + lastKeyRef.current = null; + return; + } + + const key = `${String(writeError)}|${parsed.message}`; + if (key === lastKeyRef.current) return; + lastKeyRef.current = key; + + console.error('[contract-write]', writeError); + + if (parsed.isUserRejection) { + toast.info(parsed.message); + return; + } + + toast.error(parsed.message); + }, [parsed, writeError, toast]); +}; From 80aad2bfbc7e080c6d3c5f288e47a28310df4a72 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 16:24:25 -0400 Subject: [PATCH 07/99] feat(mobile): add the navigation shell --- mobile/__tests__/navigation.test.tsx | 97 ++ mobile/jest.config.js | 10 +- mobile/package.json | 4 + mobile/src/navigation/RootNavigator.tsx | 118 +++ mobile/src/navigation/routes.ts | 56 + mobile/src/screens/PlaceholderScreen.tsx | 45 + pnpm-lock.yaml | 1189 +++++++++++++--------- 7 files changed, 1033 insertions(+), 486 deletions(-) create mode 100644 mobile/__tests__/navigation.test.tsx create mode 100644 mobile/src/navigation/RootNavigator.tsx create mode 100644 mobile/src/navigation/routes.ts create mode 100644 mobile/src/screens/PlaceholderScreen.tsx diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx new file mode 100644 index 00000000..518f3163 --- /dev/null +++ b/mobile/__tests__/navigation.test.tsx @@ -0,0 +1,97 @@ +/** + * Navigator smoke test: the tab shell mounts, every route in the table is + * reachable, and the initial screen renders. Screens are placeholders until + * Phase 4, so this checks wiring rather than content. + */ + +import React from 'react'; +import { Text } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; +import { NavigationContainer } from '@react-navigation/native'; + +import { RootNavigator } from '../src/navigation/RootNavigator'; +import { STACK_TITLES, TAB_ITEMS } from '../src/navigation/routes'; + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create( + + + , + ); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + const walk = (child: unknown): string => + typeof child === 'string' + ? child + : Array.isArray(child) + ? child.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' '); + +describe('routes', () => { + it('has five tabs, not the seven routed sidebar entries', () => { + // Past five, a bottom tab bar truncates labels past readability. If this + // changes, the entry also needs moving out of RootStackParamList. + expect(TAB_ITEMS).toHaveLength(5); + expect(TAB_ITEMS.map((t) => t.name)).toEqual([ + 'Gallery', + 'Battle', + 'Breed', + 'LevelUp', + 'Train', + ]); + }); + + it('keeps the per-pet actions on the stack', () => { + expect(Object.keys(STACK_TITLES)).toEqual(['Marriage', 'Rename', 'Defense']); + }); + + it('does not route the deferred features', () => { + const everyRoute = [...TAB_ITEMS.map((t) => t.name), ...Object.keys(STACK_TITLES)]; + expect(everyRoute).not.toContain('Inventory'); + expect(everyRoute).not.toContain('ShardForge'); + }); +}); + +describe('RootNavigator', () => { + it('mounts the tab shell and renders the first tab', async () => { + const tree = await render(); + expect(textOf(tree)).toContain('Gallery'); + }); + + it('renders a tab bar entry for every item in the table', async () => { + const tree = await render(); + const rendered = textOf(tree); + TAB_ITEMS.forEach((item) => { + expect(rendered).toContain(item.label); + }); + }); + + it('exposes every route to navigation', async () => { + let container!: ReactTestRenderer.ReactTestRenderer; + const ref = React.createRef>(); + await ReactTestRenderer.act(() => { + container = ReactTestRenderer.create( + + + , + ); + }); + + const names = ref.current?.getRootState().routeNames ?? []; + expect(names).toEqual( + expect.arrayContaining(['Landing', 'Main', 'Marriage', 'Rename', 'Defense']), + ); + expect(container).toBeTruthy(); + }); +}); diff --git a/mobile/jest.config.js b/mobile/jest.config.js index a1eacd75..7de75dce 100644 --- a/mobile/jest.config.js +++ b/mobile/jest.config.js @@ -5,10 +5,12 @@ module.exports = { // it, jest cannot parse it, and nothing under test reads from it. '^@walletconnect/react-native-compat$': '/__mocks__/walletconnectCompat.js', }, - // wagmi and viem ship ESM only. Metro handles that; jest does not, and the - // react-native preset's default pattern skips everything in node_modules except - // react-native itself, so anything importing `wagmi/chains` dies on `export *`. + // wagmi, viem and React Navigation ship ESM only. Metro handles that; jest does + // not, and the react-native preset's default pattern skips everything in + // node_modules except react-native itself, so importing any of them dies on + // `export *`. `react-native-*` covers the navigation native peers (screens, + // safe-area-context) as well as react-native itself. transformIgnorePatterns: [ - 'node_modules/(?!(?:@react-native|react-native|wagmi|@wagmi|viem|ox|abitype)/)', + 'node_modules/(?!(?:@react-native|react-native|react-native-.*|@react-navigation|wagmi|@wagmi|viem|ox|abitype)/)', ], }; diff --git a/mobile/package.json b/mobile/package.json index a8b758f4..67a1515c 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -18,6 +18,9 @@ "@solana/web3.js": "^1.95.2", "@react-native-async-storage/async-storage": "^2.2.0", "@react-native-community/netinfo": "^11.4.1", + "@react-navigation/bottom-tabs": "^7.18.14", + "@react-navigation/native": "^7.3.14", + "@react-navigation/native-stack": "^7.18.6", "@reown/appkit-react-native": "^2.0.1", "@reown/appkit-solana-react-native": "^2.0.1", "@reown/appkit-wagmi-react-native": "^2.0.1", @@ -28,6 +31,7 @@ "react-native-dotenv": "^3.4.11", "react-native-get-random-values": "^2.0.0", "react-native-safe-area-context": "^5.5.2", + "react-native-screens": "^4.26.2", "react-native-svg": "^15.14.0", "bs58": "^6.0.0", "viem": "~2.38.3", diff --git a/mobile/src/navigation/RootNavigator.tsx b/mobile/src/navigation/RootNavigator.tsx new file mode 100644 index 00000000..eca70d6e --- /dev/null +++ b/mobile/src/navigation/RootNavigator.tsx @@ -0,0 +1,118 @@ +import React from 'react'; +import { StyleSheet, Text } from 'react-native'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; + +import { placeholderFor } from '../screens/PlaceholderScreen'; +import { neon } from '../theme/neon'; +import { + STACK_TITLES, + TAB_ITEMS, + type MainTabParamList, + type RootStackParamList, +} from './routes'; + +const Tab = createBottomTabNavigator(); +const Stack = createNativeStackNavigator(); + +/** Phase 4 swaps these for the real screens, one per commit. */ +const TAB_SCREENS: Record = { + Gallery: placeholderFor('Gallery'), + Battle: placeholderFor('Battle Arena'), + Breed: placeholderFor('Breeding Lab'), + LevelUp: placeholderFor('Level Up'), + Train: placeholderFor('Training Ground'), +}; + +const STACK_SCREENS = { + Marriage: placeholderFor('Marriage'), + Rename: placeholderFor('Rename Pet'), + Defense: placeholderFor('Allow Challenges'), +} as const; + +/** + * Built once at module scope rather than inline in the map below. `tabBarIcon` is + * a render prop, so defining it during render hands the tab bar a new component + * type every pass and remounts the icon. + */ +const TAB_OPTIONS = Object.fromEntries( + TAB_ITEMS.map((item) => { + const Icon = ({ color }: { color: string }) => ( + {item.glyph} + ); + Icon.displayName = `TabIcon(${item.name})`; + return [item.name, { title: item.label, tabBarIcon: Icon }]; + }), +) as Record }>; + +export const MainTabs = () => ( + + {TAB_ITEMS.map((item) => ( + + ))} + +); + +/** + * Landing sits outside the tab shell so the connect screen has no tab bar. The + * gate that decides which one is shown lands in step 3.2; for now `Main` is the + * initial route so the shell can be exercised. + */ +export const RootNavigator = () => ( + + + + {(Object.keys(STACK_SCREENS) as (keyof typeof STACK_SCREENS)[]).map((name) => ( + + ))} + +); + +const styles = StyleSheet.create({ + tabBar: { + backgroundColor: neon.bgPanel, + borderTopColor: neon.border, + }, + tabLabel: { + fontSize: 11, + fontWeight: '700', + }, + tabGlyph: { + fontSize: 18, + }, + header: { + backgroundColor: neon.bgPanel, + }, + content: { + backgroundColor: neon.bgDeep, + }, +}); diff --git a/mobile/src/navigation/routes.ts b/mobile/src/navigation/routes.ts new file mode 100644 index 00000000..64dea40a --- /dev/null +++ b/mobile/src/navigation/routes.ts @@ -0,0 +1,56 @@ +/** + * Route table, mirroring `frontend/src/constants/interactionRoutes.ts` and the + * sidebar's `NAV_ITEMS`. Same destinations, different shape: frontend renders all + * seven as sidebar entries, mobile splits them between a tab bar and the stack. + * + * Inventory and Shard Forge are deferred in frontend and absent here too, rather + * than shown disabled: a tab bar has no room to advertise what does not work yet. + */ + +/** Screens pushed over the tab shell. `undefined` = takes no params. */ +export type RootStackParamList = { + Landing: undefined; + Main: undefined; + Marriage: undefined; + Rename: { petId?: string } | undefined; + Defense: { petId?: string } | undefined; +}; + +export type MainTabParamList = { + Gallery: undefined; + Battle: { roomId?: string } | undefined; + Breed: undefined; + LevelUp: undefined; + Train: undefined; +}; + +export type TabItem = { + name: keyof MainTabParamList; + label: string; + /** Stands in for frontend's per-item SVG; RN has no icon set wired up yet. */ + glyph: string; +}; + +/** + * The tab bar, in `NAV_ITEMS` order. + * + * Five, not the seven routed sidebar entries: past five a bottom tab bar truncates + * labels to the point of being unreadable. Marriage and Rename move to the stack + * because both act on one chosen pet, which is the same reason `defense` is a + * per-pet action rather than a tab. Moving one back is an edit to this array plus + * its `RootStackParamList` entry. + */ +export const TAB_ITEMS: readonly TabItem[] = [ + { name: 'Gallery', label: 'Gallery', glyph: '◈' }, + { name: 'Battle', label: 'Battle', glyph: '⚔' }, + { name: 'Breed', label: 'Breed', glyph: '❋' }, + { name: 'LevelUp', label: 'Level Up', glyph: '▲' }, + { name: 'Train', label: 'Train', glyph: '◉' }, +]; + +/** Titles for the stack screens, matching `STANDALONE_INTERACTION_HEADERS`. */ +export const STACK_TITLES: Record, string> = { + Marriage: 'Marriage', + Rename: 'Rename Pet', + Defense: 'Allow Challenges', +}; diff --git a/mobile/src/screens/PlaceholderScreen.tsx b/mobile/src/screens/PlaceholderScreen.tsx new file mode 100644 index 00000000..81a55ef7 --- /dev/null +++ b/mobile/src/screens/PlaceholderScreen.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { StyleSheet, Text, View } from 'react-native'; + +import { neon } from '../theme/neon'; + +/** + * Stands in for a screen until Phase 4 builds it. Each real screen replaces one + * of these, so the navigator can be wired and tested before any of them exist. + */ +export const PlaceholderScreen = ({ title }: { title: string }) => ( + + {title} + Not built yet. + +); + +/** Named factory so each route gets a stable component identity across renders. */ +export const placeholderFor = (title: string) => { + const Screen = () => ; + Screen.displayName = `Placeholder(${title})`; + return Screen; +}; + +const styles = StyleSheet.create({ + root: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: neon.bgDeep, + padding: 24, + }, + title: { + fontSize: 22, + fontWeight: '800', + color: neon.text, + marginBottom: 8, + textShadowColor: neon.cyan, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 10, + }, + body: { + fontSize: 15, + color: neon.textMuted, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a10e755..e4d66b3a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -241,16 +241,16 @@ importers: dependencies: '@dynamic-labs/ethereum': specifier: ^4.37.1 - version: 4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + version: 4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@dynamic-labs/sdk-react-core': specifier: ^4.37.1 version: 4.40.1(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@19.1.1(react@19.1.1))(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(utf-8-validate@5.0.10) '@dynamic-labs/solana': specifier: ^4.37.1 - version: 4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + version: 4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@dynamic-labs/wagmi-connector': specifier: ^4.37.1 - version: 4.40.1(lupvgyugmbc5ztyp7prdwbwueq) + version: 4.40.1(6pshzk3dt2fxrycfxy5f4d5jsi) '@shared/core': specifier: workspace:* version: link:../shared @@ -262,7 +262,7 @@ importers: version: 0.9.39(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bs58@5.0.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(typescript@5.8.3) '@solana/wallet-adapter-wallets': specifier: ^0.19.32 - version: 0.19.37(wcwzcvkiean7xoqtynzwkhqyla) + version: 0.19.37(k66plh6iifxyw5d3zjvlhcznga) '@solana/web3.js': specifier: ^1.95.2 version: 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) @@ -292,10 +292,10 @@ importers: version: 7.13.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) viem: specifier: ^2.37.7 - version: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + version: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) wagmi: specifier: ^2.17.1 - version: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + version: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) devDependencies: '@eslint/js': specifier: ^9.36.0 @@ -390,15 +390,24 @@ importers: '@react-native-community/netinfo': specifier: ^11.4.1 version: 11.4.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)) + '@react-navigation/bottom-tabs': + specifier: ^7.18.14 + version: 7.18.14(vzhavef6vncmqxwgvkqusq63fa) + '@react-navigation/native': + specifier: ^7.3.14 + version: 7.3.14(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + '@react-navigation/native-stack': + specifier: ^7.18.6 + version: 7.18.6(vzhavef6vncmqxwgvkqusq63fa) '@reown/appkit-react-native': specifier: ^2.0.1 - version: 2.0.1(htg2tpf3zzmsrhrwiskzh3ey3i) + version: 2.0.1(x6p2ghfntjx42rethspyovjvr4) '@reown/appkit-solana-react-native': specifier: ^2.0.1 version: 2.0.1(@walletconnect/react-native-compat@2.23.0(lh5jzsrjqwxruiai4runjz3fou))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10) '@reown/appkit-wagmi-react-native': specifier: ^2.0.1 - version: 2.0.1(gbsuv35t73ppduqv7v3dwovljy) + version: 2.0.1(shpadx773iilzq7h2tdwz2t7he) '@shared/core': specifier: workspace:* version: link:../shared @@ -429,15 +438,18 @@ importers: react-native-safe-area-context: specifier: ^5.5.2 version: 5.6.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + react-native-screens: + specifier: ^4.26.2 + version: 4.26.2(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) react-native-svg: specifier: ^15.14.0 version: 15.14.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) viem: specifier: ~2.38.3 - version: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + version: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) wagmi: specifier: ^2.18.2 - version: 2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) devDependencies: '@babel/core': specifier: ^7.25.2 @@ -568,7 +580,7 @@ importers: version: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) wagmi: specifier: ^2.0.0 - version: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) devDependencies: '@eslint/js': specifier: ^9.36.0 @@ -3221,7 +3233,7 @@ packages: '@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' + deprecated: 'Switch to "qr" (new package name) for security updates: npm install qr' '@pinax/graph-networks-registry@0.7.1': resolution: {integrity: sha512-Gn2kXRiEd5COAaMY/aDCRO0V+zfb1uQKCu5HFPoWka+EsZW27AlTINA7JctYYYEMuCbjMia5FBOzskjgEvj6LA==} @@ -3573,6 +3585,50 @@ packages: '@types/react': optional: true + '@react-navigation/bottom-tabs@7.18.14': + resolution: {integrity: sha512-A3V9rDSut459TBPtkD7rb0npUUBlJBfMunyRT5nOGKqPguhuXWk1h91NfQMuqyW2DCUvvFZChzsbLbj42rXTdQ==} + peerDependencies: + '@react-navigation/native': ^7.3.14 + react: '>= 18.2.0' + react-native: '*' + react-native-safe-area-context: '>= 4.0.0' + react-native-screens: '>= 4.0.0' + + '@react-navigation/core@7.21.11': + resolution: {integrity: sha512-bCW1PsLA/eOXDOukcJFEzlcL3Zpy8DJuDCfkDDwAQlAgoSZ/J9+ZeDRUMmCUi6xbnFgvFEEIMertaLeErOFP0Q==} + peerDependencies: + react: '>= 18.2.0' + + '@react-navigation/elements@2.9.36': + resolution: {integrity: sha512-+10x9s5v2Q7FwAYdSmPMgILtxZyC5e4hWJQu8g5o3u4p8DUToTBmGvys/UvmEr+h9xmm0Go42qw9Ff2ape53kQ==} + peerDependencies: + '@react-native-masked-view/masked-view': '>= 0.2.0' + '@react-navigation/native': ^7.3.14 + react: '>= 18.2.0' + react-native: '*' + react-native-safe-area-context: '>= 4.0.0' + peerDependenciesMeta: + '@react-native-masked-view/masked-view': + optional: true + + '@react-navigation/native-stack@7.18.6': + resolution: {integrity: sha512-KuvvSBddHrbKC4c6yKz+UCFey2xgTuPQHgjf2wJQAvA7JM8jCQa3G1+QzhO6d44nYNKir3y6EounXZvQE/BX6w==} + peerDependencies: + '@react-navigation/native': ^7.3.14 + react: '>= 18.2.0' + react-native: '*' + react-native-safe-area-context: '>= 4.0.0' + react-native-screens: '>= 4.0.0' + + '@react-navigation/native@7.3.14': + resolution: {integrity: sha512-hcKTDNBuuAA1/xW6QeKYmMPVhk5W9dKGQpPmn5dQeeePwMpu5OZ14NOgwKH0w9D3tg2jupojTcVL0tsx5DTFXg==} + peerDependencies: + react: '>= 18.2.0' + react-native: '*' + + '@react-navigation/routers@7.6.4': + resolution: {integrity: sha512-GI7eJm8/KsZUQaYcXvEExikKurRZRgEsSzyZ7faENfi65yqJBCXjDMwyN1pF6pNW1MoLH1ErDwDivFxY6BzD3w==} + '@reown/appkit-common-react-native@2.0.1': resolution: {integrity: sha512-xw+4gJBQSakcBn9rHCoH1gnr0PsmurJ0GMx+sIz8focuZqWNcsN+84tEHtQPo1bkfTwvv3WoNPV2tzZnpaQxRA==} peerDependencies: @@ -9763,6 +9819,12 @@ packages: '@types/react': optional: true + react-freeze@1.0.4: + resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==} + engines: {node: '>=10'} + peerDependencies: + react: '>=17.0.0' + react-i18next@13.5.0: resolution: {integrity: sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==} peerDependencies: @@ -9826,6 +9888,12 @@ packages: react: '*' react-native: '*' + react-native-screens@4.26.2: + resolution: {integrity: sha512-2XnWsZToKj76trGtEZzx5ELD/qOICFEprEeUntImmitQFVUkea27fiWdUSITArI356Y1qynpXZINW+Unbhky/A==} + peerDependencies: + react: '*' + react-native: '*' + react-native-svg@15.14.0: resolution: {integrity: sha512-B3gYc7WztcOT4N54AtUutbe0Nuqqh/nkresY0fAXzUHYLsWuIu/yGiCCD3DKfAs6GLv5LFtWTu7N333Q+e3bkg==} peerDependencies: @@ -10189,6 +10257,10 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sf-symbols-typescript@2.2.0: + resolution: {integrity: sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==} + engines: {node: '>=10'} + sha.js@2.4.12: resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} engines: {node: '>= 0.10'} @@ -10346,6 +10418,11 @@ packages: standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + standard-navigation@0.0.8: + resolution: {integrity: sha512-TyVbo7INUDWtsUWDFn8RR7kwR87U0S4xHfLfbbnyeC581TmmyqQ+eM+nPw8rQTSD8QitRVcYfPaSHr/QJiUy1g==} + peerDependencies: + react: '*' + statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -10954,6 +11031,11 @@ packages: '@types/react': optional: true + use-latest-callback@0.2.6: + resolution: {integrity: sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==} + peerDependencies: + react: '>=16.8' + use-sidecar@1.1.3: resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} @@ -10969,6 +11051,11 @@ packages: 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'} @@ -11665,7 +11752,7 @@ snapshots: '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11725,7 +11812,7 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) lodash.debounce: 4.0.8 resolve: 1.22.11 transitivePeerDependencies: @@ -12460,7 +12547,7 @@ snapshots: '@babel/parser': 7.28.5 '@babel/template': 7.27.2 '@babel/types': 7.28.5 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -12514,6 +12601,26 @@ snapshots: - utf-8-validate - zod + '@base-org/account@1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(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.8.3)(zod@3.25.76) + preact: 10.24.2 + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.6.0(react@19.1.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + '@bcoe/v8-coverage@0.2.3': {} '@bcoe/v8-coverage@1.0.2': {} @@ -12582,13 +12689,13 @@ snapshots: - utf-8-validate - zod - '@coinbase/wallet-sdk@4.3.7(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@coinbase/wallet-sdk@4.3.7(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/hashes': 1.8.0 clsx: 1.2.1 eventemitter3: 5.0.1 preact: 10.27.2 - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - typescript @@ -12674,12 +12781,12 @@ snapshots: '@leichtgewicht/ip-codec': 2.0.5 utf8-codec: 1.0.0 - '@dynamic-labs-connectors/base-account-evm@4.4.2(@dynamic-labs/ethereum-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)))(@dynamic-labs/wallet-connector-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3)': + '@dynamic-labs-connectors/base-account-evm@4.4.2(@dynamic-labs/ethereum-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(@dynamic-labs/wallet-connector-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: - '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@4.4.3) - '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@types/react' - bufferutil @@ -12781,11 +12888,11 @@ snapshots: dependencies: '@dynamic-labs/logger': 4.40.1 - '@dynamic-labs/embedded-wallet-evm@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3)': + '@dynamic-labs/embedded-wallet-evm@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 '@dynamic-labs/embedded-wallet': 4.40.1(encoding@0.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/sdk-api-core': 0.0.813 '@dynamic-labs/types': 4.40.1 '@dynamic-labs/utils': 4.40.1 @@ -12794,9 +12901,9 @@ snapshots: '@dynamic-labs/webauthn': 4.40.1 '@turnkey/api-key-stamper': 0.4.7 '@turnkey/iframe-stamper': 2.5.0 - '@turnkey/viem': 0.13.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + '@turnkey/viem': 0.13.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@turnkey/webauthn-stamper': 0.5.1 - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - encoding @@ -12806,7 +12913,7 @@ snapshots: - utf-8-validate - zod - '@dynamic-labs/embedded-wallet-solana@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@dynamic-labs/embedded-wallet-solana@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@dynamic-labs-sdk/client': 0.1.0-alpha.23(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@dynamic-labs/assert-package-version': 4.40.1 @@ -12821,9 +12928,9 @@ snapshots: '@dynamic-labs/webauthn': 4.40.1 '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) '@turnkey/iframe-stamper': 2.5.0 - '@turnkey/solana': 1.0.42(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@turnkey/solana': 1.0.42(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@turnkey/webauthn-stamper': 0.5.1 - viem: 2.29.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.29.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - debug @@ -12853,7 +12960,7 @@ snapshots: - react - react-dom - '@dynamic-labs/ethereum-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))': + '@dynamic-labs/ethereum-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 '@dynamic-labs/logger': 4.40.1 @@ -12863,30 +12970,30 @@ snapshots: '@dynamic-labs/utils': 4.40.1 '@dynamic-labs/wallet-book': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - react - react-dom - '@dynamic-labs/ethereum@4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3)': + '@dynamic-labs/ethereum@4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(immer@10.0.2)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: - '@coinbase/wallet-sdk': 4.3.7(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@dynamic-labs-connectors/base-account-evm': 4.4.2(@dynamic-labs/ethereum-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)))(@dynamic-labs/wallet-connector-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + '@coinbase/wallet-sdk': 4.3.7(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@dynamic-labs-connectors/base-account-evm': 4.4.2(@dynamic-labs/ethereum-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(@dynamic-labs/wallet-connector-core@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@dynamic-labs/assert-package-version': 4.40.1 - '@dynamic-labs/embedded-wallet-evm': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) - '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/embedded-wallet-evm': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/logger': 4.40.1 '@dynamic-labs/rpc-providers': 4.40.1 '@dynamic-labs/types': 4.40.1 '@dynamic-labs/utils': 4.40.1 - '@dynamic-labs/waas-evm': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@dynamic-labs/waas-evm': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@dynamic-labs/wallet-book': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@metamask/sdk': 0.33.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@walletconnect/ethereum-provider': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/ethereum-provider': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) buffer: 6.0.3 eventemitter3: 5.0.1 - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -13033,28 +13140,28 @@ snapshots: - typescript - utf-8-validate - '@dynamic-labs/solana@4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3)': + '@dynamic-labs/solana@4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(ioredis@5.11.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 - '@dynamic-labs/embedded-wallet-solana': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@dynamic-labs/embedded-wallet-solana': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@dynamic-labs/logger': 4.40.1 '@dynamic-labs/rpc-providers': 4.40.1 '@dynamic-labs/sdk-api-core': 0.0.813 '@dynamic-labs/solana-core': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10) '@dynamic-labs/types': 4.40.1 '@dynamic-labs/utils': 4.40.1 - '@dynamic-labs/waas-svm': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/waas-svm': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/wallet-book': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@dynamic-labs/wallet-connect': 4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@dynamic-labs/wallet-connect': 4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) '@wallet-standard/app': 1.0.1 '@wallet-standard/base': 1.0.1 '@wallet-standard/experimental-features': 0.1.1 '@wallet-standard/features': 1.0.3 - '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 5.0.0 eventemitter3: 5.0.1 tweetnacl: 1.0.3 @@ -13131,17 +13238,17 @@ snapshots: eventemitter3: 5.0.1 tldts: 6.0.16 - '@dynamic-labs/waas-evm@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@dynamic-labs/waas-evm@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 - '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/logger': 4.40.1 '@dynamic-labs/sdk-api-core': 0.0.813 '@dynamic-labs/types': 4.40.1 '@dynamic-labs/utils': 4.40.1 - '@dynamic-labs/waas': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/waas': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@gql.tada/svelte-support' - '@gql.tada/vue-support' @@ -13155,7 +13262,7 @@ snapshots: - utf-8-validate - zod - '@dynamic-labs/waas-svm@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))': + '@dynamic-labs/waas-svm@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 '@dynamic-labs/logger': 4.40.1 @@ -13164,7 +13271,7 @@ snapshots: '@dynamic-labs/solana-core': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10) '@dynamic-labs/types': 4.40.1 '@dynamic-labs/utils': 4.40.1 - '@dynamic-labs/waas': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/waas': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) bs58: 5.0.0 @@ -13182,11 +13289,11 @@ snapshots: - utf-8-validate - viem - '@dynamic-labs/waas@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))': + '@dynamic-labs/waas@4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@dynamic-labs-wallet/browser-wallet-client': 0.0.187(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@dynamic-labs/assert-package-version': 4.40.1 - '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/sdk-api-core': 0.0.813 '@dynamic-labs/solana-core': 4.40.1(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10) '@dynamic-labs/sui-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3) @@ -13205,20 +13312,20 @@ snapshots: - utf-8-validate - viem - '@dynamic-labs/wagmi-connector@4.40.1(lupvgyugmbc5ztyp7prdwbwueq)': + '@dynamic-labs/wagmi-connector@4.40.1(6pshzk3dt2fxrycfxy5f4d5jsi)': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 - '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@dynamic-labs/ethereum-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@dynamic-labs/logger': 4.40.1 '@dynamic-labs/rpc-providers': 4.40.1 '@dynamic-labs/sdk-react-core': 4.40.1(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@19.1.1(react@19.1.1))(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(utf-8-validate@5.0.10) '@dynamic-labs/types': 4.40.1 '@dynamic-labs/wallet-connector-core': 4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) eventemitter3: 5.0.4 react: 19.1.1 - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - wagmi: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + wagmi: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@dynamic-labs/wallet-book@4.40.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: @@ -13232,11 +13339,11 @@ snapshots: util: 0.12.5 zod: 4.0.5 - '@dynamic-labs/wallet-connect@4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@dynamic-labs/wallet-connect@4.40.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@dynamic-labs/assert-package-version': 4.40.1 '@dynamic-labs/logger': 4.40.1 - '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -13415,7 +13522,7 @@ snapshots: '@eslint/config-array@0.21.1': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -13431,7 +13538,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -13445,7 +13552,7 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -13726,7 +13833,7 @@ snapshots: '@whatwg-node/fetch': 0.10.13 assemblyscript: 0.19.23 chokidar: 4.0.3 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) decompress: 4.2.1 docker-compose: 1.3.0 fs-extra: 11.3.2 @@ -13817,7 +13924,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -14560,7 +14667,7 @@ snapshots: bufferutil: 4.0.9 cross-fetch: 4.1.0(encoding@0.1.13) date-fns: 2.30.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eciesjs: 0.4.16 eventemitter2: 6.4.9 readable-stream: 3.6.2 @@ -14601,7 +14708,7 @@ snapshots: '@paulmillr/qr': 0.2.1 bowser: 2.12.1 cross-fetch: 4.1.0(encoding@0.1.13) - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eciesjs: 0.4.16 eth-rpc-errors: 4.0.3 eventemitter2: 6.4.9 @@ -14656,7 +14763,7 @@ snapshots: '@scure/base': 1.2.6 '@types/debug': 4.1.12 '@types/lodash': 4.17.20 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) lodash: 4.18.1 pony-cause: 2.1.11 semver: 7.8.1 @@ -14668,7 +14775,7 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) semver: 7.8.1 superstruct: 1.0.4 transitivePeerDependencies: @@ -14681,7 +14788,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) pony-cause: 2.1.11 semver: 7.8.1 uuid: 9.0.1 @@ -14695,7 +14802,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) pony-cause: 2.1.11 semver: 7.8.1 uuid: 9.0.1 @@ -14955,7 +15062,7 @@ snapshots: '@nomicfoundation/ignition-core': 3.0.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@nomicfoundation/ignition-ui': 3.0.3 chalk: 5.6.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) hardhat: 3.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) json5: 2.2.3 prompts: 2.4.2 @@ -14972,7 +15079,7 @@ snapshots: '@nomicfoundation/hardhat-utils': 3.0.3 '@nomicfoundation/hardhat-zod-utils': 3.0.5(zod@3.25.76) chalk: 5.6.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) hardhat: 3.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) zod: 3.25.76 transitivePeerDependencies: @@ -15021,7 +15128,7 @@ snapshots: '@nomicfoundation/hardhat-utils@3.0.3': dependencies: '@streamparser/json-node': 0.0.22 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) env-paths: 2.2.1 ethereum-cryptography: 2.2.1 fast-equals: 5.3.2 @@ -15034,7 +15141,7 @@ snapshots: '@nomicfoundation/hardhat-utils@4.0.1': dependencies: '@streamparser/json-node': 0.0.22 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) env-paths: 2.2.1 ethereum-cryptography: 2.2.1 fast-equals: 5.4.0 @@ -15064,7 +15171,7 @@ snapshots: '@nomicfoundation/hardhat-zod-utils': 3.0.5(zod@3.25.76) cbor2: 1.12.0 chalk: 5.6.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) hardhat: 3.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) semver: 7.8.1 zod: 3.25.76 @@ -15111,7 +15218,7 @@ snapshots: '@nomicfoundation/hardhat-utils': 3.0.3 '@nomicfoundation/solidity-analyzer': 0.1.2 cbor2: 1.12.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) immer: 10.0.2 lodash-es: 4.17.21 @@ -15200,7 +15307,7 @@ snapshots: dependencies: '@oclif/core': 4.11.4 ansis: 3.17.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) ejs: 3.1.10 transitivePeerDependencies: - supports-color @@ -15218,7 +15325,7 @@ snapshots: dependencies: '@oclif/core': 4.11.4 ansis: 3.17.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) http-call: 5.3.0 lodash: 4.18.1 registry-auth-token: 5.1.1 @@ -15690,7 +15797,7 @@ snapshots: '@react-native/community-cli-plugin@0.82.0(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@react-native/dev-middleware': 0.82.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) invariant: 2.2.4 metro: 0.83.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) metro-config: 0.83.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -15719,7 +15826,7 @@ snapshots: chrome-launcher: 0.15.2 chromium-edge-launcher: 0.2.0 connect: 3.7.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) invariant: 2.2.4 nullthrows: 1.1.1 open: 7.4.2 @@ -15791,6 +15898,70 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 + '@react-navigation/bottom-tabs@7.18.14(vzhavef6vncmqxwgvkqusq63fa)': + dependencies: + '@react-navigation/elements': 2.9.36(6vcniidslwinbtoxwnoefnjzfm) + '@react-navigation/native': 7.3.14(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + color: 4.2.3 + react: 19.1.1 + react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + react-native-safe-area-context: 5.6.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + react-native-screens: 4.26.2(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + sf-symbols-typescript: 2.2.0 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + + '@react-navigation/core@7.21.11(react@19.1.1)': + dependencies: + '@react-navigation/routers': 7.6.4 + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.11 + query-string: 7.1.3 + react: 19.1.1 + react-is: 19.2.0 + use-latest-callback: 0.2.6(react@19.1.1) + use-sync-external-store: 1.6.0(react@19.1.1) + + '@react-navigation/elements@2.9.36(6vcniidslwinbtoxwnoefnjzfm)': + dependencies: + '@react-navigation/native': 7.3.14(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + color: 4.2.3 + react: 19.1.1 + react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + react-native-safe-area-context: 5.6.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + use-latest-callback: 0.2.6(react@19.1.1) + use-sync-external-store: 1.6.0(react@19.1.1) + + '@react-navigation/native-stack@7.18.6(vzhavef6vncmqxwgvkqusq63fa)': + dependencies: + '@react-navigation/elements': 2.9.36(6vcniidslwinbtoxwnoefnjzfm) + '@react-navigation/native': 7.3.14(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + color: 4.2.3 + react: 19.1.1 + react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + react-native-safe-area-context: 5.6.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + react-native-screens: 4.26.2(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + sf-symbols-typescript: 2.2.0 + warn-once: 0.1.1 + transitivePeerDependencies: + - '@react-native-masked-view/masked-view' + + '@react-navigation/native@7.3.14(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)': + dependencies: + '@react-navigation/core': 7.21.11(react@19.1.1) + escape-string-regexp: 4.0.0 + fast-deep-equal: 3.1.3 + nanoid: 3.3.11 + react: 19.1.1 + react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + standard-navigation: 0.0.8(react@19.1.1) + use-latest-callback: 0.2.6(react@19.1.1) + + '@react-navigation/routers@7.6.4': + dependencies: + nanoid: 3.3.11 + '@reown/appkit-common-react-native@2.0.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)': dependencies: bignumber.js: 9.1.2 @@ -15809,11 +15980,11 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-common@1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit-common@1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: big.js: 6.2.2 dayjs: 1.11.13 - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - typescript @@ -15853,13 +16024,13 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit-controllers@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -15888,13 +16059,13 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit-controllers@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -15923,13 +16094,13 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -15958,11 +16129,11 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: @@ -16005,12 +16176,12 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@reown/appkit-pay@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit-pay@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) lit: 3.3.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) transitivePeerDependencies: @@ -16041,12 +16212,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) lit: 3.3.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) transitivePeerDependencies: @@ -16077,12 +16248,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) lit: 3.3.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) transitivePeerDependencies: @@ -16121,14 +16292,14 @@ snapshots: dependencies: buffer: 6.0.3 - '@reown/appkit-react-native@2.0.1(htg2tpf3zzmsrhrwiskzh3ey3i)': + '@reown/appkit-react-native@2.0.1(x6p2ghfntjx42rethspyovjvr4)': dependencies: '@reown/appkit-common-react-native': 2.0.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) '@reown/appkit-core-react-native': 2.0.1(@types/react@19.2.2)(@walletconnect/react-native-compat@2.23.0(lh5jzsrjqwxruiai4runjz3fou))(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) '@reown/appkit-ui-react-native': 2.0.1(react-native-svg@15.14.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1))(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) '@walletconnect/react-native-compat': 2.23.0(lh5jzsrjqwxruiai4runjz3fou) - '@walletconnect/universal-provider': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@3.25.76) + '@walletconnect/universal-provider': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@4.4.3) react: 19.1.1 react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) react-native-safe-area-context: 5.6.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) @@ -16161,12 +16332,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-scaffold-ui@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3)': + '@reown/appkit-scaffold-ui@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-ui': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-utils': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) + '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.1.0 transitivePeerDependencies: @@ -16198,12 +16369,12 @@ snapshots: - valtio - zod - '@reown/appkit-scaffold-ui@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3)': + '@reown/appkit-scaffold-ui@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 transitivePeerDependencies: @@ -16235,12 +16406,12 @@ snapshots: - valtio - zod - '@reown/appkit-scaffold-ui@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': + '@reown/appkit-scaffold-ui@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 transitivePeerDependencies: @@ -16272,12 +16443,12 @@ snapshots: - valtio - zod - '@reown/appkit-scaffold-ui@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 transitivePeerDependencies: @@ -16335,10 +16506,10 @@ snapshots: react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) react-native-svg: 15.14.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) - '@reown/appkit-ui@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit-ui@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.1.0 qrcode: 1.5.3 @@ -16370,10 +16541,10 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit-ui@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 qrcode: 1.5.3 @@ -16405,10 +16576,10 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-ui@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 qrcode: 1.5.3 @@ -16440,10 +16611,10 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-ui@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 qrcode: 1.5.3 @@ -16475,16 +16646,16 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3)': + '@reown/appkit-utils@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-polyfills': 1.7.2 '@reown/appkit-wallet': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16513,16 +16684,16 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3)': + '@reown/appkit-utils@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.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.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16551,16 +16722,16 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': + '@reown/appkit-utils@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@reown/appkit-polyfills': 1.7.8 '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16589,14 +16760,14 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': + '@reown/appkit-utils@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.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.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: @@ -16627,17 +16798,17 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-wagmi-react-native@2.0.1(gbsuv35t73ppduqv7v3dwovljy)': + '@reown/appkit-wagmi-react-native@2.0.1(shpadx773iilzq7h2tdwz2t7he)': dependencies: '@react-native-community/netinfo': 11.4.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)) '@reown/appkit-common-react-native': 2.0.1(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) - '@reown/appkit-react-native': 2.0.1(htg2tpf3zzmsrhrwiskzh3ey3i) + '@reown/appkit-react-native': 2.0.1(x6p2ghfntjx42rethspyovjvr4) '@walletconnect/react-native-compat': 2.23.0(lh5jzsrjqwxruiai4runjz3fou) react: 19.1.1 react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) react-native-get-random-values: 2.0.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + wagmi: 2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16690,20 +16861,20 @@ snapshots: - typescript - utf-8-validate - '@reown/appkit@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit@1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-polyfills': 1.7.2 - '@reown/appkit-scaffold-ui': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) - '@reown/appkit-ui': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-utils': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) + '@reown/appkit-scaffold-ui': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-ui': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/types': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/universal-provider': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16732,21 +16903,21 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@reown/appkit@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-pay': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) + '@reown/appkit-scaffold-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16775,21 +16946,21 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-pay': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-scaffold-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) + '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@4.4.3) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) bs58: 6.0.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -16818,18 +16989,18 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@2.1.8(@types/react@19.2.2)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/universal-provider': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 valtio: 2.1.8(@types/react@19.2.2)(react@19.1.1) viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -17121,26 +17292,26 @@ snapshots: - react-native - typescript - '@solana-program/compute-budget@0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/compute-budget@0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/stake@0.2.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/stake@0.2.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/system@0.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/system@0.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token-2022@0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))': + '@solana-program/token-2022@0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))': dependencies: - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/sysvars': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana-program/token@0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/token@0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/accounts@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': dependencies: @@ -17322,7 +17493,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -17335,11 +17506,11 @@ snapshots: '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/rpc-parsed-types': 2.3.0(typescript@5.8.3) '@solana/rpc-spec-types': 2.3.0(typescript@5.8.3) - '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/signers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/sysvars': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) typescript: 5.8.3 @@ -17429,14 +17600,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.3.0(typescript@5.8.3) '@solana/functional': 2.3.0(typescript@5.8.3) '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.3) '@solana/subscribable': 2.3.0(typescript@5.8.3) typescript: 5.8.3 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@solana/rpc-subscriptions-spec@2.3.0(typescript@5.8.3)': dependencies: @@ -17446,7 +17617,7 @@ snapshots: '@solana/subscribable': 2.3.0(typescript@5.8.3) typescript: 5.8.3 - '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.3.0(typescript@5.8.3) '@solana/fast-stable-stringify': 2.3.0(typescript@5.8.3) @@ -17454,7 +17625,7 @@ snapshots: '@solana/promises': 2.3.0(typescript@5.8.3) '@solana/rpc-spec-types': 2.3.0(typescript@5.8.3) '@solana/rpc-subscriptions-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.3) '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -17632,7 +17803,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -17640,7 +17811,7 @@ snapshots: '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/promises': 2.3.0(typescript@5.8.3) '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -17923,11 +18094,11 @@ snapshots: - typescript - utf-8-validate - '@solana/wallet-adapter-trezor@0.1.6(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/wallet-adapter-trezor@0.1.6(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/wallet-adapter-base': 0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@trezor/connect-web': 9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/connect-web': 9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) buffer: 6.0.3 transitivePeerDependencies: - '@solana/sysvars' @@ -17957,11 +18128,11 @@ snapshots: '@solana/wallet-standard-util': 1.1.2 '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-walletconnect@0.1.21(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@solana/wallet-adapter-walletconnect@0.1.21(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@solana/wallet-adapter-base': 0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/solana-adapter': 0.0.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/wallet-adapter-base@0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/solana-adapter': 0.0.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/wallet-adapter-base@0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -17990,7 +18161,7 @@ snapshots: - utf-8-validate - zod - '@solana/wallet-adapter-wallets@0.19.37(wcwzcvkiean7xoqtynzwkhqyla)': + '@solana/wallet-adapter-wallets@0.19.37(k66plh6iifxyw5d3zjvlhcznga)': dependencies: '@solana/wallet-adapter-alpha': 0.1.14(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-avana': 0.1.17(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) @@ -18023,10 +18194,10 @@ snapshots: '@solana/wallet-adapter-tokenary': 0.1.16(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-tokenpocket': 0.4.23(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-torus': 0.11.32(@babel/runtime@7.28.4)(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-trezor': 0.1.6(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-trezor': 0.1.6(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-trust': 0.1.17(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-unsafe-burner': 0.1.11(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) - '@solana/wallet-adapter-walletconnect': 0.1.21(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@solana/wallet-adapter-walletconnect': 0.1.21(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@solana/wallet-adapter-xdefi': 0.1.11(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -18513,13 +18684,13 @@ snapshots: - react-native - utf-8-validate - '@trezor/blockchain-link@2.5.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@trezor/blockchain-link@2.5.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/stake': 0.2.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)) - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/stake': 0.2.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@stellar/stellar-sdk': 13.3.0 '@trezor/blockchain-link-types': 1.4.4(tslib@2.8.1) @@ -18567,9 +18738,9 @@ snapshots: - expo-localization - react-native - '@trezor/connect-web@9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@trezor/connect-web@9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@trezor/connect': 9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/connect': 9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@trezor/connect-common': 0.4.4(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1) '@trezor/utils': 9.4.4(tslib@2.8.1) '@trezor/websocket-client': 1.2.4(bufferutil@4.0.9)(tslib@2.8.1)(utf-8-validate@5.0.10) @@ -18588,7 +18759,7 @@ snapshots: - utf-8-validate - ws - '@trezor/connect@9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@trezor/connect@9.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@ethereumjs/common': 10.0.0 '@ethereumjs/tx': 10.0.0 @@ -18596,12 +18767,12 @@ snapshots: '@mobily/ts-belt': 3.13.1 '@noble/hashes': 1.8.0 '@scure/bip39': 1.6.0 - '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/system': 0.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)) - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@trezor/blockchain-link': 2.5.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/system': 0.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)) + '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@trezor/blockchain-link': 2.5.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@trezor/blockchain-link-types': 1.4.4(tslib@2.8.1) '@trezor/blockchain-link-utils': 1.4.4(bufferutil@4.0.9)(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1)(utf-8-validate@5.0.10) '@trezor/connect-analytics': 1.3.6(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(tslib@2.8.1) @@ -18754,7 +18925,7 @@ snapshots: '@turnkey/api-key-stamper': 0.4.7 '@turnkey/encoding': 0.5.0 - '@turnkey/sdk-browser@5.8.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@turnkey/sdk-browser@5.8.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@turnkey/api-key-stamper': 0.4.7 '@turnkey/crypto': 2.5.0 @@ -18763,7 +18934,7 @@ snapshots: '@turnkey/iframe-stamper': 2.5.0 '@turnkey/indexed-db-stamper': 1.1.1 '@turnkey/sdk-types': 0.3.0 - '@turnkey/wallet-stamper': 1.0.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@turnkey/wallet-stamper': 1.0.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@turnkey/webauthn-stamper': 0.5.1 bs58check: 4.0.0 buffer: 6.0.3 @@ -18776,11 +18947,11 @@ snapshots: - utf-8-validate - zod - '@turnkey/sdk-server@4.7.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@turnkey/sdk-server@4.7.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@turnkey/api-key-stamper': 0.4.7 '@turnkey/http': 3.10.0(encoding@0.1.13) - '@turnkey/wallet-stamper': 1.0.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@turnkey/wallet-stamper': 1.0.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) buffer: 6.0.3 cross-fetch: 3.2.0(encoding@0.1.13) transitivePeerDependencies: @@ -18792,12 +18963,12 @@ snapshots: '@turnkey/sdk-types@0.3.0': {} - '@turnkey/solana@1.0.42(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@turnkey/solana@1.0.42(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) '@turnkey/http': 3.10.0(encoding@0.1.13) - '@turnkey/sdk-browser': 5.8.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@turnkey/sdk-server': 4.7.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@turnkey/sdk-browser': 5.8.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@turnkey/sdk-server': 4.7.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - encoding @@ -18805,16 +18976,16 @@ snapshots: - utf-8-validate - zod - '@turnkey/viem@0.13.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3)': + '@turnkey/viem@0.13.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@noble/curves': 1.8.0 '@openzeppelin/contracts': 4.9.6 '@turnkey/api-key-stamper': 0.4.7 '@turnkey/http': 3.10.0(encoding@0.1.13) - '@turnkey/sdk-browser': 5.8.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@turnkey/sdk-server': 4.7.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@turnkey/sdk-browser': 5.8.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@turnkey/sdk-server': 4.7.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) cross-fetch: 4.1.0(encoding@0.1.13) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - encoding @@ -18822,12 +18993,12 @@ snapshots: - utf-8-validate - zod - '@turnkey/wallet-stamper@1.0.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@turnkey/wallet-stamper@1.0.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@turnkey/crypto': 2.5.0 '@turnkey/encoding': 0.5.0 optionalDependencies: - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - typescript @@ -19067,7 +19238,7 @@ snapshots: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eslint: 8.57.1 typescript: 5.8.3 transitivePeerDependencies: @@ -19079,7 +19250,7 @@ snapshots: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eslint: 9.38.0(jiti@2.7.0) typescript: 5.8.3 transitivePeerDependencies: @@ -19089,7 +19260,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.8.3) '@typescript-eslint/types': 8.46.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -19108,7 +19279,7 @@ snapshots: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) '@typescript-eslint/utils': 8.46.2(eslint@8.57.1)(typescript@5.8.3) - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eslint: 8.57.1 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 @@ -19120,7 +19291,7 @@ snapshots: '@typescript-eslint/types': 8.46.2 '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) '@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@2.7.0))(typescript@5.8.3) - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eslint: 9.38.0(jiti@2.7.0) ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 @@ -19135,7 +19306,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.8.3) '@typescript-eslint/types': 8.46.2 '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -19323,7 +19494,7 @@ snapshots: '@vue/shared@3.5.22': {} - '@wagmi/connectors@6.1.0(2orsghzlwewxwohejkwolumw4e)': + '@wagmi/connectors@6.1.0(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76)': dependencies: '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) @@ -19332,9 +19503,9 @@ snapshots: '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(6oek35uj62dxa7liwvqvv47ara) + porto: 0.2.19(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)) viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.8.3 @@ -19370,19 +19541,19 @@ snapshots: - wagmi - zod - '@wagmi/connectors@6.1.0(bgpzjh5q7yrj4ocuf4x4nrqhlm)': + '@wagmi/connectors@6.1.0(qnfautsezg4qphd44hbshkqvfi)': dependencies: - '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.2.0(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@4.4.3) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@4.4.3) + '@gemini-wallet/core': 0.2.0(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@walletconnect/ethereum-provider': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(gvhepirkfl6ucqngccm4za6i6m) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + porto: 0.2.19(wbrvrvfq6sbyt2murnqn7zt4wm) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -19417,19 +19588,19 @@ snapshots: - wagmi - zod - '@wagmi/connectors@6.1.0(g3hyk7kpi5chrxeuitid5ge5f4)': + '@wagmi/connectors@6.1.0(rxz3hjijsrpdsnyjdo2xg6taam)': dependencies: - '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@4.4.3) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@4.4.3) - '@gemini-wallet/core': 0.2.0(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@gemini-wallet/core': 0.2.0(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) - '@walletconnect/ethereum-provider': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@walletconnect/ethereum-provider': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(dryu7ql2ha2chpe6amo3r4teni) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + porto: 0.2.19(3zx2pflwoncd6cecqkkxj4knxy) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -19494,6 +19665,21 @@ snapshots: - react - use-sync-external-store + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.8.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.0(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.6.0(react@19.1.1)) + optionalDependencies: + '@tanstack/query-core': 5.90.5 + typescript: 5.8.3 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + '@wallet-standard/app@1.0.1': dependencies: '@wallet-standard/base': 1.0.1 @@ -19543,7 +19729,7 @@ snapshots: dependencies: '@wallet-standard/base': 1.1.0 - '@walletconnect/core@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/core@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -19557,7 +19743,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 events: 3.3.0 lodash.isequal: 4.5.0 @@ -19587,7 +19773,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/core@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -19601,7 +19787,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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 @@ -19631,7 +19817,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/core@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -19645,7 +19831,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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 @@ -19675,21 +19861,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': 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.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -19719,21 +19905,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.8.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.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.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 @@ -19763,7 +19949,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/core@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -19777,7 +19963,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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 @@ -19807,21 +19993,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': 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.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -19851,21 +20037,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.8.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.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.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 @@ -19895,7 +20081,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -19909,7 +20095,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@3.25.76) + '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@4.4.3) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.39.3 events: 3.3.0 @@ -19939,7 +20125,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/core@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -19953,7 +20139,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.39.3 events: 3.3.0 @@ -19987,18 +20173,18 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/ethereum-provider@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/universal-provider': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20028,18 +20214,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/ethereum-provider@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/ethereum-provider@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/universal-provider': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/universal-provider': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20069,18 +20255,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/ethereum-provider@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/universal-provider': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20110,18 +20296,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/ethereum-provider@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/ethereum-provider@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit': 1.7.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/universal-provider': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20283,16 +20469,16 @@ snapshots: dependencies: tslib: 1.14.1 - '@walletconnect/sign-client@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/sign-client@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/core': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20319,16 +20505,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/sign-client@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/core': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20355,16 +20541,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/sign-client@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/core': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20391,16 +20577,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@walletconnect/core': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20427,16 +20613,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.8.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20463,16 +20649,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/sign-client@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/core': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20499,16 +20685,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@walletconnect/core': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20535,16 +20721,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20571,16 +20757,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: - '@walletconnect/core': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@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.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@3.25.76) + '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@4.4.3) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20607,16 +20793,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/sign-client@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/core': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.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.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20643,13 +20829,13 @@ snapshots: - utf-8-validate - zod - '@walletconnect/solana-adapter@0.0.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/wallet-adapter-base@0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/solana-adapter@0.0.8(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@solana/wallet-adapter-base@0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@reown/appkit': 1.7.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@solana/wallet-adapter-base': 0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) - '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/universal-provider': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -20741,7 +20927,7 @@ snapshots: - ioredis - uploadthing - '@walletconnect/types@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))': + '@walletconnect/types@2.21.0': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 @@ -20828,7 +21014,7 @@ snapshots: - ioredis - uploadthing - '@walletconnect/types@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))': + '@walletconnect/types@2.21.1': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 @@ -20973,7 +21159,7 @@ snapshots: - ioredis - uploadthing - '@walletconnect/universal-provider@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/universal-provider@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -20982,9 +21168,9 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 lodash: 4.17.21 transitivePeerDependencies: @@ -21013,7 +21199,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/universal-provider@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -21022,9 +21208,9 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21053,7 +21239,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/universal-provider@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -21062,9 +21248,9 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21093,18 +21279,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21133,18 +21319,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21173,7 +21359,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/universal-provider@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -21182,9 +21368,9 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21213,18 +21399,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21253,18 +21439,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -21293,7 +21479,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -21302,9 +21488,9 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) '@walletconnect/types': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@3.25.76) + '@walletconnect/utils': 2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@4.4.3) es-toolkit: 1.39.3 events: 3.3.0 transitivePeerDependencies: @@ -21333,7 +21519,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/universal-provider@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(encoding@0.1.13)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) @@ -21342,9 +21528,9 @@ snapshots: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/sign-client': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) - '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + '@walletconnect/utils': 2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.39.3 events: 3.3.0 transitivePeerDependencies: @@ -21373,7 +21559,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/utils@2.19.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 @@ -21391,7 +21577,7 @@ snapshots: elliptic: 6.6.1 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21417,7 +21603,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/utils@2.19.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 @@ -21436,7 +21622,7 @@ snapshots: elliptic: 6.6.1 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21462,7 +21648,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/utils@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 @@ -21480,7 +21666,7 @@ snapshots: detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21506,25 +21692,25 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': 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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) + '@walletconnect/types': 2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21550,18 +21736,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.0(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.8.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/types': 2.21.0 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 @@ -21594,7 +21780,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/utils@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 @@ -21612,7 +21798,7 @@ snapshots: detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21638,25 +21824,25 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': 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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))) + '@walletconnect/types': 2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -21682,18 +21868,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.8.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/keyvaluestorage': 1.1.1(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.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(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1) + '@walletconnect/types': 2.21.1 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 @@ -21726,7 +21912,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@3.25.76)': + '@walletconnect/utils@2.21.10(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(ioredis@5.11.1)(typescript@5.8.3)(zod@4.4.3)': dependencies: '@msgpack/msgpack': 3.1.2 '@noble/ciphers': 1.3.0 @@ -21745,7 +21931,7 @@ snapshots: blakejs: 1.2.1 bs58: 6.0.0 detect-browser: 5.3.0 - ox: 0.9.3(typescript@5.8.3)(zod@3.25.76) + ox: 0.9.3(typescript@5.8.3)(zod@4.4.3) uint8arrays: 3.1.1 transitivePeerDependencies: - '@azure/app-configuration' @@ -21770,7 +21956,7 @@ snapshots: - uploadthing - zod - '@walletconnect/utils@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)': + '@walletconnect/utils@2.21.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.9)(ioredis@5.11.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@msgpack/msgpack': 3.1.2 '@noble/ciphers': 1.3.0 @@ -21791,7 +21977,7 @@ snapshots: detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: 3.1.1 - viem: 2.31.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.31.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23597,7 +23783,7 @@ snapshots: eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) eslint: 9.38.0(jiti@2.7.0) get-tsconfig: 4.12.0 is-bun-module: 2.0.0 @@ -23789,7 +23975,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -23836,7 +24022,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -24217,7 +24403,7 @@ snapshots: follow-redirects@1.15.11(debug@4.4.3): optionalDependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) for-each@0.3.5: dependencies: @@ -24486,7 +24672,7 @@ snapshots: adm-zip: 0.4.16 chalk: 5.6.2 chokidar: 4.0.3 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) enquirer: 2.4.1 ethereum-cryptography: 2.2.1 micro-eth-signer: 0.14.0 @@ -24598,7 +24784,7 @@ snapshots: http-call@5.3.0: dependencies: content-type: 1.0.5 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) is-retry-allowed: 1.2.0 is-stream: 2.0.1 parse-json: 4.0.0 @@ -24621,7 +24807,7 @@ snapshots: https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -24719,7 +24905,7 @@ snapshots: dependencies: '@ioredis/commands': 1.10.0 cluster-key-slot: 1.1.1 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) denque: 2.1.0 redis-errors: 1.2.0 redis-parser: 3.0.0 @@ -24984,7 +25170,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -25877,7 +26063,7 @@ snapshots: metro-file-map@0.83.3: dependencies: - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -25973,7 +26159,7 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -26491,7 +26677,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.7.1(typescript@5.8.3)(zod@4.4.3): + ox@0.7.1(typescript@5.8.3)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -26499,7 +26685,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.1(typescript@5.8.3)(zod@4.4.3) + abitype: 1.1.1(typescript@5.8.3)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.8.3 @@ -26521,7 +26707,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.9.3(typescript@5.8.3)(zod@3.25.76): + ox@0.9.3(typescript@5.8.3)(zod@4.4.3): dependencies: '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 @@ -26529,7 +26715,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.1(typescript@5.8.3)(zod@3.25.76) + abitype: 1.1.1(typescript@5.8.3)(zod@4.4.3) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.8.3 @@ -26793,9 +26979,9 @@ snapshots: pony-cause@2.1.11: {} - porto@0.2.19(6oek35uj62dxa7liwvqvv47ara): + porto@0.2.19(3zx2pflwoncd6cecqkkxj4knxy): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.6.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) hono: 4.10.3 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.8.3) @@ -26807,47 +26993,47 @@ snapshots: '@tanstack/react-query': 5.90.5(react@19.1.1) react: 19.1.1 typescript: 5.8.3 - wagmi: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + wagmi: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) transitivePeerDependencies: - '@types/react' - immer - use-sync-external-store - porto@0.2.19(dryu7ql2ha2chpe6amo3r4teni): + porto@0.2.19(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) hono: 4.10.3 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.8.3) ox: 0.9.12(typescript@5.8.3)(zod@4.4.3) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 4.4.3 zustand: 5.0.8(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) optionalDependencies: '@tanstack/react-query': 5.90.5(react@19.1.1) react: 19.1.1 typescript: 5.8.3 - wagmi: 2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) + wagmi: 2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) transitivePeerDependencies: - '@types/react' - immer - use-sync-external-store - porto@0.2.19(gvhepirkfl6ucqngccm4za6i6m): + porto@0.2.19(wbrvrvfq6sbyt2murnqn7zt4wm): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) hono: 4.10.3 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.8.3) ox: 0.9.12(typescript@5.8.3)(zod@4.4.3) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) zod: 4.4.3 zustand: 5.0.8(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) optionalDependencies: '@tanstack/react-query': 5.90.5(react@19.1.1) react: 19.1.1 typescript: 5.8.3 - wagmi: 2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + wagmi: 2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3) transitivePeerDependencies: - '@types/react' - immer @@ -27141,6 +27327,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 + react-freeze@1.0.4(react@19.1.1): + dependencies: + react: 19.1.1 + react-i18next@13.5.0(i18next@23.4.6)(react-dom@19.1.1(react@19.1.1))(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1): dependencies: '@babel/runtime': 7.28.4 @@ -27197,6 +27387,13 @@ snapshots: react: 19.1.1 react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + react-native-screens@4.26.2(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1): + dependencies: + react: 19.1.1 + react-freeze: 1.0.4(react@19.1.1) + react-native: 0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + warn-once: 0.1.1 + react-native-svg@15.14.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1): dependencies: css-select: 5.2.2 @@ -27663,6 +27860,8 @@ snapshots: setprototypeof@1.2.0: {} + sf-symbols-typescript@2.2.0: {} + sha.js@2.4.12: dependencies: inherits: 2.0.4 @@ -27812,7 +28011,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@8.1.1) + debug: 4.4.3(supports-color@5.5.0) socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -27877,6 +28076,10 @@ snapshots: standard-as-callback@2.1.0: {} + standard-navigation@0.0.8(react@19.1.1): + dependencies: + react: 19.1.1 + statuses@1.5.0: {} statuses@2.0.1: {} @@ -28460,6 +28663,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 + use-latest-callback@0.2.6(react@19.1.1): + dependencies: + react: 19.1.1 + use-sidecar@1.1.3(@types/react@19.2.2)(react@19.1.1): dependencies: detect-node-es: 1.1.0 @@ -28472,6 +28679,10 @@ snapshots: dependencies: react: 19.1.1 + use-sync-external-store@1.6.0(react@19.1.1): + dependencies: + react: 19.1.1 + utf-8-validate@5.0.10: dependencies: node-gyp-build: 4.8.4 @@ -28560,15 +28771,15 @@ snapshots: - utf-8-validate - zod - viem@2.29.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3): + viem@2.29.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76): dependencies: '@noble/curves': 1.8.2 '@noble/hashes': 1.7.2 '@scure/bip32': 1.6.2 '@scure/bip39': 1.5.4 - abitype: 1.0.8(typescript@5.8.3)(zod@4.4.3) + abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) isows: 1.0.6(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.6.9(typescript@5.8.3)(zod@4.4.3) + ox: 0.6.9(typescript@5.8.3)(zod@3.25.76) ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.8.3 @@ -28577,15 +28788,15 @@ snapshots: - utf-8-validate - zod - viem@2.31.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3): + viem@2.31.0(bufferutil@4.0.9)(typescript@5.8.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.0.8(typescript@5.8.3)(zod@4.4.3) + abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) isows: 1.0.7(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.7.1(typescript@5.8.3)(zod@4.4.3) + ox: 0.7.1(typescript@5.8.3)(zod@3.25.76) ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.8.3 @@ -28739,14 +28950,14 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - wagmi@2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3): + wagmi@2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): dependencies: '@tanstack/react-query': 5.90.5(react@19.1.1) - '@wagmi/connectors': 6.1.0(g3hyk7kpi5chrxeuitid5ge5f4) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) + '@wagmi/connectors': 6.1.0(rxz3hjijsrpdsnyjdo2xg6taam) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -28778,14 +28989,14 @@ snapshots: - utf-8-validate - zod - wagmi@2.18.2(@react-native-async-storage/async-storage@1.24.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): + wagmi@2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3))(zod@4.4.3): dependencies: '@tanstack/react-query': 5.90.5(react@19.1.1) - '@wagmi/connectors': 6.1.0(2orsghzlwewxwohejkwolumw4e) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/connectors': 6.1.0(qnfautsezg4qphd44hbshkqvfi) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3)) react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) - viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.4.3) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -28817,10 +29028,10 @@ snapshots: - utf-8-validate - zod - wagmi@2.18.2(@react-native-async-storage/async-storage@2.2.0(react-native@0.82.0(@babel/core@7.28.5)(@react-native-community/cli@20.0.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(@react-native/metro-config@0.82.0(@babel/core@7.28.5)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(ioredis@5.11.1)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): + wagmi@2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): dependencies: '@tanstack/react-query': 5.90.5(react@19.1.1) - '@wagmi/connectors': 6.1.0(bgpzjh5q7yrj4ocuf4x4nrqhlm) + '@wagmi/connectors': 6.1.0(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.18.2(@tanstack/query-core@5.90.5)(@tanstack/react-query@5.90.5(react@19.1.1))(@types/react@19.2.2)(bufferutil@4.0.9)(encoding@0.1.13)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76) '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.5)(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.38.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) @@ -29211,6 +29422,13 @@ snapshots: react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) + zustand@5.0.0(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.6.0(react@19.1.1)): + optionalDependencies: + '@types/react': 19.2.2 + immer: 10.0.2 + react: 19.1.1 + use-sync-external-store: 1.6.0(react@19.1.1) + zustand@5.0.3(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)): optionalDependencies: '@types/react': 19.2.2 @@ -29218,6 +29436,13 @@ snapshots: react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) + zustand@5.0.3(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.6.0(react@19.1.1)): + optionalDependencies: + '@types/react': 19.2.2 + immer: 10.0.2 + react: 19.1.1 + use-sync-external-store: 1.6.0(react@19.1.1) + zustand@5.0.8(@types/react@19.2.2)(immer@10.0.2)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)): optionalDependencies: '@types/react': 19.2.2 From ee7f9b45dc7a8bd2cd5938238e93f834810b8664 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 16:49:33 -0400 Subject: [PATCH 08/99] feat(mobile): mount the navigator behind a connect gate --- mobile/App.tsx | 57 ++-- mobile/__tests__/App.test.tsx | 5 +- mobile/__tests__/navigation.test.tsx | 50 +++- mobile/__tests__/toast.test.tsx | 6 + mobile/src/AppContent.tsx | 356 ------------------------ mobile/src/components/AppHeader.tsx | 56 ++++ mobile/src/components/ui/toast.tsx | 16 +- mobile/src/navigation/RootNavigator.tsx | 140 ++++++---- mobile/src/screens/GalleryScreen.tsx | 137 +++++++++ mobile/src/screens/LandingScreen.tsx | 143 ++++++++++ 10 files changed, 523 insertions(+), 443 deletions(-) delete mode 100644 mobile/src/AppContent.tsx create mode 100644 mobile/src/components/AppHeader.tsx create mode 100644 mobile/src/screens/GalleryScreen.tsx create mode 100644 mobile/src/screens/LandingScreen.tsx diff --git a/mobile/App.tsx b/mobile/App.tsx index 273cb7bb..2f0a8ef0 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -1,35 +1,54 @@ import React from 'react'; import "@walletconnect/react-native-compat"; -import { AppKitProvider } from '@reown/appkit-react-native'; +import { StatusBar } from 'react-native'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; +import { NavigationContainer } from '@react-navigation/native'; +import { AppKit, AppKitProvider } from '@reown/appkit-react-native'; import { WagmiProvider } from 'wagmi'; import { QueryClientProvider } from '@tanstack/react-query'; import { queryClient, ApiClientProvider, AuthProvider, PetsConfigProvider } from '@shared/core'; import { appKit, wagmiConfig } from './src/AppKitConfig'; -import AppRoot from './src/AppContent.tsx'; import { API_URL } from './config'; import { petsContractParams } from './src/petsContractParams'; import { ToastProvider } from './src/components/ui/toast'; +import { RootNavigator } from './src/navigation/RootNavigator'; +import { neon } from './src/theme/neon'; import { SolanaAppKitAnchorBridge } from './src/solana/SolanaAppKitAnchorBridge'; +/** + * Provider order matches `frontend/src/AppProviders.tsx`, with `NavigationContainer` + * where its `BrowserRouter` sits. + * + * `SafeAreaProvider` is outermost so `ToastProvider` can measure a real bottom + * inset; it used to live inside the old `AppContent`, which put it below the toast + * viewport. `AppKit` renders as a sibling of the navigator so its connect sheet is + * reachable from the landing screen and the tab shell alike. + */ export default function App() { return ( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + ); } diff --git a/mobile/__tests__/App.test.tsx b/mobile/__tests__/App.test.tsx index f8d91124..eae5e68c 100644 --- a/mobile/__tests__/App.test.tsx +++ b/mobile/__tests__/App.test.tsx @@ -13,7 +13,7 @@ import ReactTestRenderer from 'react-test-renderer'; const passthrough = ({children}: {children?: React.ReactNode}) => <>{children}; -jest.mock('@reown/appkit-react-native', () => ({AppKitProvider: passthrough})); +jest.mock('@reown/appkit-react-native', () => ({AppKitProvider: passthrough, AppKit: () => null})); jest.mock('wagmi', () => ({WagmiProvider: passthrough})); jest.mock('@tanstack/react-query', () => ({QueryClientProvider: passthrough})); jest.mock('@shared/core', () => ({ @@ -26,7 +26,8 @@ jest.mock('../src/AppKitConfig', () => ({appKit: {}, wagmiConfig: {}})); jest.mock('../src/solana/SolanaAppKitAnchorBridge', () => ({ SolanaAppKitAnchorBridge: passthrough, })); -jest.mock('../src/AppContent.tsx', () => () => null); +jest.mock('@react-navigation/native', () => ({NavigationContainer: passthrough})); +jest.mock('../src/navigation/RootNavigator', () => ({RootNavigator: () => null})); // Reaches AsyncStorage (a native module) at import time, just to read API_URL. jest.mock('../config', () => ({API_URL: 'http://localhost:3001'})); diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index 518f3163..b336ec0c 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -9,6 +9,19 @@ import { Text } from 'react-native'; import ReactTestRenderer from 'react-test-renderer'; import { NavigationContainer } from '@react-navigation/native'; +const mockIsConnected = jest.fn(() => true); +jest.mock('wagmi', () => ({ useAccount: () => ({ isConnected: mockIsConnected() }) })); + +// The screens behind the gate are the app's real ones; each pulls in the chain +// adapter and the API client, which is not what a navigator smoke test is for. +jest.mock('../src/screens/GalleryScreen', () => () => null); +jest.mock('../src/components/AppHeader', () => () => null); +jest.mock('../src/screens/LandingScreen', () => { + const { Text: RNText } = jest.requireActual('react-native'); + const React_ = jest.requireActual('react'); + return () => React_.createElement(RNText, null, 'Connect your wallet'); +}); + import { RootNavigator } from '../src/navigation/RootNavigator'; import { STACK_TITLES, TAB_ITEMS } from '../src/navigation/routes'; @@ -24,6 +37,10 @@ const render = async () => { return tree; }; +beforeEach(() => { + mockIsConnected.mockReturnValue(true); +}); + const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => tree.root .findAllByType(Text) @@ -77,21 +94,40 @@ describe('RootNavigator', () => { }); }); - it('exposes every route to navigation', async () => { - let container!: ReactTestRenderer.ReactTestRenderer; + const routeNames = async (connected: boolean) => { + mockIsConnected.mockReturnValue(connected); const ref = React.createRef>(); await ReactTestRenderer.act(() => { - container = ReactTestRenderer.create( + ReactTestRenderer.create( , ); }); + return ref.current?.getRootState().routeNames ?? []; + }; - const names = ref.current?.getRootState().routeNames ?? []; - expect(names).toEqual( - expect.arrayContaining(['Landing', 'Main', 'Marriage', 'Rename', 'Defense']), + it('exposes every in-app route once connected', async () => { + expect(await routeNames(true)).toEqual( + expect.arrayContaining(['Main', 'Marriage', 'Rename', 'Defense']), ); - expect(container).toBeTruthy(); + }); + + it('shows only Landing while disconnected', async () => { + // Registered conditionally, not redirected to: with Main absent there is no + // window where a tab screen renders against a disconnected wallet. + expect(await routeNames(false)).toEqual(['Landing']); + }); + + it('leaves no back route into Landing once connected', async () => { + // The point of the conditional split: reconnecting must not leave a stale + // Landing entry on the stack for the back gesture to return to. + expect(await routeNames(true)).not.toContain('Landing'); + }); + + it('renders the landing screen while disconnected', async () => { + mockIsConnected.mockReturnValue(false); + const tree = await render(); + expect(textOf(tree)).toContain('Connect your wallet'); }); }); diff --git a/mobile/__tests__/toast.test.tsx b/mobile/__tests__/toast.test.tsx index 9e90ef98..6f077da3 100644 --- a/mobile/__tests__/toast.test.tsx +++ b/mobile/__tests__/toast.test.tsx @@ -10,6 +10,12 @@ import React from 'react'; import { Text } from 'react-native'; import ReactTestRenderer from 'react-test-renderer'; +// The viewport measures a bottom inset, which needs a SafeAreaProvider and a real +// frame. Neither is what these tests are about. +jest.mock('react-native-safe-area-context', () => ({ + useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 }), +})); + const mockUsePetError = jest.fn(); const mockUseTxError = jest.fn(); jest.mock('@shared/core', () => ({ diff --git a/mobile/src/AppContent.tsx b/mobile/src/AppContent.tsx deleted file mode 100644 index 9308ca88..00000000 --- a/mobile/src/AppContent.tsx +++ /dev/null @@ -1,356 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import { - ActivityIndicator, - StatusBar, - StyleSheet, - ScrollView, - View, - Text, - TouchableOpacity, -} from 'react-native'; -import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'; -import { AppKit } from '@reown/appkit-react-native'; -import { useAuth, useCreatePet, usePetList } from '@shared/core'; -import { useAccount } from 'wagmi'; -import ConnectButton from './components/ConnectButton'; -import EthereumNetworkSwitcher from './components/EthereumNetworkSwitcher'; -import CreatePetModal from './components/CreatePetModal'; -import PetList from './components/PetList'; -import { neon, neonGlow } from './theme/neon'; - -function AppRoot() { - return ( - - - - - ); -} - -function AppContent() { - const { isAuthenticated } = useAuth(); - const { isConnected } = useAccount(); - const pets = usePetList(); - const [refreshing, setRefreshing] = useState(false); - const [createModalVisible, setCreateModalVisible] = useState(false); - const insets = useSafeAreaInsets(); - - const closeCreateModal = useCallback(() => { - setCreateModalVisible(false); - }, []); - - // EVM minting is two-phase (requestMintStarter, then settleMint once Pyth - // Entropy reveals), so the list is only worth re-reading once onSuccess fires. - const createPet = useCreatePet({ - onSuccess: () => { - closeCreateModal(); - pets.refetch(); - }, - }); - - const handleRefreshPets = useCallback(async () => { - setRefreshing(true); - try { - await pets.refetch(); - } finally { - setRefreshing(false); - } - }, [pets]); - - return ( - - {/* Header */} - - Do Not Stop - {(isAuthenticated || isConnected) && ( - - - {isConnected ? : null} - - - - )} - - - {/* Main: avoid nesting ScrollView with PetList’s own scroll + pull-to-refresh */} - {isAuthenticated || isConnected ? ( - isConnected ? ( - - Welcome back! - - setCreateModalVisible(true)} - activeOpacity={0.85} - > - Create - - - {refreshing ? ( - - ) : ( - Refresh - )} - - - - - - ) : ( - - Welcome back! - Connect a wallet to load your on-chain pets. - - ) - ) : ( - - - ON-CHAIN COLLECTION - Do Not Stop - - - Connect your wallet to mint, battle, and breed — same universe as the web app, in your - pocket. - - - - Create pets - Mint unique companions on-chain. - - - Battles - Prove strength in the arena. - - - Breeding - Combine traits for the next gen. - - - - - - - - )} - - {/* AppKit UI component for wallet connection */} - - - ); -} - -const styles = StyleSheet.create({ - mainContainer: { - flex: 1, - backgroundColor: neon.bgDeep, - }, - header: { - backgroundColor: neon.bgPanel, - borderBottomWidth: 1, - borderBottomColor: neon.border, - paddingHorizontal: 16, - paddingBottom: 16, - ...neonGlow(neon.cyan, 8, 0.2), - }, - headerTitle: { - fontSize: 28, - fontWeight: '800', - textAlign: 'center', - color: neon.text, - letterSpacing: 2, - textShadowColor: neon.cyan, - textShadowOffset: { width: 0, height: 0 }, - textShadowRadius: 12, - }, - walletSection: { - marginTop: 12, - alignItems: 'center', - }, - walletRow: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - flexWrap: 'wrap', - }, - scrollView: { - flex: 1, - }, - scrollContent: { - paddingHorizontal: 16, - paddingTop: 24, - paddingBottom: 32, - }, - welcomeSection: { - alignItems: 'center', - }, - heroKicker: { - fontSize: 11, - fontWeight: '700', - letterSpacing: 4, - color: neon.magenta, - marginBottom: 8, - textShadowColor: neon.magenta, - textShadowOffset: { width: 0, height: 0 }, - textShadowRadius: 8, - }, - heroTitle: { - fontSize: 36, - fontWeight: '900', - color: neon.text, - letterSpacing: 1, - marginBottom: 4, - textShadowColor: neon.cyan, - textShadowOffset: { width: 0, height: 0 }, - textShadowRadius: 16, - }, - heroGlowLine: { - width: 120, - height: 3, - backgroundColor: neon.cyan, - marginBottom: 20, - borderRadius: 2, - opacity: 0.95, - ...neonGlow(neon.cyan, 8, 0.75), - }, - welcomeText: { - fontSize: 16, - color: neon.textMuted, - textAlign: 'center', - marginBottom: 28, - maxWidth: 600, - lineHeight: 24, - }, - features: { - width: '100%', - maxWidth: 900, - }, - feature: { - backgroundColor: neon.bgCard, - borderRadius: 16, - padding: 20, - marginBottom: 16, - borderWidth: 1, - }, - featureCyan: { - borderColor: 'rgba(0, 245, 255, 0.45)', - ...neonGlow(neon.cyan, 12, 0.25), - }, - featureMagenta: { - borderColor: 'rgba(255, 45, 166, 0.45)', - ...neonGlow(neon.magenta, 12, 0.25), - }, - featurePurple: { - borderColor: 'rgba(192, 132, 252, 0.45)', - ...neonGlow(neon.purple, 12, 0.22), - }, - featureTitle: { - fontSize: 18, - fontWeight: '800', - color: neon.text, - letterSpacing: 0.5, - marginBottom: 6, - }, - featureSub: { - fontSize: 14, - color: neon.textDim, - lineHeight: 20, - }, - connectButtonContainer: { - alignItems: 'center', - marginTop: 8, - }, - authenticatedMain: { - flex: 1, - paddingHorizontal: 16, - paddingTop: 24, - paddingBottom: 16, - width: '100%', - }, - walletHint: { - marginTop: 16, - fontSize: 16, - color: neon.textMuted, - textAlign: 'center', - }, - authenticatedText: { - fontSize: 24, - fontWeight: '700', - color: neon.text, - textShadowColor: neon.purple, - textShadowOffset: { width: 0, height: 0 }, - textShadowRadius: 10, - }, - actionsRow: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - marginBottom: 16, - flexWrap: 'wrap', - }, - createBtn: { - backgroundColor: neon.bgCard, - paddingHorizontal: 20, - paddingVertical: 10, - borderRadius: 12, - marginRight: 12, - marginBottom: 4, - minWidth: 100, - alignItems: 'center', - borderWidth: 1, - borderColor: neon.cyan, - ...neonGlow(neon.cyan, 10, 0.4), - }, - createBtnText: { - color: neon.cyan, - fontSize: 16, - fontWeight: '700', - letterSpacing: 0.5, - }, - refreshBtn: { - borderWidth: 1, - borderColor: neon.magenta, - backgroundColor: neon.bgPanel, - paddingHorizontal: 20, - paddingVertical: 10, - borderRadius: 12, - marginBottom: 4, - minWidth: 100, - alignItems: 'center', - justifyContent: 'center', - minHeight: 42, - ...neonGlow(neon.magenta, 8, 0.25), - }, - refreshBtnDisabled: { - opacity: 0.5, - }, - refreshBtnText: { - color: neon.magenta, - fontSize: 16, - fontWeight: '700', - }, -}); - -export default AppRoot; diff --git a/mobile/src/components/AppHeader.tsx b/mobile/src/components/AppHeader.tsx new file mode 100644 index 00000000..407d0dcb --- /dev/null +++ b/mobile/src/components/AppHeader.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { StyleSheet, Text, View } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { useAccount } from 'wagmi'; + +import ConnectButton from './ConnectButton'; +import EthereumNetworkSwitcher from './EthereumNetworkSwitcher'; +import { neon, neonGlow } from '../theme/neon'; + +/** + * Sits above the tab shell, carrying the wallet controls that frontend keeps in + * its sidebar. Rendered once around the navigator rather than per screen, so it + * does not remount on every tab change. + */ +export default function AppHeader() { + const { isConnected } = useAccount(); + const insets = useSafeAreaInsets(); + + return ( + + Do Not Stop + + {isConnected ? : null} + + + + ); +} + +const styles = StyleSheet.create({ + header: { + backgroundColor: neon.bgPanel, + borderBottomWidth: 1, + borderBottomColor: neon.border, + paddingHorizontal: 16, + paddingBottom: 16, + ...neonGlow(neon.cyan, 8, 0.2), + }, + headerTitle: { + fontSize: 28, + fontWeight: '800', + textAlign: 'center', + color: neon.text, + letterSpacing: 2, + textShadowColor: neon.cyan, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 12, + }, + walletRow: { + marginTop: 12, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + flexWrap: 'wrap', + }, +}); diff --git a/mobile/src/components/ui/toast.tsx b/mobile/src/components/ui/toast.tsx index 0d71bbe6..005c048b 100644 --- a/mobile/src/components/ui/toast.tsx +++ b/mobile/src/components/ui/toast.tsx @@ -1,5 +1,6 @@ import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { neon, neonGlow } from '../../theme/neon'; @@ -9,9 +10,8 @@ import { neon, neonGlow } from '../../theme/neon'; * `useTxErrorToast` port across unchanged. * * Rendered as an absolutely positioned overlay rather than a portal, since RN has - * no document to portal into. It sits outside `SafeAreaProvider` (matching - * frontend's provider order, where `ToastProvider` wraps the router), so the - * bottom offset is a fixed inset rather than a measured one. + * no document to portal into. The bottom offset clears both the safe area and the + * tab bar, so a toast never lands under either. */ export type ToastTone = 'error' | 'info' | 'success'; @@ -44,9 +44,13 @@ const TONE_COLOR: Record = { /** Stands in for `crypto.randomUUID`, which RN does not provide. */ let nextToastId = 0; +/** Roughly a bottom tab bar, so a toast does not sit on top of the tabs. */ +const TAB_BAR_CLEARANCE = 64; + export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [toasts, setToasts] = useState([]); const timersRef = useRef[]>([]); + const insets = useSafeAreaInsets(); const dismiss = useCallback((id: string) => { setToasts((current) => current.filter((toast) => toast.id !== id)); @@ -84,7 +88,10 @@ export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ childre {children} {toasts.length > 0 && ( - + {toasts.map((toast) => { const color = TONE_COLOR[toast.tone ?? 'error']; return ( @@ -124,7 +131,6 @@ const styles = StyleSheet.create({ position: 'absolute', left: 16, right: 16, - bottom: 32, }, toast: { flexDirection: 'row', diff --git a/mobile/src/navigation/RootNavigator.tsx b/mobile/src/navigation/RootNavigator.tsx index eca70d6e..69e292cd 100644 --- a/mobile/src/navigation/RootNavigator.tsx +++ b/mobile/src/navigation/RootNavigator.tsx @@ -1,8 +1,15 @@ import React from 'react'; import { StyleSheet, Text } from 'react-native'; -import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { + createBottomTabNavigator, + type BottomTabNavigationOptions, +} from '@react-navigation/bottom-tabs'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { useAccount } from 'wagmi'; +import AppHeader from '../components/AppHeader'; +import GalleryScreen from '../screens/GalleryScreen'; +import LandingScreen from '../screens/LandingScreen'; import { placeholderFor } from '../screens/PlaceholderScreen'; import { neon } from '../theme/neon'; import { @@ -15,9 +22,9 @@ import { const Tab = createBottomTabNavigator(); const Stack = createNativeStackNavigator(); -/** Phase 4 swaps these for the real screens, one per commit. */ +/** Phase 4 swaps the remaining placeholders for real screens, one per commit. */ const TAB_SCREENS: Record = { - Gallery: placeholderFor('Gallery'), + Gallery: GalleryScreen, Battle: placeholderFor('Battle Arena'), Breed: placeholderFor('Breeding Lab'), LevelUp: placeholderFor('Level Up'), @@ -35,67 +42,92 @@ const STACK_SCREENS = { * a render prop, so defining it during render hands the tab bar a new component * type every pass and remounts the icon. */ -const TAB_OPTIONS = Object.fromEntries( - TAB_ITEMS.map((item) => { +const TAB_OPTIONS = TAB_ITEMS.reduce( + (acc, item) => { const Icon = ({ color }: { color: string }) => ( {item.glyph} ); Icon.displayName = `TabIcon(${item.name})`; - return [item.name, { title: item.label, tabBarIcon: Icon }]; - }), -) as Record }>; + acc[item.name] = { title: item.label, tabBarIcon: Icon }; + return acc; + }, + {} as Record, +); export const MainTabs = () => ( - - {TAB_ITEMS.map((item) => ( - - ))} - + <> + + + {TAB_ITEMS.map((item) => ( + + ))} + + ); /** - * Landing sits outside the tab shell so the connect screen has no tab bar. The - * gate that decides which one is shown lands in step 3.2; for now `Main` is the - * initial route so the shell can be exercised. + * Landing sits outside the tab shell so the connect screen has no tab bar and no + * header. + * + * The two halves are registered conditionally rather than both being present with + * a redirect. That is React Navigation's documented auth-flow shape and it is what + * makes the transition one-way: with Landing unregistered there is no back target + * to return to once a wallet connects, and no window where a tab screen renders + * against a disconnected wallet. + * + * The gate is `isConnected`, not `isAuthenticated`. A backend session alone does + * not let any of these screens work, because every one of them reads chain state. */ -export const RootNavigator = () => ( - - - - {(Object.keys(STACK_SCREENS) as (keyof typeof STACK_SCREENS)[]).map((name) => ( - - ))} - -); +export const RootNavigator = () => { + const { isConnected } = useAccount(); + + return ( + + {!isConnected ? ( + + ) : ( + <> + + {(Object.keys(STACK_SCREENS) as (keyof typeof STACK_SCREENS)[]).map((name) => ( + + ))} + + )} + + ); +}; const styles = StyleSheet.create({ tabBar: { diff --git a/mobile/src/screens/GalleryScreen.tsx b/mobile/src/screens/GalleryScreen.tsx new file mode 100644 index 00000000..cca6be1e --- /dev/null +++ b/mobile/src/screens/GalleryScreen.tsx @@ -0,0 +1,137 @@ +import React, { useCallback, useState } from 'react'; +import { ActivityIndicator, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; +import { useCreatePet, usePetList } from '@shared/core'; + +import CreatePetModal from '../components/CreatePetModal'; +import PetList from '../components/PetList'; +import { neon, neonGlow } from '../theme/neon'; + +/** + * The player's collection. Carried over from the pre-navigation `AppContent`, so + * it is already on `usePetList` / `useCreatePet`; Phase 4 adds the cooldown and + * per-pet action surface frontend's pet-gallery has. + */ +export default function GalleryScreen() { + const pets = usePetList(); + const [refreshing, setRefreshing] = useState(false); + const [createModalVisible, setCreateModalVisible] = useState(false); + + const closeCreateModal = useCallback(() => { + setCreateModalVisible(false); + }, []); + + // EVM minting is two-phase (requestMintStarter, then settleMint once Pyth + // Entropy reveals), so the list is only worth re-reading once onSuccess fires. + const createPet = useCreatePet({ + onSuccess: () => { + closeCreateModal(); + pets.refetch(); + }, + }); + + const handleRefreshPets = useCallback(async () => { + setRefreshing(true); + try { + await pets.refetch(); + } finally { + setRefreshing(false); + } + }, [pets]); + + return ( + // No outer ScrollView: PetList brings its own scroll and pull-to-refresh. + + + setCreateModalVisible(true)} + activeOpacity={0.85} + > + Create + + + {refreshing ? ( + + ) : ( + Refresh + )} + + + + + + ); +} + +const styles = StyleSheet.create({ + root: { + flex: 1, + backgroundColor: neon.bgDeep, + paddingHorizontal: 16, + paddingTop: 16, + paddingBottom: 8, + }, + actionsRow: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + marginBottom: 16, + flexWrap: 'wrap', + }, + createBtn: { + backgroundColor: neon.bgCard, + paddingHorizontal: 20, + paddingVertical: 10, + borderRadius: 12, + marginRight: 12, + marginBottom: 4, + minWidth: 100, + alignItems: 'center', + borderWidth: 1, + borderColor: neon.cyan, + ...neonGlow(neon.cyan, 10, 0.4), + }, + createBtnText: { + color: neon.cyan, + fontSize: 16, + fontWeight: '700', + letterSpacing: 0.5, + }, + refreshBtn: { + borderWidth: 1, + borderColor: neon.magenta, + backgroundColor: neon.bgPanel, + paddingHorizontal: 20, + paddingVertical: 10, + borderRadius: 12, + marginBottom: 4, + minWidth: 100, + alignItems: 'center', + justifyContent: 'center', + minHeight: 42, + ...neonGlow(neon.magenta, 8, 0.25), + }, + refreshBtnDisabled: { + opacity: 0.5, + }, + refreshBtnText: { + color: neon.magenta, + fontSize: 16, + fontWeight: '700', + }, +}); diff --git a/mobile/src/screens/LandingScreen.tsx b/mobile/src/screens/LandingScreen.tsx new file mode 100644 index 00000000..cfa8a054 --- /dev/null +++ b/mobile/src/screens/LandingScreen.tsx @@ -0,0 +1,143 @@ +import React from 'react'; +import { ScrollView, StyleSheet, Text, View } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; +import { useAuth } from '@shared/core'; + +import ConnectButton from '../components/ConnectButton'; +import { neon, neonGlow } from '../theme/neon'; + +/** + * Pre-connect screen, outside the tab shell. A signed-in player whose wallet is + * not connected also lands here: every screen behind the tabs reads chain state, + * so a session alone is not enough to enter. + */ +export default function LandingScreen() { + const { isAuthenticated } = useAuth(); + const insets = useSafeAreaInsets(); + + return ( + + + ON-CHAIN COLLECTION + Do Not Stop + + + {isAuthenticated + ? 'Welcome back. Connect a wallet to load your on-chain pets.' + : 'Connect your wallet to mint, battle, and breed — same universe as the web app, in your pocket.'} + + + + Create pets + Mint unique companions on-chain. + + + Battles + Prove strength in the arena. + + + Breeding + Combine traits for the next gen. + + + + + + + + ); +} + +const styles = StyleSheet.create({ + scrollView: { + flex: 1, + backgroundColor: neon.bgDeep, + }, + scrollContent: { + paddingHorizontal: 16, + paddingBottom: 32, + }, + welcomeSection: { + alignItems: 'center', + }, + heroKicker: { + fontSize: 11, + fontWeight: '700', + letterSpacing: 4, + color: neon.magenta, + marginBottom: 8, + textShadowColor: neon.magenta, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 8, + }, + heroTitle: { + fontSize: 36, + fontWeight: '900', + color: neon.text, + letterSpacing: 1, + marginBottom: 4, + textShadowColor: neon.cyan, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 16, + }, + heroGlowLine: { + width: 120, + height: 3, + backgroundColor: neon.cyan, + marginBottom: 20, + borderRadius: 2, + opacity: 0.95, + ...neonGlow(neon.cyan, 8, 0.75), + }, + welcomeText: { + fontSize: 16, + color: neon.textMuted, + textAlign: 'center', + marginBottom: 28, + maxWidth: 600, + lineHeight: 24, + }, + features: { + width: '100%', + maxWidth: 900, + }, + feature: { + backgroundColor: neon.bgCard, + borderRadius: 16, + padding: 20, + marginBottom: 16, + borderWidth: 1, + }, + featureCyan: { + borderColor: 'rgba(0, 245, 255, 0.45)', + ...neonGlow(neon.cyan, 12, 0.25), + }, + featureMagenta: { + borderColor: 'rgba(255, 45, 166, 0.45)', + ...neonGlow(neon.magenta, 12, 0.25), + }, + featurePurple: { + borderColor: 'rgba(192, 132, 252, 0.45)', + ...neonGlow(neon.purple, 12, 0.22), + }, + featureTitle: { + fontSize: 18, + fontWeight: '800', + color: neon.text, + letterSpacing: 0.5, + marginBottom: 6, + }, + featureSub: { + fontSize: 14, + color: neon.textDim, + lineHeight: 20, + }, + connectButtonContainer: { + alignItems: 'center', + marginTop: 8, + }, +}); From a1a3578cf2c97255fd101f59d497b542eafbaddc Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 17:39:31 -0400 Subject: [PATCH 09/99] feat(mobile): build the gallery screen on the composite hook --- mobile/__tests__/GalleryScreen.test.tsx | 188 ++++++++++++++++++ mobile/jest.config.js | 5 + mobile/src/components/PetCard.tsx | 153 ++++++++++++++ mobile/src/components/PetList.tsx | 90 +++------ mobile/src/hooks/pet-gallery/usePetGallery.ts | 99 +++++++++ mobile/src/hooks/usePetCooldowns.ts | 61 ++++++ mobile/src/navigation/routes.ts | 26 ++- mobile/src/screens/GalleryScreen.tsx | 120 +++++++---- 8 files changed, 635 insertions(+), 107 deletions(-) create mode 100644 mobile/__tests__/GalleryScreen.test.tsx create mode 100644 mobile/src/components/PetCard.tsx create mode 100644 mobile/src/hooks/pet-gallery/usePetGallery.ts create mode 100644 mobile/src/hooks/usePetCooldowns.ts diff --git a/mobile/__tests__/GalleryScreen.test.tsx b/mobile/__tests__/GalleryScreen.test.tsx new file mode 100644 index 00000000..fee5e9d3 --- /dev/null +++ b/mobile/__tests__/GalleryScreen.test.tsx @@ -0,0 +1,188 @@ +/** + * Gallery screen over a stubbed `usePetGallery`. The composite hook is where the + * real wiring lives (chain adapter, API client, navigation), so the screen is + * checked as what it is: a pure view over that hook's return value. + * + * `usePetCooldowns` is exercised directly further down, since its tick and label + * logic is the part with actual behaviour. + */ + +import React from 'react'; +import { Text } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; +import type { Pet } from '@shared/core'; + +// `@shared/core`'s barrel re-exports the Solana adapter, so importing anything from +// it drags @solana/web3.js and its transitive runtime into jest. The only thing +// needed here is the two cooldown utils, which are dependency-free, so they are +// pulled from their own module and the barrel is stubbed. +jest.mock('@shared/core', () => ({ + ...jest.requireActual('../../shared/src/utils/ethereum/petReadyTime'), + getRarityColor: (r: number) => (r === 2 ? '#C0C0C0' : '#8B4513'), + getRarityName: (r: number) => (r === 2 ? 'Uncommon' : 'Common'), +})); + +const mockGallery = jest.fn(); +jest.mock('../src/hooks/pet-gallery/usePetGallery', () => ({ + usePetGallery: () => mockGallery(), +})); +jest.mock('../src/components/CreatePetModal', () => () => null); + +import GalleryScreen from '../src/screens/GalleryScreen'; +import { usePetCooldowns } from '../src/hooks/usePetCooldowns'; + +const pet = (over: Partial = {}): Pet => ({ + id: '1', + chain: 'evm', + name: 'Rex', + dna: 0n, + level: 3, + rarity: 2, + winCount: 4, + lossCount: 1, + readyAt: 0, + ...over, +}); + +const readyStatus = { + onCooldown: false, + battleReady: true, + battleOnCooldown: false, + breedOnCooldown: false, + trainOnCooldown: false, + battleLabel: '', + breedLabel: '', + trainLabel: '', +}; + +const galleryValue = (over: Record = {}) => ({ + pets: [] as Pet[], + isLoading: false, + error: null, + totalWins: 0, + statusFor: () => readyStatus, + refreshing: false, + onRefresh: jest.fn(), + createPet: {}, + createModalOpen: false, + onOpenCreateModal: jest.fn(), + onCloseCreateModal: jest.fn(), + onBattle: jest.fn(), + onRename: jest.fn(), + onDefend: jest.fn(), + ...over, +}); + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' | '); + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +describe('GalleryScreen', () => { + it('shows the pet and win totals', async () => { + mockGallery.mockReturnValue( + galleryValue({ pets: [pet(), pet({ id: '2', winCount: 6 })], totalWins: 10 }), + ); + const rendered = textOf(await render()); + expect(rendered).toContain('Pets'); + expect(rendered).toContain('10'); + }); + + it('renders a card per pet with its rarity and record', async () => { + mockGallery.mockReturnValue(galleryValue({ pets: [pet()], totalWins: 4 })); + const rendered = textOf(await render()); + expect(rendered).toContain('Rex'); + expect(rendered).toContain('Uncommon'); + expect(rendered).toContain('ID #1'); + expect(rendered).toContain('Level 3'); + }); + + it('surfaces the empty state rather than an empty list', async () => { + mockGallery.mockReturnValue(galleryValue()); + expect(textOf(await render())).toContain('No pets yet'); + }); + + it('shows a load failure instead of pretending the roster is empty', async () => { + mockGallery.mockReturnValue(galleryValue({ error: new Error('rpc down') })); + const rendered = textOf(await render()); + expect(rendered).toContain('Could not load pets'); + expect(rendered).toContain('rpc down'); + }); + + it('renders cooldown countdowns when a pet is not ready', async () => { + mockGallery.mockReturnValue( + galleryValue({ + pets: [pet()], + statusFor: () => ({ + ...readyStatus, + onCooldown: true, + battleReady: false, + battleOnCooldown: true, + battleLabel: '2h 5m', + }), + }), + ); + expect(textOf(await render())).toContain('Battle ready in 2h 5m'); + }); +}); + +describe('usePetCooldowns', () => { + const Probe = ({ pets, onStatus }: { pets: Pet[]; onStatus: (s: unknown) => void }) => { + const { anyCooldown, statusFor } = usePetCooldowns(pets); + onStatus({ anyCooldown, status: pets[0] ? statusFor(pets[0]) : null }); + return null; + }; + + const probe = async (pets: Pet[]) => { + const seen: { anyCooldown: boolean; status: { onCooldown: boolean } | null }[] = []; + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create( + seen.push(s as never)} />, + ); + }); + // A pet on cooldown starts a 1s interval. Without unmounting, the hook's + // cleanup never runs and jest hangs after the assertions pass. + await ReactTestRenderer.act(() => { + tree.unmount(); + }); + return seen[seen.length - 1]; + }; + + it('reports a ready pet as off cooldown', async () => { + const result = await probe([pet({ readyAt: 0 })]); + expect(result.anyCooldown).toBe(false); + expect(result.status?.onCooldown).toBe(false); + }); + + it('reports a future readyAt as on cooldown', async () => { + const future = Math.floor(Date.now() / 1000) + 3600; + const result = await probe([pet({ readyAt: future })]); + expect(result.anyCooldown).toBe(true); + expect(result.status?.onCooldown).toBe(true); + }); + + it('treats an absent breed/train cooldown as ready, not as zero', async () => { + // breedReadyAt/trainReadyAt are optional on Pet; a missing one must not read + // as epoch 0 and it must not read as blocked either. + const result = await probe([pet({ readyAt: 0, breedReadyAt: undefined })]); + expect(result.status?.onCooldown).toBe(false); + }); +}); diff --git a/mobile/jest.config.js b/mobile/jest.config.js index 7de75dce..2e3d050a 100644 --- a/mobile/jest.config.js +++ b/mobile/jest.config.js @@ -10,6 +10,11 @@ module.exports = { // node_modules except react-native itself, so importing any of them dies on // `export *`. `react-native-*` covers the navigation native peers (screens, // safe-area-context) as well as react-native itself. + // Deliberately does not list @solana. Reaching it means a test imported the + // `@shared/core` barrel, which re-exports the Solana adapter and drags the whole + // Solana runtime in; that ends in unparseable .mjs and an unresolvable + // `rpc-websockets`, not just a transform gap. Stub the barrel in the test and + // require the specific util module instead (see GalleryScreen.test.tsx). transformIgnorePatterns: [ 'node_modules/(?!(?:@react-native|react-native|react-native-.*|@react-navigation|wagmi|@wagmi|viem|ox|abitype)/)', ], diff --git a/mobile/src/components/PetCard.tsx b/mobile/src/components/PetCard.tsx new file mode 100644 index 00000000..8b247ff7 --- /dev/null +++ b/mobile/src/components/PetCard.tsx @@ -0,0 +1,153 @@ +import React from 'react'; +import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; +import { getRarityColor, getRarityName, type Pet } from '@shared/core'; + +import type { PetCooldownStatus } from '../hooks/usePetCooldowns'; +import { neon, neonGlow } from '../theme/neon'; + +type Props = { + pet: Pet; + status: PetCooldownStatus; + onBattle: () => void; + onRename: () => void; + onDefend: () => void; +}; + +/** + * One pet, with its cooldowns and the per-pet actions that reach the stack routes. + * Rename and Defense live here rather than in the tab bar because both act on a + * chosen pet; see plan 3.1. + */ +export default function PetCard({ pet, status, onBattle, onRename, onDefend }: Props) { + const rarityColor = getRarityColor(pet.rarity); + + return ( + + + {pet.name} + + + {getRarityName(pet.rarity)} + + + + + ID #{pet.id} + + Level {pet.level} + {pet.xp != null ? ` · ${pet.xp} XP` : ''} + + + W {pet.winCount} · L {pet.lossCount} + + + {status.onCooldown ? ( + + {status.battleOnCooldown && ( + Battle ready in {status.battleLabel} + )} + {status.breedOnCooldown && ( + Breed ready in {status.breedLabel} + )} + {status.trainOnCooldown && ( + Train ready in {status.trainLabel} + )} + + ) : null} + + + + Battle + + + Rename + + + Defend + + + + ); +} + +const styles = StyleSheet.create({ + card: { + backgroundColor: neon.bgCard, + borderRadius: 14, + padding: 16, + marginBottom: 12, + borderWidth: 1, + borderColor: 'rgba(0, 245, 255, 0.22)', + width: '100%', + ...neonGlow(neon.cyan, 8, 0.2), + }, + cardHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 8, + }, + petName: { + fontSize: 20, + fontWeight: '800', + color: neon.text, + flex: 1, + }, + rarityBadge: { + borderWidth: 1, + borderRadius: 8, + paddingHorizontal: 10, + paddingVertical: 4, + }, + rarityText: { + fontSize: 12, + fontWeight: '600', + }, + meta: { + fontSize: 14, + color: neon.textMuted, + marginTop: 4, + }, + cooldowns: { + marginTop: 8, + paddingTop: 8, + borderTopWidth: 1, + borderTopColor: 'rgba(255, 45, 166, 0.2)', + }, + cooldown: { + fontSize: 13, + color: neon.textDim, + marginTop: 2, + }, + actions: { + flexDirection: 'row', + marginTop: 12, + flexWrap: 'wrap', + }, + action: { + borderWidth: 1, + borderColor: neon.border, + backgroundColor: neon.bgPanel, + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 8, + marginRight: 8, + marginTop: 4, + }, + battleAction: { + borderColor: neon.borderMagenta, + }, + actionDisabled: { + opacity: 0.4, + }, + actionText: { + fontSize: 13, + fontWeight: '700', + color: neon.cyan, + }, +}); diff --git a/mobile/src/components/PetList.tsx b/mobile/src/components/PetList.tsx index ebb410b9..ee15cfec 100644 --- a/mobile/src/components/PetList.tsx +++ b/mobile/src/components/PetList.tsx @@ -7,8 +7,11 @@ import { Text, View, } from 'react-native'; -import { getRarityColor, getRarityName, type Pet } from '@shared/core'; -import { neon, neonGlow } from '../theme/neon'; +import type { Pet } from '@shared/core'; + +import PetCard from './PetCard'; +import type { PetCooldownStatus } from '../hooks/usePetCooldowns'; +import { neon } from '../theme/neon'; type Props = { pets: Pet[]; @@ -16,9 +19,23 @@ type Props = { error: Error | null; onRefresh: () => void; refreshing: boolean; + statusFor: (pet: Pet) => PetCooldownStatus; + onBattle: (pet: Pet) => void; + onRename: (pet: Pet) => void; + onDefend: (pet: Pet) => void; }; -export default function PetList({ pets, isLoading, error, onRefresh, refreshing }: Props) { +export default function PetList({ + pets, + isLoading, + error, + onRefresh, + refreshing, + statusFor, + onBattle, + onRename, + onDefend, +}: Props) { if (error) { const message = error instanceof Error ? error.message : String(error); return ( @@ -75,26 +92,16 @@ export default function PetList({ pets, isLoading, error, onRefresh, refreshing } > Your pets - {pets.map((pet) => { - const rarityColor = getRarityColor(pet.rarity); - return ( - - - {pet.name} - - - {getRarityName(pet.rarity)} - - - - ID #{pet.id} - Level {pet.level} - - W {pet.winCount} · L {pet.lossCount} - - - ); - })} + {pets.map((pet) => ( + onBattle(pet)} + onRename={() => onRename(pet)} + onDefend={() => onDefend(pet)} + /> + ))} ); } @@ -123,43 +130,6 @@ const styles = StyleSheet.create({ textShadowOffset: { width: 0, height: 0 }, textShadowRadius: 8, }, - card: { - backgroundColor: neon.bgCard, - borderRadius: 14, - padding: 16, - marginBottom: 12, - borderWidth: 1, - borderColor: 'rgba(0, 245, 255, 0.22)', - width: '100%', - ...neonGlow(neon.cyan, 8, 0.2), - }, - cardHeader: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: 8, - }, - petName: { - fontSize: 20, - fontWeight: '800', - color: neon.text, - flex: 1, - }, - rarityBadge: { - borderWidth: 1, - borderRadius: 8, - paddingHorizontal: 10, - paddingVertical: 4, - }, - rarityText: { - fontSize: 12, - fontWeight: '600', - }, - meta: { - fontSize: 14, - color: neon.textMuted, - marginTop: 4, - }, loadingText: { marginTop: 12, fontSize: 16, diff --git a/mobile/src/hooks/pet-gallery/usePetGallery.ts b/mobile/src/hooks/pet-gallery/usePetGallery.ts new file mode 100644 index 00000000..617e7b08 --- /dev/null +++ b/mobile/src/hooks/pet-gallery/usePetGallery.ts @@ -0,0 +1,99 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useNavigation } from '@react-navigation/native'; +import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { useChainCapabilities, useCreatePet, usePetList, type Pet } from '@shared/core'; + +import type { RootStackParamList } from '../../navigation/routes'; +import { useNotifyError } from '../useNotifyError'; +import { usePetCooldowns, type PetCooldownStatus } from '../usePetCooldowns'; + +/** + * Headless controller for the gallery, ported from + * `frontend/src/hooks/pet-gallery/usePetGallery.ts`. The view is a pure function of + * this hook, same convention as frontend. + * + * Two differences. Navigation is React Navigation rather than `useNavigate`, and + * targets the per-pet stack routes decided in plan 3.1 instead of a sidebar path. + * And `useCreatePet` lives here rather than in the screen, so the mint's `onSuccess` + * can refetch the list the hook already owns. + * + * The send/transfer modal is deliberately absent: `useTransferPet` exists in the + * adapter, but transfer is not in the plan's hook list for this screen and pulls in + * a whole address-entry flow. It belongs with the rest of Phase 4, not here. + */ +export interface UsePetGallery { + pets: Pet[]; + isLoading: boolean; + error: Error | null; + totalWins: number; + statusFor: (pet: Pet) => PetCooldownStatus; + refreshing: boolean; + onRefresh: () => void; + createPet: ReturnType; + createModalOpen: boolean; + onOpenCreateModal: () => void; + onCloseCreateModal: () => void; + onBattle: (pet: Pet) => void; + onRename: (pet: Pet) => void; + onDefend: (pet: Pet) => void; +} + +type GalleryNavigation = NativeStackNavigationProp; + +export const usePetGallery = (): UsePetGallery => { + const navigation = useNavigation(); + const { isConnected } = useChainCapabilities(); + const { pets, isLoading, error, refetch } = usePetList(); + const notifyError = useNotifyError(); + const [createModalOpen, setCreateModalOpen] = useState(false); + const [refreshing, setRefreshing] = useState(false); + + const { statusFor } = usePetCooldowns(pets); + + const totalWins = useMemo( + () => pets.reduce((sum, pet) => sum + (pet.winCount ?? 0), 0), + [pets], + ); + + useEffect(() => { + if (!error) return; + notifyError('Failed to load pet data. Please try again.', error, 'pet-list'); + }, [error, notifyError]); + + const onCloseCreateModal = useCallback(() => setCreateModalOpen(false), []); + + // EVM minting is two-phase (requestMintStarter, then settleMint once Pyth + // Entropy reveals), so the list is only worth re-reading once onSuccess fires. + const createPet = useCreatePet({ + onSuccess: () => { + onCloseCreateModal(); + refetch(); + }, + }); + + const onRefresh = useCallback(async () => { + setRefreshing(true); + try { + await refetch(); + } finally { + setRefreshing(false); + } + }, [refetch]); + + return { + pets: isConnected ? pets : [], + isLoading, + error, + totalWins, + statusFor, + refreshing, + onRefresh, + createPet, + createModalOpen, + onOpenCreateModal: () => setCreateModalOpen(true), + onCloseCreateModal, + onBattle: (pet) => navigation.navigate('Main', { screen: 'Battle', params: { petId: pet.id } }), + onRename: (pet) => navigation.navigate('Rename', { petId: pet.id }), + onDefend: (pet) => navigation.navigate('Defense', { petId: pet.id }), + }; +}; diff --git a/mobile/src/hooks/usePetCooldowns.ts b/mobile/src/hooks/usePetCooldowns.ts new file mode 100644 index 00000000..e77d92f3 --- /dev/null +++ b/mobile/src/hooks/usePetCooldowns.ts @@ -0,0 +1,61 @@ +import { useEffect, useState } from 'react'; +import { getTimeUntilReady, isPetReady, type Pet } from '@shared/core'; + +export interface PetCooldownStatus { + /** True when any of the three cooldowns is still active. */ + onCooldown: boolean; + /** Battle cooldown (the pet's primary `readyAt`). */ + battleReady: boolean; + battleOnCooldown: boolean; + breedOnCooldown: boolean; + trainOnCooldown: boolean; + /** "Xh Ym" countdown labels — only meaningful while the matching cooldown is active. */ + battleLabel: string; + breedLabel: string; + trainLabel: string; +} + +export interface PetCooldowns { + /** True while any pet in the list is on cooldown (drives the live 1s tick). */ + anyCooldown: boolean; + /** Per-pet readiness flags + countdown labels, recomputed each tick. */ + statusFor: (pet: Pet) => PetCooldownStatus; +} + +const statusFor = (pet: Pet): PetCooldownStatus => { + const battleReady = isPetReady(BigInt(pet.readyAt)); + const breedOnCooldown = pet.breedReadyAt != null && !isPetReady(BigInt(pet.breedReadyAt)); + const trainOnCooldown = pet.trainReadyAt != null && !isPetReady(BigInt(pet.trainReadyAt)); + return { + onCooldown: !battleReady || breedOnCooldown || trainOnCooldown, + battleReady, + battleOnCooldown: !battleReady, + breedOnCooldown, + trainOnCooldown, + battleLabel: getTimeUntilReady(BigInt(pet.readyAt)), + breedLabel: pet.breedReadyAt != null ? getTimeUntilReady(BigInt(pet.breedReadyAt)) : '', + trainLabel: pet.trainReadyAt != null ? getTimeUntilReady(BigInt(pet.trainReadyAt)) : '', + }; +}; + +/** + * Cooldown readiness for a list of pets. Ticks once a second while any pet is on + * cooldown so the countdown labels stay live, and exposes a `statusFor(pet)` helper + * so the view never repeats the readiness math. + * + * Copied from `frontend/src/hooks/usePetCooldowns.ts` unchanged: it depends only on + * `@shared/core` utils, so there is nothing web-specific to adapt. + */ +export const usePetCooldowns = (pets: Pet[]): PetCooldowns => { + const [, setTick] = useState(0); + + const anyCooldown = pets.some((p) => statusFor(p).onCooldown); + + useEffect(() => { + if (!anyCooldown) return; + const id = setInterval(() => setTick((t) => t + 1), 1000); + return () => clearInterval(id); + }, [anyCooldown]); + + return { anyCooldown, statusFor }; +}; diff --git a/mobile/src/navigation/routes.ts b/mobile/src/navigation/routes.ts index 64dea40a..0af209a8 100644 --- a/mobile/src/navigation/routes.ts +++ b/mobile/src/navigation/routes.ts @@ -7,23 +7,31 @@ * than shown disabled: a tab bar has no room to advertise what does not work yet. */ -/** Screens pushed over the tab shell. `undefined` = takes no params. */ -export type RootStackParamList = { - Landing: undefined; - Main: undefined; - Marriage: undefined; - Rename: { petId?: string } | undefined; - Defense: { petId?: string } | undefined; -}; +import type { NavigatorScreenParams } from '@react-navigation/native'; export type MainTabParamList = { Gallery: undefined; - Battle: { roomId?: string } | undefined; + /** + * `roomId` mirrors frontend's optional `/battle/:roomId?` segment, set once + * Start Battle mints a room. `petId` is the pet a Gallery action came in with, + * which frontend passes as router state rather than in the path. + */ + Battle: { roomId?: string; petId?: string } | undefined; Breed: undefined; LevelUp: undefined; Train: undefined; }; +/** Screens pushed over the tab shell. `undefined` = takes no params. */ +export type RootStackParamList = { + Landing: undefined; + /** `NavigatorScreenParams` is what makes `navigate('Main', { screen, params })` type-check. */ + Main: NavigatorScreenParams | undefined; + Marriage: undefined; + Rename: { petId?: string } | undefined; + Defense: { petId?: string } | undefined; +}; + export type TabItem = { name: keyof MainTabParamList; label: string; diff --git a/mobile/src/screens/GalleryScreen.tsx b/mobile/src/screens/GalleryScreen.tsx index cca6be1e..120dc0f7 100644 --- a/mobile/src/screens/GalleryScreen.tsx +++ b/mobile/src/screens/GalleryScreen.tsx @@ -1,57 +1,62 @@ -import React, { useCallback, useState } from 'react'; +import React from 'react'; import { ActivityIndicator, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { useCreatePet, usePetList } from '@shared/core'; import CreatePetModal from '../components/CreatePetModal'; import PetList from '../components/PetList'; +import { usePetGallery } from '../hooks/pet-gallery/usePetGallery'; import { neon, neonGlow } from '../theme/neon'; /** - * The player's collection. Carried over from the pre-navigation `AppContent`, so - * it is already on `usePetList` / `useCreatePet`; Phase 4 adds the cooldown and - * per-pet action surface frontend's pet-gallery has. + * The player's collection: a pure view over `usePetGallery`, same split frontend + * uses between `pet-gallery/index.tsx` and its hook. + * + * Frontend's stat strip has a third tile, Global Rank, backed by placeholder data. + * It is left out rather than reproduced: a hardcoded "#3" reads as real on a phone + * with no surrounding context. */ export default function GalleryScreen() { - const pets = usePetList(); - const [refreshing, setRefreshing] = useState(false); - const [createModalVisible, setCreateModalVisible] = useState(false); - - const closeCreateModal = useCallback(() => { - setCreateModalVisible(false); - }, []); - - // EVM minting is two-phase (requestMintStarter, then settleMint once Pyth - // Entropy reveals), so the list is only worth re-reading once onSuccess fires. - const createPet = useCreatePet({ - onSuccess: () => { - closeCreateModal(); - pets.refetch(); - }, - }); - - const handleRefreshPets = useCallback(async () => { - setRefreshing(true); - try { - await pets.refetch(); - } finally { - setRefreshing(false); - } - }, [pets]); + const { + pets, + isLoading, + error, + totalWins, + statusFor, + refreshing, + onRefresh, + createPet, + createModalOpen, + onOpenCreateModal, + onCloseCreateModal, + onBattle, + onRename, + onDefend, + } = usePetGallery(); return ( // No outer ScrollView: PetList brings its own scroll and pull-to-refresh. + + + {pets.length} + Pets + + + {totalWins} + Wins + + + setCreateModalVisible(true)} + onPress={onOpenCreateModal} activeOpacity={0.85} > Create @@ -62,17 +67,23 @@ export default function GalleryScreen() { )} + + ); @@ -86,6 +97,39 @@ const styles = StyleSheet.create({ paddingTop: 16, paddingBottom: 8, }, + stats: { + flexDirection: 'row', + marginBottom: 16, + }, + stat: { + flex: 1, + backgroundColor: neon.bgCard, + borderRadius: 12, + borderWidth: 1, + paddingVertical: 12, + alignItems: 'center', + marginRight: 12, + }, + statCyan: { + borderColor: 'rgba(0, 245, 255, 0.35)', + ...neonGlow(neon.cyan, 8, 0.2), + }, + statViolet: { + borderColor: 'rgba(192, 132, 252, 0.35)', + marginRight: 0, + ...neonGlow(neon.purple, 8, 0.2), + }, + statValue: { + fontSize: 22, + fontWeight: '900', + color: neon.text, + }, + statLabel: { + fontSize: 12, + color: neon.textMuted, + marginTop: 2, + letterSpacing: 1, + }, actionsRow: { flexDirection: 'row', alignItems: 'center', From 69ea76f30f9e181da9e8aac3aa41d833856efa94 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 5 Aug 2026 19:47:12 -0400 Subject: [PATCH 10/99] feat(mobile): add the defense consent screen --- mobile/__tests__/DefenseScreen.test.tsx | 182 +++++++++++++++ mobile/__tests__/actionScreens.test.tsx | 216 ++++++++++++++++++ mobile/__tests__/navigation.test.tsx | 11 +- mobile/src/components/PetPicker.tsx | 107 +++++++++ mobile/src/hooks/usePetPicker.ts | 42 ++++ mobile/src/navigation/RootNavigator.tsx | 15 +- mobile/src/screens/DefenseScreen.tsx | 180 +++++++++++++++ mobile/src/screens/LevelUpScreen.tsx | 102 +++++++++ mobile/src/screens/RenameScreen.tsx | 176 ++++++++++++++ mobile/src/screens/TrainScreen.tsx | 98 ++++++++ .../src/screens/parts/ActionScreenLayout.tsx | 151 ++++++++++++ 11 files changed, 1273 insertions(+), 7 deletions(-) create mode 100644 mobile/__tests__/DefenseScreen.test.tsx create mode 100644 mobile/__tests__/actionScreens.test.tsx create mode 100644 mobile/src/components/PetPicker.tsx create mode 100644 mobile/src/hooks/usePetPicker.ts create mode 100644 mobile/src/screens/DefenseScreen.tsx create mode 100644 mobile/src/screens/LevelUpScreen.tsx create mode 100644 mobile/src/screens/RenameScreen.tsx create mode 100644 mobile/src/screens/TrainScreen.tsx create mode 100644 mobile/src/screens/parts/ActionScreenLayout.tsx diff --git a/mobile/__tests__/DefenseScreen.test.tsx b/mobile/__tests__/DefenseScreen.test.tsx new file mode 100644 index 00000000..d0e7de4f --- /dev/null +++ b/mobile/__tests__/DefenseScreen.test.tsx @@ -0,0 +1,182 @@ +/** + * Standing defence consent (§D). The parts worth pinning are what reaches `grant`: + * a wrong scope here either exposes every pet a player owns or silently authorizes + * none, and neither is visible in the UI afterwards. + * + * `@shared/core` is stubbed — its barrel drags the Solana runtime into jest. + */ + +import React from 'react'; +import { Text, TouchableOpacity } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; +import type { Pet } from '@shared/core'; + +const pet = (over: Partial = {}): Pet => ({ + id: '1', + chain: 'evm', + name: 'Rex', + dna: 0n, + level: 5, + rarity: 2, + winCount: 0, + lossCount: 0, + readyAt: 0, + ...over, +}); + +const mockState = { + pets: [pet(), pet({ id: '2', name: 'Momo' })] as Pet[], + isConnected: true, + isPending: false, + error: null as Error | null, +}; + +const mockGrant = jest.fn(async () => '0xhash'); +const mockRevoke = jest.fn(async () => true); + +jest.mock('@shared/core', () => ({ + usePetList: () => ({ pets: mockState.pets, isLoading: false, error: null, refetch: jest.fn() }), + useChainCapabilities: () => ({ isConnected: mockState.isConnected }), + useDefenseAuthorization: () => ({ + grant: mockGrant, + revoke: mockRevoke, + isPending: mockState.isPending, + error: mockState.error, + }), +})); + +const mockNotify = jest.fn(); +jest.mock('../src/hooks/useNotifyError', () => ({ useNotifyError: () => mockNotify })); + +const mockRouteParams: { petId?: string } = {}; +jest.mock('@react-navigation/native', () => ({ + useRoute: () => ({ params: mockRouteParams }), +})); + +import DefenseScreen from '../src/screens/DefenseScreen'; + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((n) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(n.props.children); + }) + .join(' | '); + +/** + * ActionScreenLayout renders its children first, then the primary action, then the + * secondary — so the two buttons are always the last two touchables, whatever the + * checkbox rows above them look like. + */ +const press = async (tree: ReactTestRenderer.ReactTestRenderer, index: number) => { + await ReactTestRenderer.act(async () => { + tree.root.findAllByType(TouchableOpacity)[index].props.onPress(); + }); +}; + +const pressAllow = async (tree: ReactTestRenderer.ReactTestRenderer) => { + const buttons = tree.root.findAllByType(TouchableOpacity); + await ReactTestRenderer.act(async () => { + buttons[buttons.length - 2].props.onPress(); + }); +}; + +const pressWithdraw = async (tree: ReactTestRenderer.ReactTestRenderer) => { + const buttons = tree.root.findAllByType(TouchableOpacity); + await ReactTestRenderer.act(async () => { + buttons[buttons.length - 1].props.onPress(); + }); +}; + +beforeEach(() => { + mockState.pets = [pet(), pet({ id: '2', name: 'Momo' })]; + mockState.isConnected = true; + mockState.isPending = false; + mockState.error = null; + delete mockRouteParams.petId; + jest.clearAllMocks(); +}); + +describe('DefenseScreen', () => { + it('defaults to covering every pet, including future ones', async () => { + const tree = await render(); + await pressAllow(tree); + expect(mockGrant).toHaveBeenCalledWith({ allPets: true }); + }); + + it('hides the per-pet list until the blanket scope is turned off', async () => { + const tree = await render(); + expect(textOf(tree)).not.toContain('Momo'); + await press(tree, 0); + expect(textOf(tree)).toContain('Momo'); + }); + + it('grants only the chosen pets once narrowed', async () => { + const tree = await render(); + await press(tree, 0); // turn off "all pets" + await press(tree, 2); // second pet row (row 1 is the all-pets toggle) + await pressAllow(tree); + expect(mockGrant).toHaveBeenCalledWith({ petIds: ['2'] }); + }); + + it('narrows to the pet a Gallery action arrived with, rather than granting for all', async () => { + // Coming in from one pet's Defend button must not silently authorize the + // whole wallet, which is what the default scope would do. + mockRouteParams.petId = '2'; + const tree = await render(); + await pressAllow(tree); + expect(mockGrant).toHaveBeenCalledWith({ petIds: ['2'] }); + }); + + it('reports the scope it actually granted', async () => { + const tree = await render(); + await pressAllow(tree); + expect(textOf(tree)).toContain('Every pet you own can now be challenged.'); + }); + + it('withdraws consent', async () => { + const tree = await render(); + await pressWithdraw(tree); + expect(mockRevoke).toHaveBeenCalled(); + expect(textOf(tree)).toContain('Consent withdrawn.'); + }); + + it('notifies rather than signing when disconnected', async () => { + mockState.isConnected = false; + const tree = await render(); + await pressAllow(tree); + expect(mockGrant).not.toHaveBeenCalled(); + expect(mockNotify).toHaveBeenCalledWith( + 'Please connect your wallet first', + undefined, + 'defense-validation', + ); + }); + + it('surfaces a signing failure', async () => { + mockState.error = new Error('User rejected the signature'); + const tree = await render(); + expect(textOf(tree)).toContain('User rejected the signature'); + }); + + it('says so when there is nothing to authorize', async () => { + mockState.pets = []; + const tree = await render(); + await press(tree, 0); + expect(textOf(tree)).toContain('No pets to authorize yet.'); + }); +}); diff --git a/mobile/__tests__/actionScreens.test.tsx b/mobile/__tests__/actionScreens.test.tsx new file mode 100644 index 00000000..a5d0634e --- /dev/null +++ b/mobile/__tests__/actionScreens.test.tsx @@ -0,0 +1,216 @@ +/** + * Level Up, Train and Rename: the three single-mutation screens. Each is checked + * for the parts that are easy to get wrong and invisible until a wallet is + * attached — the level-scaled fee in the button label, the validation gate, and + * what reaches `mutate`. + * + * `@shared/core` is stubbed rather than imported: its barrel re-exports the Solana + * adapter and drags an unparseable runtime into jest (see GalleryScreen.test.tsx). + */ + +import React from 'react'; +import { Text, TextInput, TouchableOpacity } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; +import type { Pet } from '@shared/core'; + +const pet = (over: Partial = {}): Pet => ({ + id: '1', + chain: 'evm', + name: 'Rex', + dna: 0n, + level: 5, + rarity: 2, + winCount: 0, + lossCount: 0, + readyAt: 0, + ...over, +}); + +const mockState = { + pets: [pet()] as Pet[], + isConnected: true, + renameMinLevel: 1, + levelUpFee: 1000n as bigint | null, + trainFee: 1000n as bigint | null, +}; + +const mockMutations = { + levelUp: jest.fn(), + train: jest.fn(), + rename: jest.fn(), +}; + +const mutationResult = (mutate: jest.Mock) => ({ + mutate, + isPending: false, + error: null, + reset: jest.fn(), + lifecycle: {}, +}); + +jest.mock('@shared/core', () => ({ + getReadyPetsUnified: (pets: Pet[]) => pets.map((p) => ({ id: p.id, pet: p })), + usePetList: () => ({ pets: mockState.pets, isLoading: false, error: null, refetch: jest.fn() }), + useChainCapabilities: () => ({ + isConnected: mockState.isConnected, + renameMinLevel: mockState.renameMinLevel, + }), + useFees: () => ({ + levelUpFee: mockState.levelUpFee, + trainFee: mockState.trainFee, + // Mirrors the real formatter closely enough to assert the scaling maths. + formatAmount: (v: bigint) => `${v.toString()} wei`, + }), + useLevelUpPet: () => mutationResult(mockMutations.levelUp), + useTrainPet: () => mutationResult(mockMutations.train), + useRenamePet: () => mutationResult(mockMutations.rename), +})); + +const mockNotify = jest.fn(); +jest.mock('../src/hooks/useNotifyError', () => ({ useNotifyError: () => mockNotify })); +jest.mock('../src/hooks/useTxErrorToast', () => ({ useTxErrorToast: () => {} })); + +const mockRouteParams: { petId?: string } = {}; +jest.mock('@react-navigation/native', () => ({ + useRoute: () => ({ params: mockRouteParams }), +})); + +import LevelUpScreen from '../src/screens/LevelUpScreen'; +import TrainScreen from '../src/screens/TrainScreen'; +import RenameScreen from '../src/screens/RenameScreen'; + +const render = async (Screen: React.ComponentType) => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((n) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(n.props.children); + }) + .join(' | '); + +/** The action button is the last touchable the layout renders. */ +const pressAction = async (tree: ReactTestRenderer.ReactTestRenderer) => { + const buttons = tree.root.findAllByType(TouchableOpacity); + await ReactTestRenderer.act(() => { + buttons[buttons.length - 1].props.onPress(); + }); +}; + +const selectFirstPet = async (tree: ReactTestRenderer.ReactTestRenderer) => { + await ReactTestRenderer.act(() => { + tree.root.findAllByType(TouchableOpacity)[0].props.onPress(); + }); +}; + +beforeEach(() => { + mockState.pets = [pet()]; + mockState.isConnected = true; + mockState.renameMinLevel = 1; + mockState.levelUpFee = 1000n; + mockState.trainFee = 1000n; + delete mockRouteParams.petId; + jest.clearAllMocks(); +}); + +describe('LevelUpScreen', () => { + it('scales the fee by (level-1)² and shows it on the button', async () => { + // level 5 → 100 + 4² = 116 → 1000 * 116 / 100 = 1160 + const tree = await render(LevelUpScreen); + await selectFirstPet(tree); + expect(textOf(tree)).toContain('Level Up (1160 wei)'); + }); + + it('omits the cost until a pet is chosen, since the fee depends on its level', async () => { + const tree = await render(LevelUpScreen); + expect(textOf(tree)).toContain('Level Up'); + expect(textOf(tree)).not.toContain('wei'); + }); + + it('passes the selected pet to the mutation', async () => { + const tree = await render(LevelUpScreen); + await selectFirstPet(tree); + await pressAction(tree); + expect(mockMutations.levelUp).toHaveBeenCalledWith({ petId: '1' }); + }); + + it('notifies rather than mutating when disconnected', async () => { + mockState.isConnected = false; + const tree = await render(LevelUpScreen); + await selectFirstPet(tree); + await pressAction(tree); + expect(mockMutations.levelUp).not.toHaveBeenCalled(); + expect(mockNotify).toHaveBeenCalledWith( + 'Please connect your wallet first', + undefined, + 'level-up-validation', + ); + }); +}); + +describe('TrainScreen', () => { + it('scales the fee by 2·level, a different curve from level-up', async () => { + // level 5 → 100 + 10 = 110 → 1000 * 110 / 100 = 1100 + const tree = await render(TrainScreen); + await selectFirstPet(tree); + expect(textOf(tree)).toContain('Train (1100 wei)'); + }); + + it('still offers the action when the fee has not loaded', async () => { + mockState.trainFee = null; + const tree = await render(TrainScreen); + await selectFirstPet(tree); + expect(textOf(tree)).toContain('Train'); + }); +}); + +describe('RenameScreen', () => { + it('rejects a name below the minimum length', async () => { + const tree = await render(RenameScreen); + await selectFirstPet(tree); + await ReactTestRenderer.act(() => { + tree.root.findByType(TextInput).props.onChangeText('a'); + }); + expect(textOf(tree)).toContain('○ Min 2 characters'); + }); + + it('trims before sending, so trailing spaces do not reach the chain', async () => { + const tree = await render(RenameScreen); + await selectFirstPet(tree); + await ReactTestRenderer.act(() => { + tree.root.findByType(TextInput).props.onChangeText(' Blaze '); + }); + await pressAction(tree); + expect(mockMutations.rename).toHaveBeenCalledWith({ petId: '1', name: 'Blaze' }); + }); + + it('preselects the pet a Gallery action arrived with', async () => { + mockState.pets = [pet(), pet({ id: '2', name: 'Momo' })]; + mockRouteParams.petId = '2'; + const tree = await render(RenameScreen); + await ReactTestRenderer.act(() => { + tree.root.findByType(TextInput).props.onChangeText('Blaze'); + }); + await pressAction(tree); + expect(mockMutations.rename).toHaveBeenCalledWith({ petId: '2', name: 'Blaze' }); + }); + + it('hides pets below the chain minimum level', async () => { + mockState.renameMinLevel = 10; + mockState.pets = [pet({ level: 5 })]; + const tree = await render(RenameScreen); + expect(textOf(tree)).toContain('level 10 or above'); + }); +}); diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index b336ec0c..509aea0e 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -12,9 +12,16 @@ import { NavigationContainer } from '@react-navigation/native'; const mockIsConnected = jest.fn(() => true); jest.mock('wagmi', () => ({ useAccount: () => ({ isConnected: mockIsConnected() }) })); -// The screens behind the gate are the app's real ones; each pulls in the chain -// adapter and the API client, which is not what a navigator smoke test is for. +// The screens behind the gate are the app's real ones; each imports the +// `@shared/core` barrel, which drags the Solana runtime into jest and fails to +// parse. Stub every screen the navigator mounts — a new real screen replacing a +// placeholder is what breaks this suite next. jest.mock('../src/screens/GalleryScreen', () => () => null); +jest.mock('../src/screens/LevelUpScreen', () => () => null); +jest.mock('../src/screens/TrainScreen', () => () => null); +jest.mock('../src/screens/RenameScreen', () => () => null); +jest.mock('../src/screens/DefenseScreen', () => () => null); +jest.mock('../src/screens/BreedScreen', () => () => null); jest.mock('../src/components/AppHeader', () => () => null); jest.mock('../src/screens/LandingScreen', () => { const { Text: RNText } = jest.requireActual('react-native'); diff --git a/mobile/src/components/PetPicker.tsx b/mobile/src/components/PetPicker.tsx new file mode 100644 index 00000000..8865deb1 --- /dev/null +++ b/mobile/src/components/PetPicker.tsx @@ -0,0 +1,107 @@ +import React from 'react'; +import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; +import type { ReadyPet } from '@shared/core'; + +import { neon } from '../theme/neon'; + +type Props = { + pets: ReadyPet[]; + selectedId: string; + onSelect: (id: string) => void; + /** Shown when nothing is selectable, e.g. every pet is on cooldown. */ + emptyHint: string; + disabled?: boolean; +}; + +/** + * Horizontal chips in place of frontend's ``. RN has no native picker * without a dependency, and the lists here are short: only pets off cooldown. */ -export default function PetPicker({ pets, selectedId, onSelect, emptyHint, disabled }: Props) { +export default function PetPicker({ + pets, + selectedId, + onSelect, + emptyHint, + hasAnyPets, + disabled, +}: Props) { if (pets.length === 0) { return ( - {emptyHint} + + {hasAnyPets === false ? NO_PETS_HINT : emptyHint} + ); } diff --git a/mobile/src/hooks/battle/useBattlePanel.ts b/mobile/src/hooks/battle/useBattlePanel.ts index 56ade744..fbbe54c6 100644 --- a/mobile/src/hooks/battle/useBattlePanel.ts +++ b/mobile/src/hooks/battle/useBattlePanel.ts @@ -37,6 +37,8 @@ export interface UseBattlePanel { isConnected: boolean; /** Own pets off cooldown; a pet on cooldown cannot legally battle. */ readyPets: { id: string; pet: Pet }[]; + /** Whether the wallet holds any pets at all, before the cooldown filter. */ + hasAnyPets: boolean; selectedPetId: string; onSelectPet: (id: string) => void; fighter: Pet | null; @@ -209,6 +211,7 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { return { isConnected: capabilities.isConnected, readyPets, + hasAnyPets: pets.length > 0, selectedPetId, onSelectPet: setSelectedPetId, fighter, diff --git a/mobile/src/hooks/usePetPicker.ts b/mobile/src/hooks/usePetPicker.ts index d76f8714..ad7f68ce 100644 --- a/mobile/src/hooks/usePetPicker.ts +++ b/mobile/src/hooks/usePetPicker.ts @@ -4,6 +4,8 @@ import { getReadyPetsUnified, usePetList, type Pet, type ReadyPet } from '@share export interface PetPicker { /** Pets off cooldown, after the caller's own filter. */ selectable: ReadyPet[]; + /** Whether the wallet holds any pets at all, before cooldown or filter. */ + hasAnyPets: boolean; selectedId: string; selectedPet: Pet | null; select: (id: string) => void; @@ -32,6 +34,7 @@ export const usePetPicker = (filter?: (pet: Pet) => boolean): PetPicker => { return { selectable, + hasAnyPets: pets.length > 0, selectedId, selectedPet, select: setSelectedId, diff --git a/mobile/src/screens/BattleScreen.tsx b/mobile/src/screens/BattleScreen.tsx index 75b3e1b7..3bc9a95d 100644 --- a/mobile/src/screens/BattleScreen.tsx +++ b/mobile/src/screens/BattleScreen.tsx @@ -50,6 +50,7 @@ export default function BattleScreen() { selectedId={panel.selectedPetId} onSelect={panel.onSelectPet} disabled={panel.isBusy} + hasAnyPets={panel.hasAnyPets} emptyHint="No pets are off cooldown. A pet that just fought has to wait." /> diff --git a/mobile/src/screens/LevelUpScreen.tsx b/mobile/src/screens/LevelUpScreen.tsx index bfd97d15..fccdce80 100644 --- a/mobile/src/screens/LevelUpScreen.tsx +++ b/mobile/src/screens/LevelUpScreen.tsx @@ -72,6 +72,7 @@ export default function LevelUpScreen() { selectedId={picker.selectedId} onSelect={picker.select} disabled={isPending} + hasAnyPets={picker.hasAnyPets} emptyHint="No pets are off cooldown right now." /> {picker.selectedPet ? ( diff --git a/mobile/src/screens/RenameScreen.tsx b/mobile/src/screens/RenameScreen.tsx index e75ba3f6..21200a4b 100644 --- a/mobile/src/screens/RenameScreen.tsx +++ b/mobile/src/screens/RenameScreen.tsx @@ -93,6 +93,7 @@ export default function RenameScreen() { selectedId={picker.selectedId} onSelect={picker.select} disabled={isPending} + hasAnyPets={picker.hasAnyPets} emptyHint={ renameMinLevel > 1 ? `No pets are off cooldown and at level ${renameMinLevel} or above.` diff --git a/mobile/src/screens/TrainScreen.tsx b/mobile/src/screens/TrainScreen.tsx index 0d7c69d7..c92b92dd 100644 --- a/mobile/src/screens/TrainScreen.tsx +++ b/mobile/src/screens/TrainScreen.tsx @@ -68,6 +68,7 @@ export default function TrainScreen() { selectedId={picker.selectedId} onSelect={picker.select} disabled={isPending} + hasAnyPets={picker.hasAnyPets} emptyHint="No pets are off cooldown right now." /> {picker.selectedPet ? ( From 653565ef4875dcdc38d5a47666254138b4d87ce6 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Sun, 9 Aug 2026 18:57:12 -0400 Subject: [PATCH 32/99] fix(mobile): offer a network fix that a frozen session can accept --- mobile/__tests__/networkGate.test.tsx | 68 ++++++++++++++++-- mobile/src/components/NetworkGate.tsx | 100 ++++++++++++++++++++++---- 2 files changed, 148 insertions(+), 20 deletions(-) diff --git a/mobile/__tests__/networkGate.test.tsx b/mobile/__tests__/networkGate.test.tsx index 9ae43fb7..b0473b09 100644 --- a/mobile/__tests__/networkGate.test.tsx +++ b/mobile/__tests__/networkGate.test.tsx @@ -25,12 +25,28 @@ const mockState = { }; const mockSwitchChainAsync = jest.fn(async () => undefined); +const mockOpen = jest.fn(async () => undefined); +const mockDisconnect = jest.fn(async () => undefined); +const mockToast = { + show: jest.fn(), + error: jest.fn(), + info: jest.fn(), + success: jest.fn(), +}; jest.mock('wagmi', () => ({ useAccount: () => ({ isConnected: mockState.isConnected, chainId: mockState.chainId }), useSwitchChain: () => ({ switchChainAsync: mockSwitchChainAsync }), })); +jest.mock('@reown/appkit-react-native', () => ({ + useAppKit: () => ({ open: mockOpen, disconnect: mockDisconnect }), +})); + +jest.mock('../src/components/ui/toast', () => ({ + useToast: () => mockToast, +})); + jest.mock('../src/hooks/useApprovedEvmChains', () => ({ ...jest.requireActual('../src/hooks/useApprovedEvmChains'), useApprovedEvmChains: () => mockState.approved, @@ -71,6 +87,10 @@ beforeEach(() => { // call that would otherwise carry it into the next test. mockSwitchChainAsync.mockReset(); mockSwitchChainAsync.mockResolvedValue(undefined); + mockOpen.mockClear(); + mockDisconnect.mockClear(); + mockToast.error.mockClear(); + mockToast.info.mockClear(); }); describe('pickRequestChainId', () => { @@ -209,21 +229,58 @@ describe('NetworkGate', () => { expect(textOf(tree)).toContain('signing will fail'); }); - it('offers the switch even when the target is unapproved', async () => { - // `wallet_addEthereumChain` is the only call that can widen a live - // session, so hiding the button strands the player on reconnect advice - // that does not help a wallet which hides testnets. + it('leads with reconnect when the target was never approved', async () => { + // A session's chain set is frozen at handshake, so a new proposal is the + // only path that reliably widens it. Switching leads only when the target + // is already approved, where it is a local provider call. mockState.chainId = TARGET_CHAIN_ID; mockState.approved = [mainnet.id]; const tree = await render(); + expect(textOf(tree)).toContain('Reconnect wallet'); + await ReactTestRenderer.act(async () => { tree.root.findAllByType(TouchableOpacity)[0].props.onPress(); }); + expect(mockDisconnect).toHaveBeenCalled(); + expect(mockOpen).toHaveBeenCalled(); + expect(mockSwitchChainAsync).not.toHaveBeenCalledWith({ chainId: TARGET_CHAIN_ID }); + }); + + it('still offers the add attempt for wallets that honour it', async () => { + // `wallet_addEthereumChain` does widen a live session in some wallets, so + // the path stays reachable rather than being removed for everyone. + mockState.chainId = TARGET_CHAIN_ID; + mockState.approved = [mainnet.id]; + const tree = await render(); + + await ReactTestRenderer.act(async () => { + tree.root.findAllByType(TouchableOpacity)[1].props.onPress(); + }); + expect(mockSwitchChainAsync).toHaveBeenCalledWith({ chainId: TARGET_CHAIN_ID }); }); + it('explains a wallet that ends the session instead of adding the chain', async () => { + // Rabby's behaviour: the request goes out, no prompt appears, and the + // session dies. The gate unmounts with it, so the message has to survive + // as a toast or the player is returned to Landing with no reason given. + mockState.chainId = TARGET_CHAIN_ID; + mockState.approved = [mainnet.id]; + mockSwitchChainAsync.mockRejectedValue( + new Error('An unknown RPC error occurred.\n\nDetails: User disconnected.'), + ); + const tree = await render(); + + await ReactTestRenderer.act(async () => { + tree.root.findAllByType(TouchableOpacity)[1].props.onPress(); + }); + + expect(textOf(tree)).toContain('ended the session'); + expect(mockToast.error).toHaveBeenCalledWith(expect.stringContaining('ended the session')); + }); + it('repairs a session pinned to a chain it never approved', async () => { // Mounted on Sepolia with only mainnet approved: every request would die // in the sign client, including the `wallet_addEthereumChain` the switch @@ -260,8 +317,9 @@ describe('NetworkGate', () => { mockSwitchChainAsync.mockRejectedValue(new Error('unsupported chain')); const tree = await render(); + // The add attempt is the secondary action now; reconnect leads. await ReactTestRenderer.act(async () => { - tree.root.findAllByType(TouchableOpacity)[0].props.onPress(); + tree.root.findAllByType(TouchableOpacity)[1].props.onPress(); }); expect(textOf(tree)).toContain('disconnect and reconnect'); diff --git a/mobile/src/components/NetworkGate.tsx b/mobile/src/components/NetworkGate.tsx index 6498e07f..af207223 100644 --- a/mobile/src/components/NetworkGate.tsx +++ b/mobile/src/components/NetworkGate.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import { ActivityIndicator, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; +import { useAppKit } from '@reown/appkit-react-native'; import { useAccount, useSwitchChain } from 'wagmi'; import { @@ -9,6 +10,7 @@ import { } from '../constants/ethereumNetworks'; import { useApprovedEvmChains } from '../hooks/useApprovedEvmChains'; import { useEvmSessionChain } from '../hooks/useEvmSessionChain'; +import { useNotifyError } from '../hooks/useNotifyError'; import { neon, neonGlow } from '../theme/neon'; /** MetaMask's user-rejection code, per EIP-1193. */ @@ -26,10 +28,16 @@ function describeSwitchFailure( if (code === USER_REJECTED) { return 'You dismissed the request in your wallet. Try again to keep playing.'; } + const message = err instanceof Error ? err.message : String(err); + // Some wallets answer a request for a chain they never approved by ending the + // session outright rather than refusing the call. Observed with Rabby, which + // hides testnets by default and so has no Base Sepolia to add. + if (/disconnect/i.test(message)) { + return `Your wallet ended the session instead of adding ${targetName}. Enable ${targetName} in the wallet, then connect again.`; + } if (!targetAuthorized) { return `Your wallet would not add ${targetName} to this session. Enable ${targetName} in the wallet, then disconnect and reconnect.`; } - const message = err instanceof Error ? err.message : String(err); return message || 'Could not switch networks. Change it manually in your wallet.'; } @@ -46,8 +54,10 @@ function describeSwitchFailure( export default function NetworkGate() { const { isConnected, chainId } = useAccount(); const { switchChainAsync } = useSwitchChain(); + const { open, disconnect } = useAppKit(); const approvedChains = useApprovedEvmChains(); - const [isSwitching, setIsSwitching] = useState(false); + const notifyError = useNotifyError(); + const [isBusy, setIsBusy] = useState(false); const [error, setError] = useState(null); useEvmSessionChain(); @@ -59,22 +69,54 @@ export default function NetworkGate() { const targetName = getTargetChainName(); + const report = (err: unknown) => { + const copy = describeSwitchFailure(err, targetName, targetAuthorized); + setError(copy); + // A wallet that ends the session takes this gate down with it: the tab + // shell unmounts back to Landing, so the inline copy is gone before it can + // be read. The toast outlives that. + notifyError(copy, err, 'network-gate'); + }; + const handleSwitch = async () => { - setIsSwitching(true); + setIsBusy(true); setError(null); try { await switchChainAsync({ chainId: TARGET_CHAIN_ID }); } catch (err) { - setError(describeSwitchFailure(err, targetName, targetAuthorized)); + report(err); } finally { - setIsSwitching(false); + setIsBusy(false); } }; - // An unapproved target still gets the switch button. The wallet fixed the - // approved set at connect time, but `wallet_addEthereumChain` can extend a - // live session, and that is the only path that does — reconnecting alone will - // not help a wallet that hides testnets by default. + /** + * Drops the session and opens the connect sheet, so the next handshake can + * propose the target chain. + * + * This is the reliable path when the wallet never approved the target: + * WalletConnect freezes a session's chain set at connect time, and only some + * wallets honour `wallet_addEthereumChain` against a live session. The ones + * that do not either refuse it or, worse, end the session. + */ + const handleReconnect = async () => { + setIsBusy(true); + setError(null); + try { + await disconnect(); + await open(); + } catch (err) { + report(err); + } finally { + setIsBusy(false); + } + }; + + // Which action leads depends on why the gate is up. On the wrong chain with + // the target approved, switching is a local provider call and always works. + // With the target unapproved, only a fresh handshake reliably widens the set, + // so reconnect leads and the add attempt stays available for the wallets that + // do honour it. return ( @@ -86,22 +128,38 @@ export default function NetworkGate() { {error ?? (targetAuthorized ? "Your wallet is on a different network, so pets and battles can't load." - : `This session has no permission for ${targetName}, so signing will fail. Switching asks your wallet to add it.`)} + : `This session has no permission for ${targetName}, so signing will fail. Your wallet fixes that list when it connects, so turn on ${targetName} there, then reconnect.`)} { - handleSwitch().catch(() => undefined); + (targetAuthorized ? handleSwitch() : handleReconnect()).catch(() => undefined); }} - disabled={isSwitching} + disabled={isBusy} activeOpacity={0.85} > - {isSwitching ? ( + {isBusy ? ( ) : ( - Switch to {targetName} + + {targetAuthorized ? `Switch to ${targetName}` : 'Reconnect wallet'} + )} + {targetAuthorized ? null : ( + { + handleSwitch().catch(() => undefined); + }} + disabled={isBusy} + activeOpacity={0.85} + > + + Ask this wallet to add {targetName} + + + )} ); } @@ -144,6 +202,18 @@ const styles = StyleSheet.create({ fontWeight: '800', fontSize: 13, }, + secondaryBtn: { + alignSelf: 'flex-start', + paddingHorizontal: 4, + paddingVertical: 8, + marginTop: 4, + }, + secondaryBtnText: { + color: neon.textMuted, + fontWeight: '700', + fontSize: 12, + textDecorationLine: 'underline', + }, disabled: { opacity: 0.55, }, From 22decfd01a2834d8a3b9deb6ee7341b9ecec279d Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 15:16:11 -0400 Subject: [PATCH 33/99] fix(shared): read entropy and settle events from the request block --- .../ethereum/useEvmEntropySettleFlow.ts | 10 ++++++++ .../chains/ethereum/usePolledContractEvent.ts | 24 ++++++++++++++++--- .../ethereum/useWatchEntropyFulfillment.ts | 7 ++++++ .../chains/ethereum/useWatchPetsContract.ts | 7 ++++++ shared/src/hooks/pets/useBreedPets.ts | 1 + shared/src/hooks/pets/useCreatePet.ts | 3 +++ .../hooks/usePolledContractEvent.test.tsx | 22 ++++++++++++++++- 7 files changed, 70 insertions(+), 4 deletions(-) diff --git a/shared/src/hooks/chains/ethereum/useEvmEntropySettleFlow.ts b/shared/src/hooks/chains/ethereum/useEvmEntropySettleFlow.ts index deecc2f2..9b0f7b43 100644 --- a/shared/src/hooks/chains/ethereum/useEvmEntropySettleFlow.ts +++ b/shared/src/hooks/chains/ethereum/useEvmEntropySettleFlow.ts @@ -38,6 +38,14 @@ export interface EvmEntropySettleFlowOptions { export interface EvmEntropySettleFlow { /** Non-null from the request tx landing until the caller clears it. */ pendingRequestId: bigint | null; + /** + * Block the request tx landed in, for callers that watch a settled event. + * + * Both the reveal and, when a keeper is running, the settle itself can land + * before a watch armed from the request can start looking. Every watch in this + * flow therefore reads from here rather than from the current head. + */ + requestBlockNumber: bigint | undefined; /** Receipt of the settle tx, for callers that parse the settled event out of it. */ settleReceipt: TransactionReceipt | undefined; settleConfirmed: boolean; @@ -126,6 +134,7 @@ export const useEvmEntropySettleFlow = ( entropyAddress: enabled ? (entropyAddress as `0x${string}` | undefined) : undefined, gameLogicAddress: enabled ? evm?.gameLogic.address : undefined, requestId: enabled ? pendingRequestId : null, + fromBlock: requestReceipt?.blockNumber, onFulfilled: handleEntropyFulfilled, }); @@ -148,6 +157,7 @@ export const useEvmEntropySettleFlow = ( return { pendingRequestId, + requestBlockNumber: requestReceipt?.blockNumber, settleReceipt, settleConfirmed: enabled && settleConfirmed, isSettling: enabled && settle.isPending, diff --git a/shared/src/hooks/chains/ethereum/usePolledContractEvent.ts b/shared/src/hooks/chains/ethereum/usePolledContractEvent.ts index 1249ae5b..a4ffc6a8 100644 --- a/shared/src/hooks/chains/ethereum/usePolledContractEvent.ts +++ b/shared/src/hooks/chains/ethereum/usePolledContractEvent.ts @@ -27,6 +27,21 @@ export interface UsePolledContractEventParams { enabled: boolean; chainId?: number; pollingIntervalMs?: number; + /** + * First block to read, instead of "whatever is latest when the watch starts". + * + * Without this the watch is blind to anything emitted before it mounted, and + * the events these callers wait on routinely land in that window. A mint + * cannot arm its watch until the request receipt has confirmed *and* + * `parseEventLogs` has pulled the requestId out of it *and* React has + * re-rendered; Pyth Entropy reveals a block or two after the request, and + * Base builds a block every two seconds. The reveal is therefore usually + * already in the past by the time anyone is looking, and the watch then polls + * forward forever past the one event it exists to catch. + * + * Pass the request transaction's own block and the walk starts there. + */ + fromBlock?: bigint; onLogs: (logs: Log[]) => void; } @@ -53,6 +68,7 @@ export function usePolledContractEvent({ enabled, chainId, pollingIntervalMs = DEFAULT_POLLING_INTERVAL_MS, + fromBlock: startBlock, onLogs, }: UsePolledContractEventParams): void { const publicClient = usePublicClient({ chainId }); @@ -63,7 +79,7 @@ export function usePolledContractEvent({ if (!enabled || !address || !publicClient) return; let cancelled = false; - let fromBlock: bigint | null = null; + let fromBlock: bigint | null = startBlock ?? null; let inFlight = false; const tick = async () => { @@ -72,7 +88,9 @@ export function usePolledContractEvent({ try { const latest = await publicClient.getBlockNumber(); if (fromBlock === null) { - // First tick: start watching from now, not the entire chain history. + // No start block given: watch from now, not the entire chain + // history. Callers waiting on an event that may already have + // fired must pass `fromBlock` — see its doc comment. fromBlock = latest + 1n; return; } @@ -110,5 +128,5 @@ export function usePolledContractEvent({ cancelled = true; clearInterval(timer); }; - }, [enabled, address, publicClient, abi, eventName, pollingIntervalMs]); + }, [enabled, address, publicClient, abi, eventName, pollingIntervalMs, startBlock]); } diff --git a/shared/src/hooks/chains/ethereum/useWatchEntropyFulfillment.ts b/shared/src/hooks/chains/ethereum/useWatchEntropyFulfillment.ts index c44ec29c..15f20ba0 100644 --- a/shared/src/hooks/chains/ethereum/useWatchEntropyFulfillment.ts +++ b/shared/src/hooks/chains/ethereum/useWatchEntropyFulfillment.ts @@ -29,6 +29,11 @@ type UseWatchEntropyFulfillmentParams = { gameLogicAddress?: `0x${string}`; /** requestId (= entropy sequenceNumber as uint256) to wait on; null disables the watch. */ requestId: bigint | null; + /** + * Block the request tx landed in. Entropy usually reveals before this watch can + * arm, so without it the reveal is already history and the mint hangs forever. + */ + fromBlock?: bigint; /** Fired once `Revealed` lands for `requestId` called by our GameLogic. `randomNumber` * is the raw revealed word — the same 32 bytes GameLogic stores as * `uint256(randomNumber)` and settles the request from. */ @@ -45,6 +50,7 @@ export const useWatchEntropyFulfillment = ({ entropyAddress, gameLogicAddress, requestId, + fromBlock, onFulfilled, }: UseWatchEntropyFulfillmentParams): void => { const wantRef = useRef(requestId); @@ -60,6 +66,7 @@ export const useWatchEntropyFulfillment = ({ abi: ENTROPY_REVEALED_ABI as unknown as Abi, eventName: 'Revealed', enabled: Boolean(requestId != null && entropyAddress && gameLogicAddress), + fromBlock, onLogs(logs) { const want = wantRef.current; const gl = gameLogicRef.current?.toLowerCase(); diff --git a/shared/src/hooks/chains/ethereum/useWatchPetsContract.ts b/shared/src/hooks/chains/ethereum/useWatchPetsContract.ts index b3ee2c95..2d87d2dc 100644 --- a/shared/src/hooks/chains/ethereum/useWatchPetsContract.ts +++ b/shared/src/hooks/chains/ethereum/useWatchPetsContract.ts @@ -15,6 +15,11 @@ type UseWatchPetsContractParams = { address?: `0x${string}`; /** VRF request id from `BreedRandomnessRequested`; must match `BreedSettled.requestId` */ pendingRequestId: bigint | null; + /** + * Block the breed request landed in. A settle keeper can emit `BreedSettled` + * before this watch arms, and reading from the head would miss it. + */ + fromBlock?: bigint; onBreedSuccess?: (payload: BreedSuccessPayload) => void; }; @@ -27,6 +32,7 @@ export const useWatchPetsContract = ({ abi, address, pendingRequestId, + fromBlock, onBreedSuccess, }: UseWatchPetsContractParams): void => { const pendingRef = useRef(pendingRequestId); @@ -45,6 +51,7 @@ export const useWatchPetsContract = ({ abi: abi as Abi, eventName: 'BreedSettled', enabled: Boolean(pendingRequestId != null && address && contractAddress), + fromBlock, onLogs(logs) { if (!address) return; const want = pendingRef.current; diff --git a/shared/src/hooks/pets/useBreedPets.ts b/shared/src/hooks/pets/useBreedPets.ts index d1e55694..ca4152bd 100644 --- a/shared/src/hooks/pets/useBreedPets.ts +++ b/shared/src/hooks/pets/useBreedPets.ts @@ -78,6 +78,7 @@ export const useBreedPets = (options?: UseBreedPetsOptions) => { abi: evm?.gameLogic.abi ?? [], address: address as `0x${string}` | undefined, pendingRequestId: isEvm ? pendingRequestId : null, + fromBlock: flow.requestBlockNumber, onBreedSuccess: isEvm ? handleBreedFulfilled : undefined, }); diff --git a/shared/src/hooks/pets/useCreatePet.ts b/shared/src/hooks/pets/useCreatePet.ts index 90c968cc..5388c224 100644 --- a/shared/src/hooks/pets/useCreatePet.ts +++ b/shared/src/hooks/pets/useCreatePet.ts @@ -106,6 +106,9 @@ export const useCreatePet = (options?: PetMutationOptions): PetMutationResult void) => +const setup = (onLogs: (logs: unknown[]) => void, fromBlock?: bigint) => renderHook(() => usePolledContractEvent({ address: ADDRESS, abi: [], eventName: 'Revealed', enabled: true, + fromBlock, onLogs: onLogs as never, }), ); @@ -106,6 +107,25 @@ describe('usePolledContractEvent', () => { expect(afterFailure[0]![0]).toBe(1451n); }); + it('reads from a given start block, catching an event that already fired', async () => { + // The regression this guards: the watch used to begin at `latest + 1`, so + // anything emitted before it mounted was invisible. A mint cannot arm its + // watch until the request receipt confirms and React re-renders, by which + // time Pyth Entropy has usually already revealed a block or two after the + // request. The reveal was therefore missed on nearly every mint, and the + // flow sat on "awaiting randomness" forever with the fee already spent. + publicClient.getBlockNumber.mockResolvedValue(1003n); + const onLogs = vi.fn(); + publicClient.getContractEvents.mockResolvedValue([{ args: { sequenceNumber: 7n } }]); + + setup(onLogs, 1000n); // request landed in 1000, three blocks back + await flush(); + + // No watermark-only first tick: the backlog is read immediately. + expect(spans()).toEqual([[1000n, 1003n]]); + expect(onLogs).toHaveBeenCalledTimes(1); + }); + it('delivers logs to the latest callback without restarting the poll', async () => { publicClient.getBlockNumber.mockResolvedValue(1000n); const onLogs = vi.fn(); From 5cfa6f3c3b07477ca275222b7e33ace83195ac0c Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 18:24:44 -0400 Subject: [PATCH 34/99] feat(mobile): add the leaderboard screen --- mobile/__tests__/LeaderboardScreen.test.tsx | 241 ++++++++++ mobile/__tests__/accountSheet.test.tsx | 30 +- mobile/__tests__/navigation.test.tsx | 11 +- mobile/src/components/AccountSheet.tsx | 20 + mobile/src/navigation/RootNavigator.tsx | 2 + mobile/src/navigation/routes.ts | 7 + mobile/src/screens/LeaderboardScreen.tsx | 505 ++++++++++++++++++++ 7 files changed, 809 insertions(+), 7 deletions(-) create mode 100644 mobile/__tests__/LeaderboardScreen.test.tsx create mode 100644 mobile/src/screens/LeaderboardScreen.tsx diff --git a/mobile/__tests__/LeaderboardScreen.test.tsx b/mobile/__tests__/LeaderboardScreen.test.tsx new file mode 100644 index 00000000..bc334780 --- /dev/null +++ b/mobile/__tests__/LeaderboardScreen.test.tsx @@ -0,0 +1,241 @@ +/** + * The leaderboard renders the page the backend ranked and never re-sorts it. + * + * The trap worth a test is the medal: it belongs to a rank, not to a position in the + * page, so page two grows no medals and a search that turns up the leader still shows + * it as the leader. Ranks arrive absolute for exactly this reason. + * + * `@shared/core` is stubbed — its barrel drags the Solana runtime into jest. + */ + +import React from 'react'; +import { Text, TextInput, TouchableOpacity, View } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; + +const mockState = { + walletAddress: '0xAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaa' as string | null, + petEntries: [] as Record[], + playerEntries: [] as Record[], + total: 0, + isLoading: false, + error: null as Error | null, + rank: null as Record | null, +}; + +jest.mock('@shared/core', () => ({ + getRarityColor: () => '#ffffff', + shortAddress: (a: string) => `${a.slice(0, 6)}...${a.slice(-4)}`, + sameAccount: (a: string, b: string) => a.toLowerCase() === b.toLowerCase(), + useChainCapabilities: () => ({ + activeKind: 'ethereum', + walletAddress: mockState.walletAddress, + }), + useLeaderboard: ({ enabled }: { enabled: boolean }) => ({ + entries: enabled ? mockState.petEntries : [], + total: enabled ? mockState.total : 0, + pageSize: 20, + isLoading: mockState.isLoading, + error: mockState.error, + }), + usePlayerLeaderboard: ({ enabled }: { enabled: boolean }) => ({ + entries: enabled ? mockState.playerEntries : [], + total: enabled ? mockState.total : 0, + pageSize: 20, + isLoading: mockState.isLoading, + error: mockState.error, + }), + usePlayerRank: () => ({ rank: mockState.rank, isLoading: false }), +})); + +jest.mock('../src/components/PetArt', () => () => null); + +import LeaderboardScreen from '../src/screens/LeaderboardScreen'; + +const petEntry = (over: Record = {}) => ({ + rank: 1, + id: '1', + chain: 'ethereum', + owner: '0xBBbbBBbbBBbbBBbbBBbbBBbbBBbbBBbbBBbbBBbb', + name: 'caipet', + dna: '5565590272533216', + level: 3, + rarity: 1, + winCount: 4, + lossCount: 1, + asset: '', + ...over, +}); + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + // RN's Text nests a native element, so `children` holds instances rather + // than strings; the props are where the text actually is. + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' | '); + +/** + * Found by accessibility label rather than by serializing the subtree: a rendered pet + * carries a BigInt dna, which `JSON.stringify` refuses outright. + */ +const showPlayers = async (tree: ReactTestRenderer.ReactTestRenderer) => { + const tab = tree.root + .findAllByType(TouchableOpacity) + .find((node) => node.props.accessibilityLabel === 'Show Players board'); + await ReactTestRenderer.act(async () => tab!.props.onPress()); +}; + +/** Every row's border colour, in render order. Medals show up here. */ +const rowBorders = (tree: ReactTestRenderer.ReactTestRenderer): unknown[] => + tree.root + .findAllByType(View) + .map((node) => { + const style = node.props.style; + const flat = Array.isArray(style) ? Object.assign({}, ...style.filter(Boolean)) : style; + return flat?.borderColor; + }) + .filter(Boolean); + +beforeEach(() => { + mockState.walletAddress = '0xAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaa'; + mockState.petEntries = []; + mockState.playerEntries = []; + mockState.total = 0; + mockState.isLoading = false; + mockState.error = null; + mockState.rank = null; +}); + +describe('empty and loading states', () => { + it('tells a player with no battles that the board fills up, not that it is broken', async () => { + const tree = await render(); + expect(textOf(tree)).toContain('No battles on record yet'); + }); + + it('says nothing matched rather than reusing the no-battles copy', async () => { + const tree = await render(); + await ReactTestRenderer.act(async () => { + tree.root.findByType(TextInput).props.onChangeText('zzz'); + }); + // The 300 ms debounce has to elapse before the term reaches the query, and it + // has to do so in its own act: the effect that arms the timer only runs after + // the render the keystroke caused. + await ReactTestRenderer.act(async () => { + await new Promise((r) => setTimeout(r, 350)); + }); + expect(textOf(tree)).toContain('matches "zzz"'); + expect(textOf(tree)).not.toContain('No battles on record yet'); + }); + + it('reports an error instead of an empty board', async () => { + mockState.error = new Error('backend unreachable'); + const tree = await render(); + expect(textOf(tree)).toContain('backend unreachable'); + }); +}); + +describe('your standing', () => { + it('calls an unranked player unranked, which is a real state and not an error', async () => { + const tree = await render(); + expect(textOf(tree)).toContain('Unranked'); + }); + + it('shows the rank the backend gave, not one counted from the page', async () => { + mockState.rank = { rank: 42, owner: '0xAA', winCount: 7, lossCount: 3, petCount: 2 }; + const tree = await render(); + expect(textOf(tree)).toContain('#42'); + expect(textOf(tree)).toContain('7W 3L'); + }); +}); + +describe('ranking', () => { + it('medals by absolute rank, so page two grows none', async () => { + // Ranks 21-23: the first rows of page two, and nothing here is a medal. + mockState.petEntries = [21, 22, 23].map((rank) => petEntry({ rank, id: String(rank) })); + mockState.total = 60; + const tree = await render(); + + const medals = ['#ffd45e', '#c9d4e4', '#d08a52']; + expect(rowBorders(tree).filter((c) => medals.includes(c as string))).toHaveLength(0); + expect(textOf(tree)).toContain('21'); + }); + + it('medals the top three when they are the ones on screen', async () => { + mockState.petEntries = [1, 2, 3, 4].map((rank) => petEntry({ rank, id: String(rank) })); + mockState.total = 4; + const tree = await render(); + + const medals = ['#ffd45e', '#c9d4e4', '#d08a52']; + expect(rowBorders(tree).filter((c) => medals.includes(c as string))).toHaveLength(3); + }); + + it('renders rows in the order given, never re-sorted locally', async () => { + // Deliberately not in win order: the backend ranks on the merged record, so a + // local sort could only disagree with the rank printed beside each row. + mockState.petEntries = [ + petEntry({ rank: 1, id: '1', name: 'first', winCount: 2, lossCount: 0 }), + petEntry({ rank: 2, id: '2', name: 'second', winCount: 9, lossCount: 9 }), + ]; + mockState.total = 2; + const tree = await render(); + expect(textOf(tree).indexOf('first')).toBeLessThan(textOf(tree).indexOf('second')); + }); +}); + +describe('boards', () => { + it('starts on pets and switches to players', async () => { + mockState.petEntries = [petEntry({ name: 'caipet' })]; + mockState.playerEntries = [ + { + rank: 1, + owner: '0xCCccCCccCCccCCccCCccCCccCCccCCccCCccCCcc', + winCount: 5, + lossCount: 2, + petCount: 3, + }, + ]; + mockState.total = 1; + + const tree = await render(); + expect(textOf(tree)).toContain('caipet'); + + await showPlayers(tree); + + expect(textOf(tree)).toContain('3 pets'); + expect(textOf(tree)).not.toContain('caipet'); + }); + + it('marks the connected wallet on the player board', async () => { + mockState.playerEntries = [ + { + rank: 1, + owner: mockState.walletAddress!.toLowerCase(), + winCount: 1, + lossCount: 0, + petCount: 1, + }, + ]; + mockState.total = 1; + + const tree = await render(); + await showPlayers(tree); + + expect(textOf(tree)).toContain('you'); + }); +}); diff --git a/mobile/__tests__/accountSheet.test.tsx b/mobile/__tests__/accountSheet.test.tsx index a2937c02..8de931ea 100644 --- a/mobile/__tests__/accountSheet.test.tsx +++ b/mobile/__tests__/accountSheet.test.tsx @@ -29,6 +29,11 @@ const mockSignAndLogin = jest.fn(); const mockLogout = jest.fn(); const mockOpen = jest.fn(); const mockDisconnect = jest.fn(); +const mockNavigate = jest.fn(); + +jest.mock('@react-navigation/native', () => ({ + useNavigation: () => ({ navigate: mockNavigate }), +})); jest.mock('wagmi', () => ({ useAccount: () => ({ address: mockState.address, chainId: mockState.chainId }), @@ -166,23 +171,36 @@ describe('AccountSheet auth actions', () => { // Both close the sheet before acting, which unmounts the modal — so each gets // its own render rather than reusing a node list that is gone by then. + // + // Found by accessibility label, not by index: the sheet's action list grows as + // screens are added, and an index-based press silently retargets when it does. + const pressAction = async (tree: ReactTestRenderer.ReactTestRenderer, label: string) => { + const button = tree.root + .findAllByType(TouchableOpacity) + .find((node) => node.props.accessibilityLabel === label); + await ReactTestRenderer.act(async () => button!.props.onPress()); + }; + it('leaves wallet-level actions to AppKit', async () => { const tree = await render(); await openSheet(tree); - await ReactTestRenderer.act(async () => { - tree.root.findAllByType(TouchableOpacity)[2].props.onPress(); - }); + await pressAction(tree, 'Wallet'); expect(mockOpen).toHaveBeenCalled(); }); it('disconnects', async () => { const tree = await render(); await openSheet(tree); - await ReactTestRenderer.act(async () => { - tree.root.findAllByType(TouchableOpacity)[3].props.onPress(); - }); + await pressAction(tree, 'Disconnect'); expect(mockDisconnect).toHaveBeenCalled(); }); + + it('reaches the leaderboard, which has no tab of its own', async () => { + const tree = await render(); + await openSheet(tree); + await pressAction(tree, 'Leaderboard'); + expect(mockNavigate).toHaveBeenCalledWith('Leaderboard'); + }); }); describe('NativeBalance', () => { diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index 9c97e188..2a76ae5f 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -24,6 +24,7 @@ jest.mock('../src/screens/DefenseScreen', () => () => null); jest.mock('../src/screens/BreedScreen', () => () => null); jest.mock('../src/screens/MarriageScreen', () => () => null); jest.mock('../src/screens/BattleScreen', () => () => null); +jest.mock('../src/screens/LeaderboardScreen', () => () => null); jest.mock('../src/components/AppHeader', () => () => null); jest.mock('../src/screens/LandingScreen', () => { const { Text: RNText } = jest.requireActual('react-native'); @@ -79,7 +80,15 @@ describe('routes', () => { }); it('keeps the per-pet actions on the stack', () => { - expect(Object.keys(STACK_TITLES)).toEqual(['Marriage', 'Rename', 'Defense']); + // Leaderboard is on the stack for a different reason than the other three: it + // acts on no pet at all, but a five-slot tab bar has no room for a read-only + // screen without truncating the labels of the four that do. + expect(Object.keys(STACK_TITLES)).toEqual([ + 'Marriage', + 'Rename', + 'Defense', + 'Leaderboard', + ]); }); it('does not route the deferred features', () => { diff --git a/mobile/src/components/AccountSheet.tsx b/mobile/src/components/AccountSheet.tsx index efb20c57..c4251db9 100644 --- a/mobile/src/components/AccountSheet.tsx +++ b/mobile/src/components/AccountSheet.tsx @@ -10,11 +10,14 @@ import { useWindowDimensions, View, } from 'react-native'; +import { useNavigation } from '@react-navigation/native'; +import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { useAppKit } from '@reown/appkit-react-native'; import { useAccount } from 'wagmi'; import { useAuth } from '@shared/core'; import NativeBalance from './NativeBalance'; +import type { RootStackParamList } from '../navigation/routes'; import { neon, neonGlow } from '../theme/neon'; const truncate = (addr: string): string => `${addr.slice(0, 6)}...${addr.slice(-4)}`; @@ -36,6 +39,7 @@ const truncate = (addr: string): string => `${addr.slice(0, 6)}...${addr.slice(- export default function AccountSheet() { const { open, disconnect } = useAppKit(); const { address } = useAccount(); + const navigation = useNavigation>(); const { isAuthenticated, signAndLogin, logout, isSigning, isVerifying, isNonceLoading } = useAuth(); const [isOpen, setIsOpen] = useState(false); @@ -144,6 +148,20 @@ export default function AccountSheet() { { + setIsOpen(false); + navigation.navigate('Leaderboard'); + }} + > + Leaderboard + + + { setIsOpen(false); open(); @@ -154,6 +172,8 @@ export default function AccountSheet() { { setIsOpen(false); disconnect(); diff --git a/mobile/src/navigation/RootNavigator.tsx b/mobile/src/navigation/RootNavigator.tsx index 69f0eb56..8a95aea1 100644 --- a/mobile/src/navigation/RootNavigator.tsx +++ b/mobile/src/navigation/RootNavigator.tsx @@ -13,6 +13,7 @@ import BreedScreen from '../screens/BreedScreen'; import DefenseScreen from '../screens/DefenseScreen'; import GalleryScreen from '../screens/GalleryScreen'; import LandingScreen from '../screens/LandingScreen'; +import LeaderboardScreen from '../screens/LeaderboardScreen'; import LevelUpScreen from '../screens/LevelUpScreen'; import MarriageScreen from '../screens/MarriageScreen'; import RenameScreen from '../screens/RenameScreen'; @@ -41,6 +42,7 @@ const STACK_SCREENS = { Marriage: MarriageScreen, Rename: RenameScreen, Defense: DefenseScreen, + Leaderboard: LeaderboardScreen, } as const; /** diff --git a/mobile/src/navigation/routes.ts b/mobile/src/navigation/routes.ts index 0af209a8..ca362130 100644 --- a/mobile/src/navigation/routes.ts +++ b/mobile/src/navigation/routes.ts @@ -30,6 +30,12 @@ export type RootStackParamList = { Marriage: undefined; Rename: { petId?: string } | undefined; Defense: { petId?: string } | undefined; + /** + * Read-only, and reached from the account sheet rather than the tab bar. Frontend + * routes it as a seventh sidebar entry, which a five-slot bottom bar has no room + * for without truncating every label to fit a screen nobody opens mid-battle. + */ + Leaderboard: undefined; }; export type TabItem = { @@ -61,4 +67,5 @@ export const STACK_TITLES: Record = ({ standing }) => { + const rate = winRate(standing.winCount, standing.lossCount); + const medal = standing.rank <= MEDALS.length ? MEDALS[standing.rank - 1] : null; + const size = medal ? 52 : 40; + + return ( + + {standing.rank} + + + {standing.pet ? ( + + ) : ( + 👤 + )} + + + + + {standing.title} + + + {standing.sub} + {standing.isYou ? ' · you' : ''} + + + + + + + + {standing.winCount}W + {standing.lossCount}L + {rate == null ? '—' : `${rate}%`} + + + ); +}; + +/** + * Pets ranked by battle record, and their owners ranked by the same record summed. + * + * Read-only, so it composes the shared hooks directly and keeps its form state local + * rather than going through a controller hook. There is no multi-step flow here to + * model, which is the test that decides between the two shapes on both clients. + * + * The ranking is entirely the backend's. It ranks over the merged record + * (`pet_battle_progress` above the frozen `pet_roster` counters) inside the query that + * orders the rows, so this renders the page it is given and never re-sorts: a local + * sort could only reorder rows the server already picked, and would then disagree with + * the `rank` printed beside them. + */ +export default function LeaderboardScreen() { + const { activeKind, walletAddress } = useChainCapabilities(); + const [board, setBoard] = useState('pets'); + const [page, setPage] = useState(0); + const [term, setTerm] = useState(''); + + // 300 ms, matching frontend and `useSearchPets`: a round trip per keystroke against + // a ranked query is a lot of work to throw away, and a board is not a typeahead. + const [search, setSearch] = useState(''); + useEffect(() => { + const id = setTimeout(() => setSearch(term.trim()), 300); + return () => clearTimeout(id); + }, [term]); + + // A term that narrows the board also renumbers which page anything is on, so the + // reader has to be put back at the first one or a search can land on an empty page. + useEffect(() => setPage(0), [search, board]); + + const pets = useLeaderboard({ chain: activeKind, page, search, enabled: board === 'pets' }); + const players = usePlayerLeaderboard({ + chain: activeKind, + page, + search, + enabled: board === 'players', + }); + const { rank: yours } = usePlayerRank(activeKind); + + const active = board === 'pets' ? pets : players; + const lastPage = Math.max(0, Math.ceil(active.total / active.pageSize) - 1); + + // `sameAccount` normalizes by address shape, so this needs no chain branch and + // cannot merge two Solana pubkeys differing only in case. + const isYou = (owner: string) => sameAccount(owner, walletAddress ?? ''); + + /** Both boards flattened to one shape, so a single row renderer takes either. */ + const standings: Standing[] = useMemo( + () => + board === 'pets' + ? pets.entries.map((entry) => ({ + key: entry.id, + rank: entry.rank, + pet: { + id: entry.id, + chain: entry.chain, + assetKey: entry.asset || undefined, + dna: BigInt(entry.dna), + }, + title: entry.name, + sub: `Lv ${entry.level}`, + accent: getRarityColor(entry.rarity), + winCount: entry.winCount, + lossCount: entry.lossCount, + isYou: isYou(entry.owner), + })) + : players.entries.map((entry) => ({ + key: entry.owner, + rank: entry.rank, + pet: null, + title: shortAddress(entry.owner), + sub: `${entry.petCount} pet${entry.petCount === 1 ? '' : 's'}`, + accent: null, + winCount: entry.winCount, + lossCount: entry.lossCount, + isYou: isYou(entry.owner), + })), + // eslint-disable-next-line react-hooks/exhaustive-deps + [board, pets.entries, players.entries, walletAddress], + ); + + const header = ( + + Leaderboard + Ranked by wins, then by fewest losses + + + {BOARDS.map((option) => ( + setBoard(option.id)} + accessibilityRole="button" + accessibilityLabel={`Show ${option.label} board`} + accessibilityState={{ selected: board === option.id }} + activeOpacity={0.85} + > + + {option.label} + + + ))} + + + + + {/* + * Frontend keeps this in its sidebar, which mobile has no equivalent of. + * A null rank is unranked, a real state rather than an error: it is what a + * player who has never fought should be told. + */} + + Your standing + + {yours + ? `#${yours.rank} · ${yours.winCount}W ${yours.lossCount}L` + : 'Unranked. Win a battle to join the board.'} + + + + ); + + const body = active.error ? ( + {active.error.message} + ) : active.isLoading ? ( + + + + ) : active.total === 0 ? ( + + {search + ? `Nothing on the board matches "${search}".` + : 'No battles on record yet. Win one and the board fills up.'} + + ) : null; + + const first = page * active.pageSize + 1; + const last = Math.min(active.total, (page + 1) * active.pageSize); + + return ( + item.key} + renderItem={({ item }) => } + ListHeaderComponent={header} + ListEmptyComponent={body} + keyboardShouldPersistTaps="handled" + ListFooterComponent={ + body || active.total === 0 ? null : ( + + setPage(page - 1)} + disabled={page === 0} + accessibilityLabel="Previous page" + > + + + + + {first}–{last} of {active.total} + + + = lastPage && styles.pageBtnOff]} + onPress={() => setPage(page + 1)} + disabled={page >= lastPage} + accessibilityLabel="Next page" + > + + + + ) + } + /> + ); +} + +const styles = StyleSheet.create({ + root: { + flex: 1, + backgroundColor: neon.bgDeep, + }, + content: { + padding: 16, + paddingBottom: 32, + }, + title: { + fontSize: 22, + fontWeight: '800', + color: neon.text, + letterSpacing: 0.5, + textShadowColor: neon.cyan, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 10, + }, + subtitle: { + fontSize: 14, + color: neon.textMuted, + marginTop: 6, + marginBottom: 16, + }, + tabs: { + flexDirection: 'row', + backgroundColor: neon.bgPanel, + borderRadius: 12, + padding: 4, + borderWidth: 1, + borderColor: neon.border, + }, + tab: { + flex: 1, + paddingVertical: 10, + alignItems: 'center', + borderRadius: 9, + }, + tabActive: { + backgroundColor: neon.bgCard, + ...neonGlow(neon.cyan, 8, 0.3), + }, + tabText: { + fontSize: 14, + fontWeight: '700', + color: neon.textDim, + }, + tabTextActive: { + color: neon.cyan, + }, + search: { + marginTop: 12, + backgroundColor: neon.bgInput, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + paddingHorizontal: 14, + paddingVertical: 10, + fontSize: 14, + color: neon.text, + }, + yourRank: { + marginTop: 12, + marginBottom: 16, + backgroundColor: neon.bgPanel, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.borderMagenta, + padding: 12, + }, + yourRankLabel: { + fontSize: 11, + fontWeight: '800', + color: neon.textDim, + letterSpacing: 1, + textTransform: 'uppercase', + }, + yourRankValue: { + marginTop: 4, + fontSize: 14, + fontWeight: '700', + color: neon.magenta, + }, + row: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: neon.bgCard, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + padding: 10, + marginBottom: 8, + }, + rowYou: { + backgroundColor: neon.bgPanel, + borderColor: neon.magenta, + }, + rank: { + width: 34, + fontSize: 18, + fontWeight: '800', + color: neon.textMuted, + textAlign: 'center', + }, + avatar: { + alignItems: 'center', + justifyContent: 'center', + marginRight: 10, + }, + identity: { + flex: 1, + minWidth: 0, + }, + name: { + fontSize: 15, + fontWeight: '800', + color: neon.text, + }, + sub: { + fontSize: 12, + color: neon.textMuted, + marginTop: 2, + }, + meter: { + marginTop: 6, + height: 4, + borderRadius: 2, + backgroundColor: neon.bgInput, + overflow: 'hidden', + }, + meterFill: { + height: 4, + borderRadius: 2, + backgroundColor: neon.cyan, + }, + record: { + alignItems: 'flex-end', + marginLeft: 8, + }, + wins: { + fontSize: 13, + fontWeight: '800', + color: neon.success, + }, + losses: { + fontSize: 13, + fontWeight: '700', + color: neon.danger, + }, + rate: { + fontSize: 11, + color: neon.textDim, + marginTop: 2, + }, + loading: { + paddingVertical: 40, + alignItems: 'center', + }, + empty: { + marginTop: 8, + fontSize: 14, + lineHeight: 20, + color: neon.textMuted, + }, + error: { + marginTop: 8, + fontSize: 13, + color: neon.danger, + }, + pager: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + marginTop: 8, + }, + pageBtn: { + width: 44, + height: 40, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: neon.bgCard, + borderWidth: 1, + borderColor: neon.cyan, + }, + pageBtnOff: { + opacity: 0.35, + }, + pageBtnText: { + color: neon.cyan, + fontSize: 18, + fontWeight: '800', + }, + pageLabel: { + fontSize: 13, + color: neon.textMuted, + fontWeight: '700', + }, +}); From 5c83b14dba176985628b3bfe69a25e831ebc5748 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 18:54:31 -0400 Subject: [PATCH 35/99] feat(mobile): find a marriage partner by search instead of by id --- mobile/__tests__/MarriageScreen.test.tsx | 52 ++++- mobile/__tests__/PetSearchField.test.tsx | 182 +++++++++++++++++ mobile/bridge-to-base-sepolia.mjs | 58 ------ mobile/src/components/PetSearchField.tsx | 242 +++++++++++++++++++++++ mobile/src/screens/MarriageScreen.tsx | 24 ++- 5 files changed, 483 insertions(+), 75 deletions(-) create mode 100644 mobile/__tests__/PetSearchField.test.tsx delete mode 100644 mobile/bridge-to-base-sepolia.mjs create mode 100644 mobile/src/components/PetSearchField.tsx diff --git a/mobile/__tests__/MarriageScreen.test.tsx b/mobile/__tests__/MarriageScreen.test.tsx index f64fc05b..1c7ab3b4 100644 --- a/mobile/__tests__/MarriageScreen.test.tsx +++ b/mobile/__tests__/MarriageScreen.test.tsx @@ -42,6 +42,8 @@ const mockState = { roster: [{ id: '9', name: 'Luna' }] as { id: string; name: string }[], /** What a direct spouse lookup returns when the roster map has no answer. */ fetchedSpouse: {} as { name?: string; level?: number }, + /** What `searchPets` returns for the partner field; someone else's pets. */ + searchResults: [] as { id: string; name: string; level: number; dna: bigint }[], }; /** Every `useSpousePet` call the card made, to check it skips when it can. */ @@ -65,6 +67,14 @@ jest.mock('@shared/core', () => ({ walletAddress: '0xme', }), useAllPets: () => ({ pets: mockState.roster }), + useSearchPets: (query: string) => ({ + results: query.trim() ? mockState.searchResults : [], + isLoading: false, + error: null, + refetch: jest.fn(), + }), + getPetAvatar: () => '🐾', + petArtUrl: () => null, useIncomingProposals: (...args: unknown[]) => { mockIncomingArgs(...args); return { proposals: mockState.proposals, isLoading: mockState.proposalsLoading }; @@ -149,6 +159,21 @@ const type = async (tree: ReactTestRenderer.ReactTestRenderer, value: string) => }); }; +/** + * Pick the partner the way a player does now: search, then tap a result. + * + * This screen used to take the partner's numeric id typed straight in, so these tests + * typed one. A proposal still names an exact pet; what changed is that finding it no + * longer requires already knowing its id. + */ +const choosePartner = async (tree: ReactTestRenderer.ReactTestRenderer, name: string) => { + await type(tree, name); + const row = tree.root + .findAllByType(TouchableOpacity) + .find((node) => node.props.accessibilityLabel === `Choose ${name}`); + await ReactTestRenderer.act(async () => row!.props.onPress()); +}; + beforeEach(() => { mockState.pets = [pet()]; mockState.kind = 'evm'; @@ -157,6 +182,7 @@ beforeEach(() => { mockState.isMarried = false; mockState.roster = [{ id: '9', name: 'Luna' }]; mockState.fetchedSpouse = {}; + mockState.searchResults = [{ id: '42', name: 'Nia', level: 3, dna: 1n }]; mockSpouseLookups.length = 0; jest.clearAllMocks(); }); @@ -182,18 +208,36 @@ describe('MarriageScreen', () => { expect(mockIncomingArgs).toHaveBeenCalledWith('evm', ['1', '2']); }); - it('sends a proposal for the chosen pet and typed partner id', async () => { + it('sends a proposal for the chosen pet and the partner found by search', async () => { const tree = await render(); await pressWith(tree, 'Rex'); - await type(tree, ' 42 '); + await choosePartner(tree, 'Nia'); await pressWith(tree, 'Send Proposal'); expect(mockMutations.propose).toHaveBeenCalledWith({ petIdA: '1', petIdB: '42' }); }); + it('keeps the player’s own pick out of the partner results', async () => { + // Marrying a pet to itself is not a proposal anyone means to send, and the + // search covers the whole roster, own pets included. + mockState.searchResults = [ + { id: '1', name: 'Rex', level: 2, dna: 1n }, + { id: '42', name: 'Nia', level: 3, dna: 1n }, + ]; + const tree = await render(); + await pressWith(tree, 'Rex'); + await type(tree, 'e'); + + const labels = tree.root + .findAllByType(TouchableOpacity) + .map((node) => node.props.accessibilityLabel); + expect(labels).toContain('Choose Nia'); + expect(labels).not.toContain('Choose Rex'); + }); + it('refreshes contract reads after a write, or every row shows stale state', async () => { const tree = await render(); await pressWith(tree, 'Rex'); - await type(tree, '42'); + await choosePartner(tree, 'Nia'); await pressWith(tree, 'Send Proposal'); expect(mockRefetch).toHaveBeenCalled(); const keys = mockInvalidate.mock.calls.map((c) => c[0].queryKey[0]); @@ -206,7 +250,7 @@ describe('MarriageScreen', () => { mockMutations.propose.mockRejectedValueOnce(new Error('reverted')); const tree = await render(); await pressWith(tree, 'Rex'); - await type(tree, '42'); + await choosePartner(tree, 'Nia'); await pressWith(tree, 'Send Proposal'); expect(mockNotify).toHaveBeenCalledWith( 'Marriage action failed', diff --git a/mobile/__tests__/PetSearchField.test.tsx b/mobile/__tests__/PetSearchField.test.tsx new file mode 100644 index 00000000..e608aa3e --- /dev/null +++ b/mobile/__tests__/PetSearchField.test.tsx @@ -0,0 +1,182 @@ +/** + * Finding another player's pet by name, rather than typing its id from memory. + * + * The states worth pinning are the ones that look alike and are not: an idle field + * showing nothing, a searched field that matched nothing, and a failed request. Only + * the middle one should say "no pets match". + * + * `@shared/core` is stubbed — its barrel drags the Solana runtime into jest. + */ + +import React from 'react'; +import { Text, TextInput, TouchableOpacity } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; + +const mockState = { + results: [] as { id: string; name: string; level: number; dna: bigint }[], + isLoading: false, + error: null as Error | null, +}; + +const mockSearchArgs = jest.fn(); + +jest.mock('@shared/core', () => ({ + useSearchPets: (query: string, options: unknown) => { + mockSearchArgs(query, options); + return { + results: query.trim() ? mockState.results : [], + isLoading: mockState.isLoading, + error: mockState.error, + refetch: jest.fn(), + }; + }, +})); + +jest.mock('../src/components/PetArt', () => () => null); + +import PetSearchField from '../src/components/PetSearchField'; + +const onChange = jest.fn(); + +const render = async (props: Partial> = {}) => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create( + , + ); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' | '); + +const type = async (tree: ReactTestRenderer.ReactTestRenderer, value: string) => { + await ReactTestRenderer.act(async () => { + tree.root.findByType(TextInput).props.onChangeText(value); + }); +}; + +const labels = (tree: ReactTestRenderer.ReactTestRenderer): unknown[] => + tree.root.findAllByType(TouchableOpacity).map((node) => node.props.accessibilityLabel); + +beforeEach(() => { + mockState.results = [{ id: '42', name: 'Nia', level: 3, dna: 1n }]; + mockState.isLoading = false; + mockState.error = null; + jest.clearAllMocks(); +}); + +describe('states that look alike', () => { + it('shows nothing at all before anything is typed', async () => { + const tree = await render(); + expect(textOf(tree)).not.toContain('No pets match'); + expect(labels(tree)).toHaveLength(0); + }); + + it('says nothing matched only once something was searched for', async () => { + mockState.results = []; + const tree = await render(); + await type(tree, 'zzz'); + expect(textOf(tree)).toContain('No pets match'); + }); + + it('treats an all-spaces term as idle, not as a miss', async () => { + mockState.results = []; + const tree = await render(); + await type(tree, ' '); + expect(textOf(tree)).not.toContain('No pets match'); + }); + + it('reports an error rather than claiming nothing matched', async () => { + mockState.error = new Error('backend unreachable'); + const tree = await render(); + await type(tree, 'nia'); + expect(textOf(tree)).toContain('backend unreachable'); + expect(textOf(tree)).not.toContain('No pets match'); + }); +}); + +describe('choosing', () => { + it('reports the chosen pet id and shows it instead of the field', async () => { + const tree = await render(); + await type(tree, 'nia'); + + const row = tree.root + .findAllByType(TouchableOpacity) + .find((node) => node.props.accessibilityLabel === 'Choose Nia'); + await ReactTestRenderer.act(async () => row!.props.onPress()); + + expect(onChange).toHaveBeenCalledWith('42'); + expect(textOf(tree)).toContain('Nia'); + expect(textOf(tree)).toContain('#42'); + expect(tree.root.findAllByType(TextInput)).toHaveLength(0); + }); + + it('drops excluded ids, so a pet cannot be proposed to itself', async () => { + mockState.results = [ + { id: '1', name: 'Rex', level: 2, dna: 1n }, + { id: '42', name: 'Nia', level: 3, dna: 1n }, + ]; + const tree = await render({ excludeIds: ['1'] }); + await type(tree, 'e'); + + expect(labels(tree)).toContain('Choose Nia'); + expect(labels(tree)).not.toContain('Choose Rex'); + }); + + it('resets when the parent clears the value after a successful proposal', async () => { + const tree = await render(); + await type(tree, 'nia'); + const row = tree.root + .findAllByType(TouchableOpacity) + .find((node) => node.props.accessibilityLabel === 'Choose Nia'); + await ReactTestRenderer.act(async () => row!.props.onPress()); + expect(tree.root.findAllByType(TextInput)).toHaveLength(0); + + // The parent owns the value: it stores what onChange reported, then clears it + // once the proposal lands. Both halves have to be replayed or the clear is + // indistinguishable from the initial empty render. + await ReactTestRenderer.act(async () => { + tree.update(); + }); + await ReactTestRenderer.act(async () => { + tree.update(); + }); + + // Back to a searchable field rather than still naming a pet it no longer reports. + expect(tree.root.findAllByType(TextInput)).toHaveLength(1); + expect(textOf(tree)).not.toContain('#42'); + }); +}); + +describe('query wiring', () => { + it('stops searching once a pet is chosen, so the list cannot reopen under it', async () => { + const tree = await render(); + await type(tree, 'nia'); + const row = tree.root + .findAllByType(TouchableOpacity) + .find((node) => node.props.accessibilityLabel === 'Choose Nia'); + await ReactTestRenderer.act(async () => row!.props.onPress()); + + const last = mockSearchArgs.mock.calls.at(-1); + expect((last?.[1] as { enabled: boolean }).enabled).toBe(false); + }); + + it('passes the chain through, since a proposal cannot cross chains', async () => { + await render({ chain: 'solana' }); + const last = mockSearchArgs.mock.calls.at(-1); + expect((last?.[1] as { chain: string }).chain).toBe('solana'); + }); +}); diff --git a/mobile/bridge-to-base-sepolia.mjs b/mobile/bridge-to-base-sepolia.mjs deleted file mode 100644 index 44ce8deb..00000000 --- a/mobile/bridge-to-base-sepolia.mjs +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Bridge Sepolia ETH to Base Sepolia by sending to the OP-stack L1StandardBridge. - * - * The bridge's `receive()` deposits to the same address on L2 when the sender is - * an EOA, so a plain value transfer is the whole operation. Addresses come from - * viem's chain registry rather than being hardcoded here. - * - * Run from the repo root: - * node # dry run, prints what it would do - * node --send # actually sends - */ -import { readFileSync } from 'node:fs'; -import { createWalletClient, createPublicClient, http, parseEther, formatEther } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { sepolia, baseSepolia } from 'viem/chains'; - -const AMOUNT = process.env.BRIDGE_AMOUNT ?? '0.05'; -const SEND = process.argv.includes('--send'); - -// Read PRIVATE_KEY without importing the whole env or printing it. -const envText = readFileSync('contracts/ethereum/.env', 'utf8'); -const pkLine = envText.split(/\r?\n/).find((l) => l.startsWith('PRIVATE_KEY=')); -if (!pkLine) throw new Error('PRIVATE_KEY not found in contracts/ethereum/.env'); -const rawKey = pkLine.slice('PRIVATE_KEY='.length).trim().replace(/^["']|["']$/g, ''); -const key = rawKey.startsWith('0x') ? rawKey : `0x${rawKey}`; - -const account = privateKeyToAccount(key); - -// viem ships Base Sepolia's L1 contracts keyed by their source chain (Sepolia). -const bridge = baseSepolia.contracts.l1StandardBridge[sepolia.id].address; - -const l1 = createPublicClient({ chain: sepolia, transport: http('https://ethereum-sepolia-rpc.publicnode.com') }); -const l2 = createPublicClient({ chain: baseSepolia, transport: http('https://sepolia.base.org') }); -const wallet = createWalletClient({ account, chain: sepolia, transport: http('https://ethereum-sepolia-rpc.publicnode.com') }); - -const [before, l2Before] = await Promise.all([ - l1.getBalance({ address: account.address }), - l2.getBalance({ address: account.address }), -]); - -console.log(`account: ${account.address}`); -console.log(`sepolia: ${formatEther(before)} ETH`); -console.log(`base sepolia: ${formatEther(l2Before)} ETH`); -console.log(`bridge target: ${bridge}`); -console.log(`amount: ${AMOUNT} ETH`); - -if (!SEND) { - console.log('\nDry run. Re-run with --send to bridge.'); - process.exit(0); -} - -const hash = await wallet.sendTransaction({ to: bridge, value: parseEther(AMOUNT) }); -console.log(`\nL1 tx: ${hash}`); -const receipt = await l1.waitForTransactionReceipt({ hash }); -console.log(`L1 confirmed in block ${receipt.blockNumber} (${receipt.status})`); -console.log('\nDeposit usually lands on Base Sepolia within 1-3 minutes. Poll with:'); -console.log(` curl -sS -X POST https://sepolia.base.org -H 'content-type: application/json' \\`); -console.log(` --data '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["${account.address}","latest"]}'`); diff --git a/mobile/src/components/PetSearchField.tsx b/mobile/src/components/PetSearchField.tsx new file mode 100644 index 00000000..2b4253ed --- /dev/null +++ b/mobile/src/components/PetSearchField.tsx @@ -0,0 +1,242 @@ +import React, { useEffect, useState } from 'react'; +import { + ActivityIndicator, + StyleSheet, + Text, + TextInput, + TouchableOpacity, + View, +} from 'react-native'; +import { useSearchPets, type OpponentPet, type PetChain } from '@shared/core'; + +import PetArt from './PetArt'; +import { neon } from '../theme/neon'; + +type Props = { + chain: PetChain | null; + /** Selected pet id, owned by the caller. Clearing it resets this field. */ + value: string; + onChange: (petId: string) => void; + /** Pet ids to keep out of the results, e.g. the pet the player already picked. */ + excludeIds?: string[]; + placeholder?: string; + disabled?: boolean; +}; + +/** + * Find another player's pet by name or id. + * + * The mobile counterpart of frontend's `PetSearchDropdown`, and it exists for the same + * reason: a marriage proposal names an exact pet, and until now this screen asked the + * player to type its numeric id from memory. That works only if the two players are + * already talking somewhere else. + * + * Results render inline rather than in an overlay. Frontend portals its dropdown to + * escape a clipping ancestor, which is a CSS problem React Native does not have, and an + * absolutely positioned list inside a `ScrollView` would be clipped by it anyway. + * + * Plain mapped views rather than a `FlatList`: this is at most ten rows, and a + * virtualized list nested in a `ScrollView` warns and loses its own scrolling. + * + * The 300 ms debounce lives in `useSearchPets`, so typing here costs one request per + * pause rather than one per keystroke. + */ +export default function PetSearchField({ + chain, + value, + onChange, + excludeIds = [], + placeholder = 'Search by name or id', + disabled = false, +}: Props) { + const [text, setText] = useState(''); + const [selected, setSelected] = useState(null); + + // The parent clears `value` after a successful proposal, which has to clear the + // chosen pet here too or the field keeps showing someone it no longer reports. + useEffect(() => { + if (!value) { + setSelected(null); + setText(''); + } + }, [value]); + + const { results, isLoading, error } = useSearchPets(text, { + chain, + enabled: !disabled && !selected, + }); + + const shown = excludeIds.length + ? results.filter((pet) => !excludeIds.includes(pet.id)) + : results; + + const choose = (pet: OpponentPet) => { + setSelected(pet); + setText(''); + onChange(pet.id); + }; + + const clear = () => { + setSelected(null); + onChange(''); + }; + + if (selected) { + return ( + + + + + {selected.name} + + + #{selected.id} · Lv {selected.level} + + + + × + + + ); + } + + // A trimmed term is what the hook actually queries on, so the states below have to + // agree with it or an all-spaces term reads as "no matches" rather than as idle. + const term = text.trim(); + + return ( + + + + {error ? {error.message} : null} + + {term.length > 0 && !error ? ( + + {isLoading && shown.length === 0 ? ( + + + + ) : shown.length === 0 ? ( + No pets match “{term}”. + ) : ( + shown.map((pet) => ( + choose(pet)} + disabled={disabled} + activeOpacity={0.85} + accessibilityRole="button" + accessibilityLabel={`Choose ${pet.name}`} + > + + + + {pet.name} + + + #{pet.id} · Lv {pet.level} + + + + )) + )} + + ) : null} + + ); +} + +const styles = StyleSheet.create({ + input: { + backgroundColor: neon.bgInput, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + paddingHorizontal: 14, + paddingVertical: 10, + fontSize: 15, + color: neon.text, + }, + results: { + marginTop: 8, + borderWidth: 1, + borderColor: neon.border, + borderRadius: 12, + backgroundColor: neon.bgPanel, + overflow: 'hidden', + }, + status: { + padding: 14, + fontSize: 13, + color: neon.textMuted, + textAlign: 'center', + }, + result: { + flexDirection: 'row', + alignItems: 'center', + padding: 10, + borderBottomWidth: StyleSheet.hairlineWidth, + borderBottomColor: neon.border, + }, + resultBody: { + flex: 1, + marginLeft: 10, + minWidth: 0, + }, + resultName: { + fontSize: 15, + fontWeight: '700', + color: neon.text, + }, + resultSub: { + fontSize: 12, + color: neon.textMuted, + marginTop: 2, + }, + selected: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: neon.bgCard, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.cyan, + padding: 10, + }, + selectedBody: { + flex: 1, + marginLeft: 10, + minWidth: 0, + }, + selectedName: { + fontSize: 15, + fontWeight: '800', + color: neon.cyan, + }, + selectedSub: { + fontSize: 12, + color: neon.textMuted, + marginTop: 2, + }, + clear: { + fontSize: 24, + color: neon.magenta, + paddingHorizontal: 6, + }, +}); diff --git a/mobile/src/screens/MarriageScreen.tsx b/mobile/src/screens/MarriageScreen.tsx index b0d18f02..0fcc5977 100644 --- a/mobile/src/screens/MarriageScreen.tsx +++ b/mobile/src/screens/MarriageScreen.tsx @@ -5,12 +5,12 @@ import { ScrollView, StyleSheet, Text, - TextInput, TouchableOpacity, View, } from 'react-native'; import PetPicker from '../components/PetPicker'; +import PetSearchField from '../components/PetSearchField'; import { useMarriagePanel } from '../hooks/marriage/useMarriagePanel'; import MarriageCard from './parts/MarriageCard'; import { neon, neonGlow } from '../theme/neon'; @@ -18,10 +18,10 @@ import { neon, neonGlow } from '../theme/neon'; /** * Marriage, as a pure view over `useMarriagePanel`. * - * Frontend picks the partner's pet with a `PetSearchDropdown` backed by the - * `searchPets` query. Mobile takes the id directly: the dropdown is a component - * and a query of its own, and a proposal needs an exact pet either way. Worth - * revisiting if players turn out not to know each other's ids. + * The partner is chosen with `PetSearchField`, mobile's answer to frontend's + * `PetSearchDropdown` over the same `searchPets` query. This screen used to ask for + * the partner's numeric id outright, which only works between two players already + * talking somewhere else. */ export default function MarriageScreen() { const panel = useMarriagePanel(); @@ -79,15 +79,13 @@ export default function MarriageScreen() { disabled={panel.busy} emptyHint="No pets on this chain yet." /> - Partner's pet id - Partner's pet + Date: Tue, 11 Aug 2026 19:13:51 -0400 Subject: [PATCH 36/99] feat(mobile): add inventory and equipment --- mobile/__tests__/EquipScreen.test.tsx | 194 +++++++++ mobile/__tests__/InventoryScreen.test.tsx | 203 +++++++++ mobile/__tests__/navigation.test.tsx | 8 +- mobile/src/components/AccountSheet.tsx | 12 + mobile/src/components/PetCard.tsx | 14 +- mobile/src/components/PetList.tsx | 3 + mobile/src/hooks/pet-gallery/usePetGallery.ts | 1 + mobile/src/navigation/RootNavigator.tsx | 4 + mobile/src/navigation/routes.ts | 11 +- mobile/src/screens/EquipScreen.tsx | 316 ++++++++++++++ mobile/src/screens/GalleryScreen.tsx | 2 + mobile/src/screens/InventoryScreen.tsx | 391 ++++++++++++++++++ 12 files changed, 1155 insertions(+), 4 deletions(-) create mode 100644 mobile/__tests__/EquipScreen.test.tsx create mode 100644 mobile/__tests__/InventoryScreen.test.tsx create mode 100644 mobile/src/screens/EquipScreen.tsx create mode 100644 mobile/src/screens/InventoryScreen.tsx diff --git a/mobile/__tests__/EquipScreen.test.tsx b/mobile/__tests__/EquipScreen.test.tsx new file mode 100644 index 00000000..12513ab3 --- /dev/null +++ b/mobile/__tests__/EquipScreen.test.tsx @@ -0,0 +1,194 @@ +/** + * Gearing a pet (roadmap section 4). + * + * Three slots are always drawn, filled or not: an empty slot is information, and + * rendering only what is equipped makes a bare pet look like a pet with no slots. + * + * The choices per slot come from the bag rather than a second query, and the filter is + * the part worth pinning: a consumable, a slotless item and a spent stack all have to + * stay out, or the player is offered something the contract will reject. + * + * `@shared/core` is stubbed — its barrel drags the Solana runtime into jest. + */ + +import React from 'react'; +import { Text, TouchableOpacity } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; + +const gear = (over: Record = {}) => ({ + itemType: '10', + key: 'rusty_dagger', + category: 'equipment', + slot: 0, + rarity: 1, + effect: { kind: 'stat_bonus', hp: 0, atk: 4, def: 0, int: 0, mdef: 0 }, + name: 'Rusty Dagger', + description: 'A dagger.', + ...over, +}); + +const mockState = { + entries: [] as { item: ReturnType; quantity: string }[], + bySlot: new Map }>(), + slotsLoading: false, + canEquip: true, + isConnected: true, +}; + +const mockEquip = jest.fn(); +const mockUnequip = jest.fn(); +const mockNotify = jest.fn(); + +jest.mock('@shared/core', () => ({ + SLOT: { weapon: 0, armor: 1, trinket: 2 }, + useChainCapabilities: () => ({ + activeKind: 'ethereum', + isConnected: mockState.isConnected, + }), + usePetList: () => ({ pets: [{ id: '1', name: 'Rex', level: 2 }] }), + useInventory: () => ({ entries: mockState.entries }), + usePetEquipment: () => ({ + equipped: [...mockState.bySlot.values()], + bySlot: mockState.bySlot, + isLoading: mockState.slotsLoading, + isSuccess: true, + error: null, + refetch: jest.fn(), + }), + useEquipItem: () => ({ + canEquip: mockState.canEquip, + equip: mockEquip, + unequip: mockUnequip, + equipLifecycle: { error: null }, + unequipLifecycle: { error: null }, + isPending: false, + }), + getRarityColor: () => '#ffffff', + describeItemEffect: () => '+4 ATK', +})); + +jest.mock('../src/hooks/useNotifyError', () => ({ useNotifyError: () => mockNotify })); +jest.mock('../src/hooks/useTxErrorToast', () => ({ useTxErrorToast: () => {} })); +jest.mock('@react-navigation/native', () => ({ useRoute: () => ({ params: { petId: '1' } }) })); + +import EquipScreen from '../src/screens/EquipScreen'; + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' | '); + +const press = async (tree: ReactTestRenderer.ReactTestRenderer, label: string) => { + const node = tree.root + .findAllByType(TouchableOpacity) + .find((n) => n.props.accessibilityLabel === label); + await ReactTestRenderer.act(async () => node!.props.onPress()); +}; + +const labels = (tree: ReactTestRenderer.ReactTestRenderer): unknown[] => + tree.root.findAllByType(TouchableOpacity).map((n) => n.props.accessibilityLabel); + +beforeEach(() => { + mockState.entries = [{ item: gear(), quantity: '1' }]; + mockState.bySlot = new Map(); + mockState.slotsLoading = false; + mockState.canEquip = true; + mockState.isConnected = true; + jest.clearAllMocks(); +}); + +describe('slots', () => { + it('draws all three whether filled or not', async () => { + const tree = await render(); + const rendered = textOf(tree); + expect(rendered).toContain('Weapon'); + expect(rendered).toContain('Armor'); + expect(rendered).toContain('Trinket'); + }); + + it('offers removal for a filled slot and nothing to equip into it', async () => { + mockState.bySlot = new Map([[0, { slot: 0, item: gear() }]]); + const tree = await render(); + expect(labels(tree)).toContain('Unequip Weapon'); + expect(labels(tree)).not.toContain('Equip Weapon'); + }); + + it('says an empty slot has nothing that fits, distinct from having no slot', async () => { + mockState.entries = []; + const tree = await render(); + expect(textOf(tree)).toContain('nothing in the bag fits this slot'); + }); +}); + +describe('what can go in a slot', () => { + it('keeps consumables and slotless items out', async () => { + mockState.entries = [ + { item: gear(), quantity: '1' }, + { item: gear({ itemType: '11', name: 'Potion', category: 'consumable', slot: null }), quantity: '5' }, + { item: gear({ itemType: '12', name: 'Badge', category: 'collectible', slot: null }), quantity: '1' }, + ]; + const tree = await render(); + expect(labels(tree)).toContain('Choose Rusty Dagger'); + expect(labels(tree)).not.toContain('Choose Potion'); + expect(labels(tree)).not.toContain('Choose Badge'); + }); + + it('keeps a spent stack out, since zero is written rather than deleted', async () => { + mockState.entries = [{ item: gear(), quantity: '0' }]; + const tree = await render(); + expect(labels(tree)).not.toContain('Choose Rusty Dagger'); + expect(textOf(tree)).toContain('nothing in the bag fits this slot'); + }); +}); + +describe('committing', () => { + it('equips the chosen item into its slot', async () => { + const tree = await render(); + await press(tree, 'Choose Rusty Dagger'); + await press(tree, 'Equip Weapon'); + expect(mockEquip).toHaveBeenCalledWith(0, '10'); + }); + + it('unequips by slot', async () => { + mockState.bySlot = new Map([[0, { slot: 0, item: gear() }]]); + const tree = await render(); + await press(tree, 'Unequip Weapon'); + expect(mockUnequip).toHaveBeenCalledWith(0); + }); + + it('refuses while disconnected rather than sending a call that cannot be signed', async () => { + mockState.isConnected = false; + const tree = await render(); + await press(tree, 'Choose Rusty Dagger'); + await press(tree, 'Equip Weapon'); + expect(mockEquip).not.toHaveBeenCalled(); + expect(mockNotify).toHaveBeenCalledWith( + 'Connect your wallet first', + undefined, + 'equip-validation', + ); + }); + + it('says why on a chain with no item contract, rather than showing a dead button', async () => { + mockState.canEquip = false; + const tree = await render(); + expect(textOf(tree)).toContain('no item contract'); + }); +}); diff --git a/mobile/__tests__/InventoryScreen.test.tsx b/mobile/__tests__/InventoryScreen.test.tsx new file mode 100644 index 00000000..42889b40 --- /dev/null +++ b/mobile/__tests__/InventoryScreen.test.tsx @@ -0,0 +1,203 @@ +/** + * The bag, and the two things about it that are easy to get wrong. + * + * Quantity zero is a value rather than an absence: `indexer-go` resumes from an + * `updatedAt` watermark, so a spent stack is written as `quantity 0` instead of being + * deleted. A row reading zero has to disappear from the bag, not show as a held item. + * + * A pending drop is not an item yet. Nothing on chain reflects one until its claim + * lands, so it cannot be offered anywhere an item can be spent. + * + * `@shared/core` is stubbed — its barrel drags the Solana runtime into jest. + */ + +import React from 'react'; +import { Text, TouchableOpacity } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; + +const item = (over: Record = {}) => ({ + itemType: '1', + key: 'xp_potion_i', + category: 'consumable', + slot: null, + rarity: 1, + effect: { kind: 'grant_xp', amount: 50 }, + name: 'XP Potion', + description: 'A small potion.', + ...over, +}); + +const mockState = { + entries: [] as { item: ReturnType; quantity: string }[], + pending: [] as Record[], + isLoading: false, + error: null as Error | null, + claimingId: null as string | null, +}; + +const mockClaim = jest.fn(); +const mockSpend = jest.fn(); +const mockRefetch = jest.fn(); +const mockNotify = jest.fn(); + +jest.mock('@shared/core', () => ({ + useChainCapabilities: () => ({ activeKind: 'ethereum', isConnected: true }), + useInventory: () => ({ + entries: mockState.entries, + isLoading: mockState.isLoading, + error: mockState.error, + refetch: mockRefetch, + }), + usePendingItems: () => ({ + pending: mockState.pending, + isLoading: false, + error: null, + claim: mockClaim, + claimingId: mockState.claimingId, + claimError: null, + }), + usePetList: () => ({ pets: [{ id: '1', name: 'Rex', level: 2 }] }), + useSpendItem: () => ({ spend: mockSpend, isPending: false, error: null, reset: jest.fn() }), + getRarityColor: () => '#ffffff', + describeItemEffect: () => 'Grants 50 XP', + explainItem: () => 'Used on one of your pets.', + itemStats: () => [{ label: 'XP', value: 50 }], + SLOT_NAMES: { 0: 'weapon', 1: 'armor', 2: 'trinket' }, +})); + +jest.mock('../src/hooks/useNotifyError', () => ({ useNotifyError: () => mockNotify })); + +import InventoryScreen from '../src/screens/InventoryScreen'; + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' | '); + +const press = async (tree: ReactTestRenderer.ReactTestRenderer, label: string) => { + const node = tree.root + .findAllByType(TouchableOpacity) + .find((n) => n.props.accessibilityLabel === label); + await ReactTestRenderer.act(async () => node!.props.onPress()); +}; + +beforeEach(() => { + mockState.entries = [{ item: item(), quantity: '3' }]; + mockState.pending = []; + mockState.isLoading = false; + mockState.error = null; + mockState.claimingId = null; + mockSpend.mockResolvedValue({ burnTxHash: '0x', level: 3, xp: 120, readyAt: 0, leveledUp: true }); + jest.clearAllMocks(); +}); + +describe('the bag', () => { + it('lists a held stack with its quantity', async () => { + const tree = await render(); + expect(textOf(tree)).toContain('XP Potion'); + expect(textOf(tree)).toContain('×3'); + }); + + it('hides a spent stack, since zero is written rather than deleted', async () => { + mockState.entries = [{ item: item(), quantity: '0' }]; + const tree = await render(); + expect(textOf(tree)).not.toContain('XP Potion'); + expect(textOf(tree)).toContain('Nothing here yet'); + }); + + it('reports an error instead of an empty bag', async () => { + mockState.error = new Error('backend unreachable'); + const tree = await render(); + expect(textOf(tree)).toContain('backend unreachable'); + expect(textOf(tree)).not.toContain('Nothing here yet'); + }); +}); + +describe('unclaimed drops', () => { + it('keeps them out of the bag, since nothing on chain reflects one yet', async () => { + mockState.entries = []; + mockState.pending = [ + { entitlementId: 'e1', item: item({ name: 'Rusty Dagger' }), quantity: 1, source: 'battle_drop', sourceRef: '7', createdAt: '' }, + ]; + const tree = await render(); + + expect(textOf(tree)).toContain('Rusty Dagger'); + expect(textOf(tree)).toContain('battle #7'); + // The bag itself is still empty: a pending drop is not a held item. + expect(textOf(tree)).toContain('Nothing here yet'); + }); + + it('claims by entitlement id', async () => { + mockState.pending = [ + { entitlementId: 'e1', item: item({ name: 'Rusty Dagger' }), quantity: 1, source: 'admin_grant', sourceRef: '', createdAt: '' }, + ]; + const tree = await render(); + await press(tree, 'Claim Rusty Dagger'); + expect(mockClaim).toHaveBeenCalledWith('e1'); + }); + + it('surfaces a failed claim rather than leaving the row looking slow', async () => { + mockClaim.mockRejectedValueOnce(new Error('out of gas')); + mockState.pending = [ + { entitlementId: 'e1', item: item({ name: 'Rusty Dagger' }), quantity: 1, source: 'admin_grant', sourceRef: '', createdAt: '' }, + ]; + const tree = await render(); + await press(tree, 'Claim Rusty Dagger'); + expect(mockNotify).toHaveBeenCalledWith( + 'Could not claim Rusty Dagger', + expect.any(Error), + 'inventory-claim', + ); + }); +}); + +describe('spending a consumable', () => { + it('refuses without a pet rather than sending a call that cannot work', async () => { + const tree = await render(); + await press(tree, 'Open XP Potion'); + await press(tree, 'Use item'); + expect(mockSpend).not.toHaveBeenCalled(); + expect(mockNotify).toHaveBeenCalledWith( + 'Pick a pet to use this on', + undefined, + 'inventory-validation', + ); + }); + + it('spends on the chosen pet and refreshes the bag', async () => { + const tree = await render(); + await press(tree, 'Open XP Potion'); + + // PetPicker renders one chip per pet; the first is Rex. + const chip = tree.root + .findAllByType(TouchableOpacity) + .find((n) => textOf({ root: n } as never).includes('Rex')); + await ReactTestRenderer.act(async () => chip!.props.onPress()); + await press(tree, 'Use item'); + + expect(mockSpend).toHaveBeenCalledWith({ + chain: 'ethereum', + petId: '1', + itemType: '1', + }); + expect(mockRefetch).toHaveBeenCalled(); + expect(textOf(tree)).toContain('Level 3'); + }); +}); diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index 2a76ae5f..3ae813ab 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -25,6 +25,8 @@ jest.mock('../src/screens/BreedScreen', () => () => null); jest.mock('../src/screens/MarriageScreen', () => () => null); jest.mock('../src/screens/BattleScreen', () => () => null); jest.mock('../src/screens/LeaderboardScreen', () => () => null); +jest.mock('../src/screens/InventoryScreen', () => () => null); +jest.mock('../src/screens/EquipScreen', () => () => null); jest.mock('../src/components/AppHeader', () => () => null); jest.mock('../src/screens/LandingScreen', () => { const { Text: RNText } = jest.requireActual('react-native'); @@ -88,12 +90,16 @@ describe('routes', () => { 'Rename', 'Defense', 'Leaderboard', + 'Inventory', + 'Equip', ]); }); it('does not route the deferred features', () => { + // Inventory left this list when roadmap section 4 landed on mobile. Shard Forge has + // no implementation on either client, so it stays absent rather than shown + // disabled: a tab bar has no room to advertise what does not work yet. const everyRoute = [...TAB_ITEMS.map((t) => t.name), ...Object.keys(STACK_TITLES)]; - expect(everyRoute).not.toContain('Inventory'); expect(everyRoute).not.toContain('ShardForge'); }); }); diff --git a/mobile/src/components/AccountSheet.tsx b/mobile/src/components/AccountSheet.tsx index c4251db9..d6ed620c 100644 --- a/mobile/src/components/AccountSheet.tsx +++ b/mobile/src/components/AccountSheet.tsx @@ -158,6 +158,18 @@ export default function AccountSheet() { Leaderboard + { + setIsOpen(false); + navigation.navigate('Inventory'); + }} + > + Inventory + + void; onRename: () => void; onDefend: () => void; + onEquip: () => void; onSend: () => void; }; @@ -19,7 +20,15 @@ type Props = { * Rename and Defense live here rather than in the tab bar because both act on a * chosen pet; see plan 3.1. */ -export default function PetCard({ pet, status, onBattle, onRename, onDefend, onSend }: Props) { +export default function PetCard({ + pet, + status, + onBattle, + onRename, + onDefend, + onEquip, + onSend, +}: Props) { const rarityColor = getRarityColor(pet.rarity); return ( @@ -71,6 +80,9 @@ export default function PetCard({ pet, status, onBattle, onRename, onDefend, onS Defend + + Equip + Send diff --git a/mobile/src/components/PetList.tsx b/mobile/src/components/PetList.tsx index a45c033b..e35563d3 100644 --- a/mobile/src/components/PetList.tsx +++ b/mobile/src/components/PetList.tsx @@ -23,6 +23,7 @@ type Props = { onBattle: (pet: Pet) => void; onRename: (pet: Pet) => void; onDefend: (pet: Pet) => void; + onEquip: (pet: Pet) => void; onSend: (pet: Pet) => void; }; @@ -36,6 +37,7 @@ export default function PetList({ onBattle, onRename, onDefend, + onEquip, onSend, }: Props) { if (error) { @@ -102,6 +104,7 @@ export default function PetList({ onBattle={() => onBattle(pet)} onRename={() => onRename(pet)} onDefend={() => onDefend(pet)} + onEquip={() => onEquip(pet)} onSend={() => onSend(pet)} /> ))} diff --git a/mobile/src/hooks/pet-gallery/usePetGallery.ts b/mobile/src/hooks/pet-gallery/usePetGallery.ts index da9759ac..c057b35c 100644 --- a/mobile/src/hooks/pet-gallery/usePetGallery.ts +++ b/mobile/src/hooks/pet-gallery/usePetGallery.ts @@ -108,6 +108,7 @@ export const usePetGallery = (): UsePetGallery => { onBattle: (pet) => navigation.navigate('Main', { screen: 'Battle', params: { petId: pet.id } }), onRename: (pet) => navigation.navigate('Rename', { petId: pet.id }), onDefend: (pet) => navigation.navigate('Defense', { petId: pet.id }), + onEquip: (pet) => navigation.navigate('Equip', { petId: pet.id }), sendingPet, onSend: setSendingPet, onCloseSend: () => setSendingPet(null), diff --git a/mobile/src/navigation/RootNavigator.tsx b/mobile/src/navigation/RootNavigator.tsx index 8a95aea1..8ba880d8 100644 --- a/mobile/src/navigation/RootNavigator.tsx +++ b/mobile/src/navigation/RootNavigator.tsx @@ -11,8 +11,10 @@ import AppHeader from '../components/AppHeader'; import BattleScreen from '../screens/BattleScreen'; import BreedScreen from '../screens/BreedScreen'; import DefenseScreen from '../screens/DefenseScreen'; +import EquipScreen from '../screens/EquipScreen'; import GalleryScreen from '../screens/GalleryScreen'; import LandingScreen from '../screens/LandingScreen'; +import InventoryScreen from '../screens/InventoryScreen'; import LeaderboardScreen from '../screens/LeaderboardScreen'; import LevelUpScreen from '../screens/LevelUpScreen'; import MarriageScreen from '../screens/MarriageScreen'; @@ -43,6 +45,8 @@ const STACK_SCREENS = { Rename: RenameScreen, Defense: DefenseScreen, Leaderboard: LeaderboardScreen, + Inventory: InventoryScreen, + Equip: EquipScreen, } as const; /** diff --git a/mobile/src/navigation/routes.ts b/mobile/src/navigation/routes.ts index ca362130..d3b638c7 100644 --- a/mobile/src/navigation/routes.ts +++ b/mobile/src/navigation/routes.ts @@ -3,8 +3,9 @@ * sidebar's `NAV_ITEMS`. Same destinations, different shape: frontend renders all * seven as sidebar entries, mobile splits them between a tab bar and the stack. * - * Inventory and Shard Forge are deferred in frontend and absent here too, rather - * than shown disabled: a tab bar has no room to advertise what does not work yet. + * Inventory is routed now, on the stack rather than the tab bar. Shard Forge is + * still absent rather than shown disabled: a tab bar has no room to advertise what + * does not work yet. */ import type { NavigatorScreenParams } from '@react-navigation/native'; @@ -36,6 +37,10 @@ export type RootStackParamList = { * for without truncating every label to fit a screen nobody opens mid-battle. */ Leaderboard: undefined; + /** The bag, reached from the account sheet. Acts on no single pet. */ + Inventory: undefined; + /** Gear one pet. Per-pet, so it arrives from a gallery action like Rename. */ + Equip: { petId?: string } | undefined; }; export type TabItem = { @@ -68,4 +73,6 @@ export const STACK_TITLES: Record>(); + const { activeKind: chain, isConnected } = useChainCapabilities(); + const { pets } = usePetList(); + const notifyError = useNotifyError(); + + const [selected, setSelected] = useState(route.params?.petId ?? ''); + /** Which item is chosen per slot, before the player commits it. */ + const [choice, setChoice] = useState>({}); + + const petId = selected || null; + const { entries } = useInventory({ chain }); + const { bySlot, isLoading: slotsLoading } = usePetEquipment({ chain, petId }); + const { canEquip, equip, unequip, equipLifecycle, unequipLifecycle, isPending } = useEquipItem({ + chain, + petId, + }); + + useTxErrorToast((equipLifecycle.error ?? unequipLifecycle.error) as Error | null); + + /** + * Held equipment bucketed by slot, filtered from the bag rather than fetched again: + * the inventory read is already on screen and an item's slot is part of its + * definition, so a second query would ask the server what the client already knows. + */ + const choicesBySlot = useMemo(() => { + const buckets = new Map(); + for (const entry of entries) { + if (entry.item.category !== 'equipment' || entry.item.slot == null) continue; + if (entry.quantity === '0') continue; + const bucket = buckets.get(entry.item.slot); + if (bucket) bucket.push(entry.item); + else buckets.set(entry.item.slot, [entry.item]); + } + return buckets; + }, [entries]); + + const run = async (action: () => Promise, label: string) => { + if (!isConnected) { + notifyError('Connect your wallet first', undefined, 'equip-validation'); + return; + } + try { + await action(); + } catch (err) { + notifyError(label, err as Error, 'equip'); + } + }; + + return ( + + Equip + + Equipping escrows the item into the contract until you take it off. You sign + it yourself, which is what makes a geared pet verifiable. + + + ({ id: pet.id, pet }))} + selectedId={selected} + onSelect={setSelected} + disabled={isPending} + emptyHint="No pets in this wallet yet." + /> + + {!canEquip ? ( + + This chain has no item contract, so nothing can be equipped here. + Inventory is EVM-only for now. + + ) : null} + + {!petId ? ( + Pick a pet to see its slots. + ) : slotsLoading ? ( + + + + ) : ( + SLOTS.map(({ index, label }) => { + const worn = bySlot.get(index); + const options = choicesBySlot.get(index) ?? []; + const picked = choice[index]; + + return ( + + {label} + + {worn ? ( + + + + {worn.item.name} + + {describeItemEffect(worn.item.effect) ? ( + + {describeItemEffect(worn.item.effect)} + + ) : null} + + { + run(() => unequip(index), 'Could not unequip that item'); + }} + disabled={isPending || !canEquip} + accessibilityRole="button" + accessibilityLabel={`Unequip ${label}`} + activeOpacity={0.85} + > + Remove + + + ) : options.length === 0 ? ( + + Empty, and nothing in the bag fits this slot. + + ) : ( + <> + + {options.map((item) => { + const active = picked === item.itemType; + return ( + + setChoice((prev) => ({ + ...prev, + [index]: item.itemType, + })) + } + disabled={isPending} + accessibilityRole="button" + accessibilityLabel={`Choose ${item.name}`} + activeOpacity={0.85} + > + + {item.name} + + {describeItemEffect(item.effect) ? ( + + {describeItemEffect(item.effect)} + + ) : null} + + ); + })} + + + { + run(() => equip(index, picked!), 'Could not equip that item'); + }} + disabled={!picked || isPending || !canEquip} + accessibilityRole="button" + accessibilityLabel={`Equip ${label}`} + activeOpacity={0.85} + > + + {isPending ? 'Confirm in your wallet…' : `Equip ${label}`} + + + + )} + + ); + }) + )} + + ); +} + +const styles = StyleSheet.create({ + root: { flex: 1, backgroundColor: neon.bgDeep }, + content: { padding: 16, paddingBottom: 32 }, + title: { + fontSize: 22, + fontWeight: '800', + color: neon.text, + letterSpacing: 0.5, + textShadowColor: neon.cyan, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 10, + }, + subtitle: { + fontSize: 13, + color: neon.textMuted, + marginTop: 6, + marginBottom: 18, + lineHeight: 19, + }, + note: { fontSize: 13, color: neon.textMuted, marginTop: 8, lineHeight: 19 }, + loading: { paddingVertical: 40, alignItems: 'center' }, + slot: { + marginTop: 16, + backgroundColor: neon.bgPanel, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + padding: 12, + }, + slotLabel: { + fontSize: 12, + fontWeight: '800', + letterSpacing: 1, + textTransform: 'uppercase', + color: neon.textDim, + marginBottom: 8, + }, + slotEmpty: { fontSize: 13, color: neon.textMuted }, + worn: { flexDirection: 'row', alignItems: 'center' }, + wornBody: { flex: 1, minWidth: 0 }, + wornName: { fontSize: 15, fontWeight: '800' }, + wornEffect: { fontSize: 12, color: neon.textMuted, marginTop: 2 }, + remove: { + paddingHorizontal: 14, + paddingVertical: 9, + borderRadius: 10, + borderWidth: 1, + borderColor: neon.borderMagenta, + backgroundColor: neon.bgCard, + }, + removeText: { color: neon.magenta, fontSize: 14, fontWeight: '700' }, + optionRow: { marginBottom: 10 }, + chip: { + borderWidth: 1, + borderColor: neon.border, + backgroundColor: neon.bgCard, + borderRadius: 12, + paddingHorizontal: 14, + paddingVertical: 9, + marginRight: 8, + minWidth: 96, + }, + chipOn: { borderColor: neon.cyan, backgroundColor: neon.bgInput }, + chipName: { fontSize: 14, fontWeight: '700', color: neon.text }, + chipNameOn: { color: neon.cyan }, + chipEffect: { fontSize: 11, color: neon.textMuted, marginTop: 2 }, + action: { + backgroundColor: neon.bgCard, + borderRadius: 12, + paddingVertical: 12, + alignItems: 'center', + borderWidth: 1, + borderColor: neon.cyan, + ...neonGlow(neon.cyan, 8, 0.35), + }, + actionText: { color: neon.cyan, fontSize: 15, fontWeight: '800' }, + disabled: { opacity: 0.5 }, +}); diff --git a/mobile/src/screens/GalleryScreen.tsx b/mobile/src/screens/GalleryScreen.tsx index 7ad421d9..b058d054 100644 --- a/mobile/src/screens/GalleryScreen.tsx +++ b/mobile/src/screens/GalleryScreen.tsx @@ -31,6 +31,7 @@ export default function GalleryScreen() { onBattle, onRename, onDefend, + onEquip, sendingPet, onSend, onCloseSend, @@ -89,6 +90,7 @@ export default function GalleryScreen() { onBattle={onBattle} onRename={onRename} onDefend={onDefend} + onEquip={onEquip} onSend={onSend} /> diff --git a/mobile/src/screens/InventoryScreen.tsx b/mobile/src/screens/InventoryScreen.tsx new file mode 100644 index 00000000..1d63fb97 --- /dev/null +++ b/mobile/src/screens/InventoryScreen.tsx @@ -0,0 +1,391 @@ +import React, { useState } from 'react'; +import { + ActivityIndicator, + Modal, + Pressable, + ScrollView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import { + describeItemEffect, + explainItem, + getRarityColor, + itemStats, + SLOT_NAMES, + useChainCapabilities, + useInventory, + usePendingItems, + usePetList, + useSpendItem, + type ItemDefinition, +} from '@shared/core'; + +import PetPicker from '../components/PetPicker'; +import { useNotifyError } from '../hooks/useNotifyError'; +import { neon, neonGlow } from '../theme/neon'; + +/** + * The bag: what this wallet holds, and what it has earned but not yet minted. + * + * The two are drawn apart because a pending drop is not an item yet. Nothing on chain + * reflects one until its claim lands, so listing them together would offer a stack that + * cannot be spent or equipped. + * + * Quantity zero is a value, not an absence. `indexer-go` resumes from an `updatedAt` + * watermark, so a spent stack is written as `quantity 0` rather than deleted, and a row + * that reads zero has to render as empty rather than be mistaken for a held item. + * + * Equipping is not here. It needs a pet and a slot, so it lives on `EquipScreen`, reached + * per pet from the gallery, for the same reason frontend keeps it in a panel of its own. + */ +export default function InventoryScreen() { + const { activeKind: chain } = useChainCapabilities(); + const { entries, isLoading, error, refetch } = useInventory({ chain }); + const pending = usePendingItems(chain); + const { pets } = usePetList(); + const { spend, isPending: isSpending } = useSpendItem(); + const notifyError = useNotifyError(); + + const [open, setOpen] = useState(null); + const [targetPet, setTargetPet] = useState(''); + const [done, setDone] = useState(null); + + const close = () => { + setOpen(null); + setTargetPet(''); + setDone(null); + }; + + const held = entries.filter((entry) => entry.quantity !== '0'); + + // Wrapped rather than called straight from onPress: `claim` rejects on a failed + // mint, and an unhandled rejection would leave the row looking merely slow. + const onClaim = async (entitlementId: string, name: string) => { + try { + await pending.claim(entitlementId); + } catch (err) { + notifyError(`Could not claim ${name}`, err as Error, 'inventory-claim'); + } + }; + + const onSpend = async () => { + if (!open || !chain) return; + if (!targetPet) { + notifyError('Pick a pet to use this on', undefined, 'inventory-validation'); + return; + } + try { + const result = await spend({ chain, petId: targetPet, itemType: open.itemType }); + setDone( + result.leveledUp + ? `Used. Level ${result.level} now, ${result.xp} XP.` + : `Used. ${result.xp} XP.`, + ); + refetch(); + } catch (err) { + notifyError('Could not use that item', err as Error, 'inventory-spend'); + } + }; + + return ( + + Inventory + + Items you hold, and drops waiting to be minted + + + {pending.pending.length > 0 ? ( + <> + Unclaimed + + Earned in battle. Claiming mints the item on chain and costs gas, + which is why it is not automatic. + + {pending.pending.map((entry) => ( + + + {entry.item.name} + + ×{entry.quantity} + {entry.source === 'battle_drop' && entry.sourceRef + ? ` · battle #${entry.sourceRef}` + : ''} + + + { + onClaim(entry.entitlementId, entry.item.name); + }} + disabled={pending.claimingId != null} + accessibilityRole="button" + accessibilityLabel={`Claim ${entry.item.name}`} + activeOpacity={0.85} + > + {pending.claimingId === entry.entitlementId ? ( + + ) : ( + Claim + )} + + + ))} + + ) : null} + + Items + + {error ? ( + {error.message} + ) : isLoading ? ( + + + + ) : held.length === 0 ? ( + + Nothing here yet. Items drop from battles. + + ) : ( + + {held.map(({ item, quantity }) => ( + setOpen(item)} + accessibilityRole="button" + accessibilityLabel={`Open ${item.name}`} + activeOpacity={0.85} + > + ×{quantity} + + {item.name} + + + {item.slot != null + ? (SLOT_NAMES[item.slot] ?? 'gear') + : item.category} + + {describeItemEffect(item.effect) ? ( + + {describeItemEffect(item.effect)} + + ) : null} + + ))} + + )} + + + + + {open ? ( + + + {open.name} + + {open.description} + + {itemStats(open.effect).length > 0 ? ( + + {itemStats(open.effect).map((stat) => ( + + + +{stat.value} {stat.label} + + + ))} + + ) : null} + + {/* The long form, worded once in @shared/core so both clients + explain an item identically. */} + {explainItem(open)} + + {open.category === 'consumable' ? ( + done ? ( + {done} + ) : ( + <> + Use on + ({ id: pet.id, pet }))} + selectedId={targetPet} + onSelect={setTargetPet} + disabled={isSpending} + emptyHint="No pets in this wallet yet." + /> + { + onSpend(); + }} + disabled={isSpending} + accessibilityRole="button" + accessibilityLabel="Use item" + activeOpacity={0.85} + > + + {isSpending ? 'Using…' : 'Use'} + + + + ) + ) : null} + + + Close + + + ) : null} + + + + ); +} + +const styles = StyleSheet.create({ + root: { flex: 1, backgroundColor: neon.bgDeep }, + content: { padding: 16, paddingBottom: 32 }, + title: { + fontSize: 22, + fontWeight: '800', + color: neon.text, + letterSpacing: 0.5, + textShadowColor: neon.cyan, + textShadowOffset: { width: 0, height: 0 }, + textShadowRadius: 10, + }, + subtitle: { fontSize: 14, color: neon.textMuted, marginTop: 6, marginBottom: 16 }, + section: { + fontSize: 12, + fontWeight: '800', + letterSpacing: 1, + textTransform: 'uppercase', + color: neon.textDim, + marginTop: 16, + marginBottom: 6, + }, + sectionHint: { fontSize: 12, color: neon.textMuted, marginBottom: 10, lineHeight: 17 }, + pendingRow: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: neon.bgPanel, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.borderMagenta, + padding: 12, + marginBottom: 8, + }, + pendingBody: { flex: 1, minWidth: 0 }, + pendingName: { fontSize: 15, fontWeight: '700', color: neon.text }, + pendingSub: { fontSize: 12, color: neon.textMuted, marginTop: 2 }, + claim: { + minWidth: 80, + paddingHorizontal: 14, + paddingVertical: 9, + borderRadius: 10, + alignItems: 'center', + backgroundColor: neon.bgCard, + borderWidth: 1, + borderColor: neon.cyan, + }, + claimText: { color: neon.cyan, fontSize: 14, fontWeight: '800' }, + grid: { flexDirection: 'row', flexWrap: 'wrap', marginHorizontal: -4 }, + tile: { + width: '46%', + margin: '2%', + backgroundColor: neon.bgCard, + borderRadius: 12, + borderWidth: 1, + padding: 12, + minHeight: 108, + }, + qty: { fontSize: 12, fontWeight: '800', color: neon.textMuted, marginBottom: 4 }, + tileName: { fontSize: 15, fontWeight: '800' }, + tileSub: { + fontSize: 11, + color: neon.textDim, + marginTop: 4, + textTransform: 'uppercase', + letterSpacing: 0.5, + }, + tileEffect: { fontSize: 12, color: neon.textMuted, marginTop: 6 }, + loading: { paddingVertical: 40, alignItems: 'center' }, + empty: { fontSize: 14, color: neon.textMuted, lineHeight: 20 }, + error: { fontSize: 13, color: neon.danger }, + modalRoot: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }, + backdrop: { backgroundColor: 'rgba(5, 5, 13, 0.88)' }, + sheet: { + zIndex: 2, + width: '100%', + maxWidth: 420, + backgroundColor: neon.bgPanel, + borderRadius: 16, + borderWidth: 1, + borderColor: neon.border, + padding: 20, + ...neonGlow(neon.purple, 14, 0.35), + }, + sheetName: { fontSize: 19, fontWeight: '800' }, + sheetDesc: { fontSize: 14, color: neon.textMuted, marginTop: 6, lineHeight: 20 }, + chips: { flexDirection: 'row', flexWrap: 'wrap', marginTop: 12 }, + chip: { + backgroundColor: neon.bgCard, + borderRadius: 8, + borderWidth: 1, + borderColor: neon.border, + paddingHorizontal: 10, + paddingVertical: 5, + marginRight: 6, + marginBottom: 6, + }, + chipText: { fontSize: 12, fontWeight: '800', color: neon.cyan }, + sheetExplain: { fontSize: 13, color: neon.textMuted, marginTop: 10, lineHeight: 19 }, + label: { + fontSize: 12, + fontWeight: '700', + letterSpacing: 1, + color: neon.textMuted, + marginTop: 16, + marginBottom: 8, + }, + action: { + backgroundColor: neon.bgCard, + borderRadius: 12, + paddingVertical: 12, + alignItems: 'center', + marginTop: 12, + borderWidth: 1, + borderColor: neon.cyan, + ...neonGlow(neon.cyan, 8, 0.35), + }, + actionText: { color: neon.cyan, fontSize: 15, fontWeight: '800' }, + secondary: { borderColor: neon.purple, ...neonGlow(neon.purple, 6, 0.15) }, + secondaryText: { color: neon.purple, fontSize: 15, fontWeight: '700' }, + disabled: { opacity: 0.5 }, + success: { + marginTop: 14, + fontSize: 14, + fontWeight: '700', + color: neon.success, + }, +}); From 5d8cd111ee3d547f3958322232f263ece5dc4a63 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 19:24:41 -0400 Subject: [PATCH 37/99] feat(mobile): replay a battle strike by strike --- mobile/__tests__/BattleScreen.test.tsx | 107 +++++++++++++ mobile/src/hooks/battle/useBattlePanel.ts | 53 +++++++ mobile/src/screens/BattleScreen.tsx | 33 +++- mobile/src/screens/parts/BattleScene.tsx | 181 ++++++++++++++++++++++ 4 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 mobile/src/screens/parts/BattleScene.tsx diff --git a/mobile/__tests__/BattleScreen.test.tsx b/mobile/__tests__/BattleScreen.test.tsx index e2a22acc..8265de53 100644 --- a/mobile/__tests__/BattleScreen.test.tsx +++ b/mobile/__tests__/BattleScreen.test.tsx @@ -41,8 +41,35 @@ const mockState = { isConnected: true, winProbability: 0.62 as number | null, turns: [] as { text: string }[], + /** + * The client's own replay of the verified receipt, which is the only thing the + * scene animates. Null until a battle resolves, and absent entirely when a check + * failed — so an unverified fight has nothing to show rather than something + * unverified to show. + */ + liveReplay: null as { + log: Record[]; + startHp1: bigint; + startHp2: bigint; + } | null, }; +/** One strike, shaped as `StrikeLogEntry`. */ +const strike = (over: Record = {}) => ({ + round: 1, + attacker: 1, + isMagic: false, + damage: 10n, + heal: 0n, + crit: false, + elementMult: 100, + furyTriggered: false, + rebirthTriggered: false, + hp1After: 100n, + hp2After: 90n, + ...over, +}); + const mockBattle = jest.fn(); const mockTaunts = jest.fn(); // `useCreateBattleRoom().createRoom` resolves to the room id itself, or null when @@ -88,8 +115,21 @@ jest.mock('@shared/core', () => ({ isPending: false, error: null, phase: 'idle', + liveReplay: mockState.liveReplay, }; }, + // The real hook, not a stub: the replay's stepping and its done-gate are the + // behaviour under test, and a fake would only assert the fake. Pulled in by + // relative path because the barrel this factory replaces is what drags the Solana + // runtime into jest. + useLiveBattleAnimation: (...args: unknown[]) => + jest + .requireActual('../../shared/src/hooks/battle/useLiveBattleAnimation') + .useLiveBattleAnimation(...args), + describeMechanicalLogEntry: (...args: unknown[]) => + jest + .requireActual('../../shared/src/hooks/battle/useLiveBattleAnimation') + .describeMechanicalLogEntry(...args), })); jest.mock('../src/hooks/usePetErrorToast', () => ({ usePetErrorToast: () => {} })); @@ -142,6 +182,7 @@ beforeEach(() => { mockState.isConnected = true; mockState.winProbability = 0.62; mockState.turns = []; + mockState.liveReplay = null; delete mockRouteParams.petId; jest.clearAllMocks(); }); @@ -306,3 +347,69 @@ describe('BattleScreen', () => { expect(textOf(tree)).toContain('backend unreachable'); }); }); + +/** + * The replay is presentation over a verified receipt, never a source of truth. + * + * `useBattlePets` only exposes `liveReplay` once every verification check has passed, + * so there is no state where the scene animates a fight the receipt does not commit to. + * What is worth pinning here is the other half: that the verdict waits for the fight to + * finish, and that a battle with nothing to animate still reports its result at once. + */ +describe('battle replay', () => { + const replay = (log: ReturnType[]) => ({ + log, + startHp1: 100n, + startHp2: 100n, + }); + + it('shows nothing to watch until a replay exists', async () => { + const tree = await render(); + expect(textOf(tree)).not.toContain('Bracing for the first strike'); + }); + + it('opens on full bars, before any strike has played', async () => { + mockState.liveReplay = replay([strike()]); + const tree = await render(); + // Both fighters at 100%: the first strike has not landed yet. + expect(textOf(tree)).toContain('Bracing for the first strike'); + expect(textOf(tree)).toContain('100%'); + }); + + it('plays a strike, dropping the defender and narrating it', async () => { + mockState.liveReplay = replay([strike({ hp1After: 100n, hp2After: 60n })]); + const tree = await render(); + + await ReactTestRenderer.act(async () => { + await new Promise((r) => setTimeout(r, 750)); + }); + + const rendered = textOf(tree); + expect(rendered).toContain('60%'); + expect(rendered).toContain('lands a physical strike'); + // The mechanical log names both fighters, unlike the one-line flourish. + expect(rendered).toContain('Round 1'); + expect(rendered).toContain('Rex'); + }); + + it('reports the whole log as history, oldest first', async () => { + mockState.liveReplay = replay([ + strike({ round: 1, hp2After: 70n }), + strike({ round: 2, attacker: 2, crit: true, hp1After: 55n }), + ]); + const tree = await render(); + + // One act per strike. The next timer is only armed by the effect that runs + // after React re-renders from the previous one, so a single long wait would + // play the first strike and never schedule the second. + for (let i = 0; i < 2; i++) { + await ReactTestRenderer.act(async () => { + await new Promise((r) => setTimeout(r, 750)); + }); + } + + const rendered = textOf(tree); + expect(rendered.indexOf('Round 1')).toBeLessThan(rendered.indexOf('Round 2')); + expect(rendered).toContain('Crit!'); + }); +}); diff --git a/mobile/src/hooks/battle/useBattlePanel.ts b/mobile/src/hooks/battle/useBattlePanel.ts index fbbe54c6..79783299 100644 --- a/mobile/src/hooks/battle/useBattlePanel.ts +++ b/mobile/src/hooks/battle/useBattlePanel.ts @@ -1,10 +1,12 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { + describeMechanicalLogEntry, getReadyPetsUnified, useBattlePets, useBattleTaunts, useChainCapabilities, useCreateBattleRoom, + useLiveBattleAnimation, useOpponents, usePetList, useWinEstimate, @@ -59,6 +61,19 @@ export interface UseBattlePanel { onStartBattle: () => void; result: BattleResolvedResult | null; onDismissResult: () => void; + /** Fighter and opponent HP as 0-100, stepping down one strike at a time. */ + hp1Percent: number; + hp2Percent: number; + /** Flavour line for the strike currently on screen; null before the first. */ + flourish: string | null; + /** Every strike played so far, worded for the log, oldest first. */ + strikeLog: string[]; + /** True once the replay has finished, or immediately when there is nothing to play. */ + replayDone: boolean; + /** Restart the same replay from its first strike. */ + onReplay: () => void; + /** Whether a replay exists to watch at all. */ + hasReplay: boolean; } /** @@ -135,6 +150,37 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { roomSocketUrl: BATTLE_ROOM_WS_URL, }); + /** + * The fight, played back one strike at a time. + * + * `liveReplay` is this client's *own* simulation of the receipt's inputs, and + * `useBattlePets` only exposes it once every verification check has passed. So the + * animation cannot disagree with the result beside it: if the local replay produced a + * different fight, `checkCombatReplay` would have failed and there would be nothing + * here to animate. That is why this needs no reconciliation notice of the kind + * frontend carried for the old on-chain path. + * + * It is presentation only either way. The receipt settles the battle; this shows how. + */ + const animation = useLiveBattleAnimation( + battle.liveReplay?.log ?? null, + battle.liveReplay?.startHp1 ?? null, + battle.liveReplay?.startHp2 ?? null, + true, + ); + + const strikeLog = useMemo( + () => + animation.history.map((entry) => + describeMechanicalLogEntry( + entry, + fighter?.name ?? 'Your pet', + opponent?.name ?? 'The opponent', + ), + ), + [animation.history, fighter?.name, opponent?.name], + ); + // Read through a ref so the effect below depends on the pending fight alone. // `battle` is a fresh object every render, and depending on it would restart // the battle on each one. @@ -231,5 +277,12 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { onStartBattle, result, onDismissResult: () => setResult(null), + hp1Percent: animation.hp1Percent, + hp2Percent: animation.hp2Percent, + flourish: animation.flourish, + strikeLog, + replayDone: animation.done, + onReplay: animation.replay, + hasReplay: (battle.liveReplay?.log.length ?? 0) > 0, }; }; diff --git a/mobile/src/screens/BattleScreen.tsx b/mobile/src/screens/BattleScreen.tsx index 3bc9a95d..73441498 100644 --- a/mobile/src/screens/BattleScreen.tsx +++ b/mobile/src/screens/BattleScreen.tsx @@ -12,6 +12,7 @@ import type { RouteProp } from '@react-navigation/native'; import { useRoute } from '@react-navigation/native'; import PetPicker from '../components/PetPicker'; +import BattleScene from './parts/BattleScene'; import { useBattlePanel } from '../hooks/battle/useBattlePanel'; import { getLevelDelta, getMatchLabel, getMatchTier } from '../hooks/battle/matchmaking'; import type { MainTabParamList } from '../navigation/routes'; @@ -129,6 +130,17 @@ export default function BattleScreen() { ) : null} + {panel.hasReplay ? ( + + ) : null} + {panel.validationError} ) : null} + {/* + * Held back until the replay finishes, or the verdict lands on top of the + * fight the player is still watching. With no replay to play, the hook reports + * done immediately, so a battle that cannot be animated still shows its result + * at once. + */} ) : null} + {panel.hasReplay ? ( + + Watch again + + ) : null} Close diff --git a/mobile/src/screens/parts/BattleScene.tsx b/mobile/src/screens/parts/BattleScene.tsx new file mode 100644 index 00000000..87d48393 --- /dev/null +++ b/mobile/src/screens/parts/BattleScene.tsx @@ -0,0 +1,181 @@ +import React, { useEffect, useRef } from 'react'; +import { Animated, ScrollView, StyleSheet, Text, View } from 'react-native'; + +import { neon, neonGlow } from '../../theme/neon'; + +/** Matches `useLiveBattleAnimation`'s strike interval, so a bar finishes as the next lands. */ +const DRAIN_MS = 700; + +type Props = { + fighterName: string; + opponentName: string; + hp1Percent: number; + hp2Percent: number; + /** Flavour line for the strike on screen, or null before the first plays. */ + flourish: string | null; + /** Every strike so far, oldest first. */ + strikeLog: string[]; +}; + +/** + * One HP bar, easing to its new percentage rather than jumping. + * + * `Animated` from React Native core, deliberately, rather than adding + * `react-native-reanimated`: that would mean a new native dependency, a Babel plugin and a + * rebuild, on an emulator image with 16 KB pages where an unaligned native library will + * not load at all. Two width interpolations do not justify any of that. + * + * `useNativeDriver` is false because width is a layout property, which the native driver + * cannot animate. At two bars stepping once per strike that costs nothing worth measuring. + */ +const HpBar: React.FC<{ percent: number; color: string; label: string }> = ({ + percent, + color, + label, +}) => { + const width = useRef(new Animated.Value(percent)).current; + + useEffect(() => { + const drain = Animated.timing(width, { + toValue: percent, + duration: DRAIN_MS, + useNativeDriver: false, + }); + drain.start(); + // Stopped rather than left running: a result dismissed mid-fight unmounts this, + // and a timing animation that outlives its component sets state on a dead node. + return () => drain.stop(); + }, [percent, width]); + + const fill = width.interpolate({ + inputRange: [0, 100], + outputRange: ['0%', '100%'], + extrapolate: 'clamp', + }); + + return ( + + + {label} + + + + + {Math.round(percent)}% + + ); +}; + +/** + * The fight, played back strike by strike. + * + * Presentation only. What drives it is this client's own replay of the verified receipt, + * so the fight shown is the fight the receipt commits to; the result card beside it is the + * authority on who won. + * + * The mechanical log is worded by `describeMechanicalLogEntry` in `@shared/core`, so both + * clients narrate a strike identically and a new combat tag has one place to be worded. + */ +export default function BattleScene({ + fighterName, + opponentName, + hp1Percent, + hp2Percent, + flourish, + strikeLog, +}: Props) { + const logRef = useRef(null); + + return ( + + + + + {/* Reserved whether or not a strike has landed, so the log below does not + jump up the screen when the first one plays. */} + + {flourish ?? 'Bracing for the first strike…'} + + + {strikeLog.length > 0 ? ( + logRef.current?.scrollToEnd({ animated: true })} + nestedScrollEnabled + > + {strikeLog.map((line, index) => ( + + {line} + + ))} + + ) : null} + + ); +} + +const styles = StyleSheet.create({ + root: { + marginTop: 16, + backgroundColor: neon.bgPanel, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + padding: 14, + ...neonGlow(neon.purple, 8, 0.2), + }, + hpRow: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 10, + }, + hpName: { + width: 84, + fontSize: 13, + fontWeight: '700', + color: neon.text, + }, + hpTrack: { + flex: 1, + height: 10, + borderRadius: 5, + backgroundColor: neon.bgInput, + overflow: 'hidden', + marginHorizontal: 8, + }, + hpFill: { + height: 10, + borderRadius: 5, + }, + hpPercent: { + width: 42, + fontSize: 12, + fontWeight: '800', + textAlign: 'right', + }, + flourishBox: { + minHeight: 40, + justifyContent: 'center', + marginTop: 4, + }, + flourish: { + fontSize: 14, + fontWeight: '700', + color: neon.text, + lineHeight: 20, + }, + log: { + maxHeight: 132, + marginTop: 8, + borderTopWidth: StyleSheet.hairlineWidth, + borderTopColor: neon.border, + paddingTop: 8, + }, + logLine: { + fontSize: 12, + color: neon.textMuted, + marginBottom: 4, + lineHeight: 17, + }, +}); From 9eaf2bc21067c68d9e3b51fc13d51c35995674cb Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 19:46:54 -0400 Subject: [PATCH 38/99] feat(mobile): play the AI result dialogue after a battle --- mobile/README.md | 11 ++- mobile/__tests__/BattleScreen.test.tsx | 83 ++++++++++++++++++ mobile/src/hooks/battle/useBattlePanel.ts | 63 +++++++++----- mobile/src/hooks/battle/useResultDialogue.ts | 91 ++++++++++++++++++++ mobile/src/screens/BattleScreen.tsx | 55 +++++++++++- 5 files changed, 276 insertions(+), 27 deletions(-) create mode 100644 mobile/src/hooks/battle/useResultDialogue.ts diff --git a/mobile/README.md b/mobile/README.md index 6e2c23c4..60172f13 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -93,11 +93,14 @@ Things worth knowing before changing any of it: ## Known gaps -- No round-by-round battle animation. A battle plays its taunts and then shows the result the - signed receipt carries. Battle *state* is live: it polls `GET /api/battle/:battleId` and - subscribes to the room socket for push updates on top. +- No private chat. `useChatThreads` / `useChatMessages` are in `@shared/core` and unused here. - No ERC-20 token balances. The target chain's popular-token list holds a single testnet LINK. -- No NFT art. Pets fall back to emoji avatars. + +Recently closed, so the older notes claiming otherwise are wrong: the battle replays +round by round from the verified receipt and plays the AI result dialogue after it; pet +art renders through `PetArt` when `IMAGE_SERVICE_URL` is set, falling back to the emoji +avatar; the leaderboard, the inventory and equipment all have screens. See +`docs/plan-mobile-frontend-parity.md` for what is left. ## Android package name diff --git a/mobile/__tests__/BattleScreen.test.tsx b/mobile/__tests__/BattleScreen.test.tsx index 8265de53..3d0cc532 100644 --- a/mobile/__tests__/BattleScreen.test.tsx +++ b/mobile/__tests__/BattleScreen.test.tsx @@ -41,6 +41,9 @@ const mockState = { isConnected: true, winProbability: 0.62 as number | null, turns: [] as { text: string }[], + /** Post-fight reactions. `taunt` turns are filtered out before rendering. */ + dialogueTurns: [] as { speaker: string; phase: string; text: string }[], + dialogueLoading: false, /** * The client's own replay of the verified receipt, which is the only thing the * scene animates. Null until a battle resolves, and absent entirely when a check @@ -80,6 +83,8 @@ const mockCreateRoom = jest.fn, unknown[]>(async () => 'r /** Captures what the panel hands `useBattlePets`, which is where roomId matters. */ const mockBattleOptions: { roomId?: string | null; roomSocketUrl?: string } = {}; const mockWinEstimateArgs = jest.fn(); +/** Captures what the result dialogue is asked for, including the personas fallback. */ +const mockDialogueArgs = jest.fn(); jest.mock('@shared/core', () => ({ getReadyPetsUnified: (pets: Pet[]) => @@ -107,6 +112,19 @@ jest.mock('@shared/core', () => ({ isLoading: false, }), useCreateBattleRoom: () => ({ createRoom: mockCreateRoom, isLoading: false }), + toDialoguePet: (subject: Pet | OpponentPet) => ({ + petId: subject.id, + name: subject.name, + level: subject.level, + rarity: subject.rarity, + dna: subject.dna.toString(), + winCount: subject.winCount, + lossCount: subject.lossCount, + }), + useBattleDialogue: (opts: Record) => { + mockDialogueArgs(opts); + return { turns: mockState.dialogueTurns, isLoading: mockState.dialogueLoading }; + }, useBattlePets: (opts: { roomId?: string | null; roomSocketUrl?: string }) => { mockBattleOptions.roomId = opts?.roomId; mockBattleOptions.roomSocketUrl = opts?.roomSocketUrl; @@ -183,6 +201,8 @@ beforeEach(() => { mockState.winProbability = 0.62; mockState.turns = []; mockState.liveReplay = null; + mockState.dialogueTurns = []; + mockState.dialogueLoading = false; delete mockRouteParams.petId; jest.clearAllMocks(); }); @@ -413,3 +433,66 @@ describe('battle replay', () => { expect(rendered).toContain('Crit!'); }); }); + +/** + * The result dialogue, and the reason it needs personas captured at battle start. + * + * Publishing a receipt puts the fighter on cooldown, so it leaves `readyPets` and + * `fighter` reads null exactly when the result is on screen. Anything naming the two + * afterwards has to fall back to what was captured when the fight began. + */ +describe('result dialogue', () => { + const startBattle = async (tree: ReactTestRenderer.ReactTestRenderer) => { + await pressWith(tree, 'Rex'); + await pressWith(tree, 'Luna'); + await pressWith(tree, 'Start Battle'); + }; + + it('asks only for the post-fight phase, since taunts already played', async () => { + mockState.dialogueTurns = [ + { speaker: 'attacker', phase: 'taunt', text: 'Before the fight.' }, + { speaker: 'defender', phase: 'result', text: 'Well fought.' }, + ]; + const tree = await render(); + await startBattle(tree); + + // A taunt turn reaching the result sheet would replay pre-fight lines after it. + expect(textOf(tree)).not.toContain('Before the fight.'); + }); + + it('names both fighters from the captured personas once the fighter is on cooldown', async () => { + const tree = await render(); + await startBattle(tree); + + // The receipt has published, so the fighter is cooling down and out of the list. + mockState.pets = [pet({ readyAt: 9_999_999_999 })]; + mockState.opponents = []; + await ReactTestRenderer.act(async () => { + tree.update(); + }); + + const asked = mockDialogueArgs.mock.calls.at(-1)?.[0] as { + attacker: { name: string } | null; + defender: { name: string } | null; + }; + expect(asked.attacker?.name).toBe('Rex'); + expect(asked.defender?.name).toBe('Luna'); + }); + + it('narrates the strike log with those names too, not "Your pet"', async () => { + mockState.liveReplay = { log: [strike({ hp2After: 80n })], startHp1: 100n, startHp2: 100n }; + const tree = await render(); + await startBattle(tree); + + mockState.pets = [pet({ readyAt: 9_999_999_999 })]; + await ReactTestRenderer.act(async () => { + tree.update(); + }); + await ReactTestRenderer.act(async () => { + await new Promise((r) => setTimeout(r, 750)); + }); + + expect(textOf(tree)).toContain('Rex'); + expect(textOf(tree)).not.toContain('Your pet strikes'); + }); +}); diff --git a/mobile/src/hooks/battle/useBattlePanel.ts b/mobile/src/hooks/battle/useBattlePanel.ts index 79783299..6d8d0cdf 100644 --- a/mobile/src/hooks/battle/useBattlePanel.ts +++ b/mobile/src/hooks/battle/useBattlePanel.ts @@ -10,9 +10,11 @@ import { useOpponents, usePetList, useWinEstimate, + toDialoguePet, + type BattlePersonas, type BattlePetsArgs, type BattleResolvedResult, - type DialoguePetInput, + type DialogueTurn, type OpponentPet, type Pet, } from '@shared/core'; @@ -20,21 +22,11 @@ import { import { BATTLE_ROOM_WS_URL } from '../../constants/api'; import { usePetErrorToast } from '../usePetErrorToast'; import { pickRandomOpponent, sortOpponentsByMatch } from './matchmaking'; +import { useResultDialogue } from './useResultDialogue'; const BATTLE_FAIL_MESSAGE = 'Failed to start the battle. Please try again.'; const VALIDATION_MESSAGE = 'Pick one of your pets and an opponent first.'; -/** Ported from frontend's `battle-utils`; the backend builds a persona from this. */ -const toDialoguePet = (pet: Pet | OpponentPet): DialoguePetInput => ({ - petId: pet.id, - name: pet.name, - level: pet.level, - rarity: pet.rarity, - dna: pet.dna.toString(), - winCount: pet.winCount, - lossCount: pet.lossCount, -}); - export interface UseBattlePanel { isConnected: boolean; /** Own pets off cooldown; a pet on cooldown cannot legally battle. */ @@ -74,6 +66,12 @@ export interface UseBattlePanel { onReplay: () => void; /** Whether a replay exists to watch at all. */ hasReplay: boolean; + /** What the two pets say to each other after the fight; taunts excluded. */ + resultTurns: DialogueTurn[]; + dialogueLoading: boolean; + /** Both names, resolved through the personas captured at battle start. */ + attackerName: string; + defenderName: string; } /** @@ -120,6 +118,17 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { const [roomId, setRoomId] = useState(null); const [pendingStart, setPendingStart] = useState(null); + /** + * Both personas as they stood when the fight started. + * + * Not a convenience. Publishing a receipt puts the fighter on cooldown, which drops + * it out of `readyPets`, so `fighter` is null by the time a result is on screen and + * `opponent` can leave the matchmaking list the same way. Everything that names the + * two afterwards the strike log, the result dialogue reads through here instead, + * or a finished battle narrates itself as "Your pet" against "The opponent". + */ + const personasRef = useRef(null); + const readyPets = useMemo(() => getReadyPetsUnified(pets), [pets]); const fighter = readyPets.find(({ id }) => id === selectedPetId)?.pet ?? null; @@ -169,16 +178,23 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { true, ); + const dialogue = useResultDialogue({ + chain: capabilities.activeKind, + battleId: battle.hash ?? null, + fighter, + opponent, + personas: personasRef.current, + attackerWon: result?.firstWins ?? null, + leveledUp: result?.attackerLeveledUp ?? false, + enabled: result != null, + }); + const strikeLog = useMemo( () => animation.history.map((entry) => - describeMechanicalLogEntry( - entry, - fighter?.name ?? 'Your pet', - opponent?.name ?? 'The opponent', - ), + describeMechanicalLogEntry(entry, dialogue.attackerName, dialogue.defenderName), ), - [animation.history, fighter?.name, opponent?.name], + [animation.history, dialogue.attackerName, dialogue.defenderName], ); // Read through a ref so the effect below depends on the pending fight alone. @@ -224,11 +240,12 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { // Taunts first, then the room, then the battle. The taunts call also // pre-generates the result dialogue on the backend, keyed by matchup. - taunts.generate({ - chain, + const personas = { attacker: toDialoguePet(fighter), defender: toDialoguePet(opponent), - }); + }; + personasRef.current = personas; + taunts.generate({ chain, ...personas }); // The room is best-effort (§J): it gives a spectator or a later replay // something to attach to, but a battle still settles from its receipt, so a @@ -284,5 +301,9 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { replayDone: animation.done, onReplay: animation.replay, hasReplay: (battle.liveReplay?.log.length ?? 0) > 0, + resultTurns: dialogue.resultTurns, + dialogueLoading: dialogue.isLoading, + attackerName: dialogue.attackerName, + defenderName: dialogue.defenderName, }; }; diff --git a/mobile/src/hooks/battle/useResultDialogue.ts b/mobile/src/hooks/battle/useResultDialogue.ts new file mode 100644 index 00000000..468aba57 --- /dev/null +++ b/mobile/src/hooks/battle/useResultDialogue.ts @@ -0,0 +1,91 @@ +import { useMemo } from 'react'; +import { + toDialoguePet, + useBattleDialogue, + type BattlePersonas, + type DialogueTurn, + type OpponentPet, + type Pet, + type PetChain, +} from '@shared/core'; + +export interface UseResultDialogueArgs { + chain: PetChain | null; + /** Stable per-battle key; null until a battle has an id. */ + battleId: string | null; + fighter: Pet | null; + opponent: OpponentPet | null; + /** Personas captured at battle start, for once the fighter leaves the ready list. */ + personas: BattlePersonas | null; + /** True when the attacker won; null until the receipt has resolved. */ + attackerWon: boolean | null; + leveledUp: boolean; + /** Only fetch while a result is on screen. */ + enabled: boolean; +} + +export interface UseResultDialogue { + /** The post-fight reactions, taunts excluded. */ + resultTurns: DialogueTurn[]; + isLoading: boolean; + attackerName: string; + defenderName: string; +} + +/** + * The settled battle's AI dialogue, shaped for the mobile result sheet. + * + * App-local rather than in `@shared/core`, matching frontend's own copy, and for the + * same reason: what it does is map dialogue turns onto one client's view props, and the + * two clients' props differ. The fetch underneath is shared (`useBattleDialogue`); only + * the mapping is duplicated, which is the part that would drift if it were unified. + * + * Smaller than frontend's, deliberately. That one also gates the result actions until a + * typewriter finishes playing the lines, and returns `markResultDialogueDone` / + * `resetResultDialogue` to drive that gate. Mobile renders the lines at once, so there is + * no playback to wait on and nothing to gate. + * + * **The personas fallback is not optional.** A pet that has just fought goes on cooldown + * and drops out of `readyPets`, so `fighter` is null by the time a result is on screen. + * Without the personas captured at battle start the query would be disabled exactly when + * it is needed, and the pre-generated dialogue would never be fetched. + */ +export const useResultDialogue = ({ + chain, + battleId, + fighter, + opponent, + personas, + attackerWon, + leveledUp, + enabled, +}: UseResultDialogueArgs): UseResultDialogue => { + const attacker = useMemo( + () => (fighter ? toDialoguePet(fighter) : (personas?.attacker ?? null)), + [fighter, personas], + ); + const defender = useMemo( + () => (opponent ? toDialoguePet(opponent) : (personas?.defender ?? null)), + [opponent, personas], + ); + + const { turns, isLoading } = useBattleDialogue({ + chain, + battleId, + attacker, + defender, + winner: attackerWon === null ? null : attackerWon ? 'attacker' : 'defender', + leveledUp, + enabled: enabled && attackerWon !== null, + }); + + // The taunts already played before the fight; only the reactions belong here. + const resultTurns = useMemo(() => turns.filter((t) => t.phase === 'result'), [turns]); + + return { + resultTurns, + isLoading, + attackerName: attacker?.name ?? 'Your pet', + defenderName: defender?.name ?? 'Opponent', + }; +}; diff --git a/mobile/src/screens/BattleScreen.tsx b/mobile/src/screens/BattleScreen.tsx index 73441498..e17781f5 100644 --- a/mobile/src/screens/BattleScreen.tsx +++ b/mobile/src/screens/BattleScreen.tsx @@ -132,8 +132,8 @@ export default function BattleScreen() { {panel.hasReplay ? ( + + {/* + * Rendered when it arrives and skipped when it does not. + * Dialogue is generated best-effort and the result is + * already on screen without it, so a slow or failed + * generation must not hold up the verdict. + */} + {panel.resultTurns.length > 0 ? ( + + {panel.resultTurns.map((turn, i) => ( + + + {turn.speaker === 'attacker' + ? panel.attackerName + : panel.defenderName} + + {turn.text} + + ))} + + ) : panel.dialogueLoading ? ( + + The pets are catching their breath + + ) : null} ) : null} {panel.hasReplay ? ( @@ -324,4 +359,20 @@ const styles = StyleSheet.create({ }, resultTitle: { fontSize: 28, fontWeight: '900', letterSpacing: 2, marginBottom: 12 }, resultLine: { fontSize: 15, color: neon.textMuted, marginBottom: 4 }, + dialogue: { + marginTop: 14, + borderTopWidth: StyleSheet.hairlineWidth, + borderTopColor: neon.border, + paddingTop: 12, + }, + dialogueTurn: { marginBottom: 10 }, + dialogueSpeaker: { + fontSize: 11, + fontWeight: '800', + letterSpacing: 0.8, + textTransform: 'uppercase', + marginBottom: 2, + }, + dialogueText: { fontSize: 14, color: neon.text, lineHeight: 20 }, + dialogueWaiting: { marginTop: 14, fontSize: 13, color: neon.textDim, fontStyle: 'italic' }, }); From e94f6df5e777d9b7cfb1ddd18c2a33b46fbef098 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 19:58:56 -0400 Subject: [PATCH 39/99] feat(mobile): add private chat --- mobile/README.md | 11 +- mobile/__tests__/ChatScreen.test.tsx | 251 ++++++++++++++ mobile/__tests__/navigation.test.tsx | 2 + mobile/src/components/AccountSheet.tsx | 12 + mobile/src/constants/api.ts | 10 + mobile/src/navigation/RootNavigator.tsx | 2 + mobile/src/navigation/routes.ts | 8 + mobile/src/screens/ChatScreen.tsx | 425 ++++++++++++++++++++++++ 8 files changed, 716 insertions(+), 5 deletions(-) create mode 100644 mobile/__tests__/ChatScreen.test.tsx create mode 100644 mobile/src/screens/ChatScreen.tsx diff --git a/mobile/README.md b/mobile/README.md index 60172f13..23b1b49a 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -82,9 +82,11 @@ Things worth knowing before changing any of it: - **`useActiveChain` decides which adapter runs**, and it resolves Solana from the auth-signer store and nothing else. `src/solana/SolanaAuthSigner.tsx` is what registers it; without that a connected Solana wallet is invisible to every one of those hooks. -- **Navigation is five tabs plus three stack routes.** `Gallery`, `Battle`, `Breed`, `Level Up` and - `Train` are tabs; `Marriage`, `Rename` and `Defense` are pushed over the shell from a per-pet - action, because each acts on one chosen pet. +- **Navigation is five tabs plus seven stack routes.** `Gallery`, `Battle`, `Breed`, `Level Up` and + `Train` are tabs. `Marriage`, `Rename`, `Defense` and `Equip` are pushed over the shell from a + per-pet action, because each acts on one chosen pet. `Leaderboard`, `Inventory` and `Chat` are + pushed from the account sheet instead: they act on no single pet, and a bottom bar past five + entries truncates every label. - **The landing screen is registered conditionally**, not redirected away from. While disconnected only `Landing` exists, so there is no window where a tab screen renders against a wallet that is not there. @@ -93,13 +95,12 @@ Things worth knowing before changing any of it: ## Known gaps -- No private chat. `useChatThreads` / `useChatMessages` are in `@shared/core` and unused here. - No ERC-20 token balances. The target chain's popular-token list holds a single testnet LINK. Recently closed, so the older notes claiming otherwise are wrong: the battle replays round by round from the verified receipt and plays the AI result dialogue after it; pet art renders through `PetArt` when `IMAGE_SERVICE_URL` is set, falling back to the emoji -avatar; the leaderboard, the inventory and equipment all have screens. See +avatar; the leaderboard, the inventory, equipment and private chat all have screens. See `docs/plan-mobile-frontend-parity.md` for what is left. ## Android package name diff --git a/mobile/__tests__/ChatScreen.test.tsx b/mobile/__tests__/ChatScreen.test.tsx new file mode 100644 index 00000000..f233d2b3 --- /dev/null +++ b/mobile/__tests__/ChatScreen.test.tsx @@ -0,0 +1,251 @@ +/** + * Private chat, and the parts of it that are security properties rather than styling. + * + * Access is derived per request from live marriage state, never cached here. A thread + * leaving the list is a divorce landing, which is the feature working. And a + * non-participant gets 404, identical to a thread that does not exist, because a 403 + * would confirm a thread id to anyone probing — so a failed read must render one message + * for both and this screen must not try to explain which happened. + * + * `@shared/core` is stubbed — its barrel drags the Solana runtime into jest. + */ + +import React from 'react'; +import { Text, TextInput, TouchableOpacity } from 'react-native'; +import ReactTestRenderer from 'react-test-renderer'; + +const SELF = '0xAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaaAAaa'; +const THEM = '0xBBbbBBbbBBbbBBbbBBbbBBbbBBbbBBbbBBbbBBbb'; + +const thread = (over: Record = {}) => ({ + threadId: 't1', + counterpart: THEM, + chain: 'ethereum', + pets: [ + { + petId: '1', + petName: 'Rex', + petDna: '1', + spousePetId: '9', + spouseName: 'Luna', + spouseDna: '2', + }, + ], + ...over, +}); + +const message = (over: Record = {}) => ({ + id: 1, + sender: THEM, + text: 'hello', + createdAt: '2026-08-11T00:00:00Z', + ...over, +}); + +const mockState = { + threads: [] as Record[], + threadsLoading: false, + threadsError: null as Error | null, + messages: [] as Record[], + messagesError: null as Error | null, + readUpTo: 0, + online: [] as string[], + isLive: true, + sendError: null as Error | null, +}; + +const mockSend = jest.fn(); +const mockReact = jest.fn(); +const mockMarkRead = jest.fn(); +const mockMessagesArgs = jest.fn(); + +jest.mock('@shared/core', () => ({ + CHAT_REACTIONS: ['👍', '❤️', '😂', '😮', '😢', '🙏', '👎'], + shortAddress: (a: string) => `${a.slice(0, 6)}...${a.slice(-4)}`, + sameAccount: (a: string, b: string) => a.toLowerCase() === b.toLowerCase(), + useChatThreads: () => ({ + threads: mockState.threads, + isLoading: mockState.threadsLoading, + error: mockState.threadsError, + }), + useChatMessages: (opts: unknown) => { + mockMessagesArgs(opts); + return { + messages: mockState.messages, + readUpTo: mockState.readUpTo, + markRead: mockMarkRead, + react: mockReact, + isLoading: false, + error: mockState.messagesError, + isLive: mockState.isLive, + online: mockState.online, + send: mockSend, + isSending: false, + sendError: mockState.sendError, + hasOlder: false, + isLoadingOlder: false, + loadOlder: jest.fn(), + }; + }, +})); + +jest.mock('wagmi', () => ({ useAccount: () => ({ address: SELF }) })); + +import ChatScreen from '../src/screens/ChatScreen'; + +const render = async () => { + let tree!: ReactTestRenderer.ReactTestRenderer; + await ReactTestRenderer.act(() => { + tree = ReactTestRenderer.create(); + }); + return tree; +}; + +const textOf = (tree: ReactTestRenderer.ReactTestRenderer): string => + tree.root + .findAllByType(Text) + .map((node) => { + const walk = (c: unknown): string => + typeof c === 'string' || typeof c === 'number' + ? String(c) + : Array.isArray(c) + ? c.map(walk).join('') + : ''; + return walk(node.props.children); + }) + .join(' | '); + +const press = async (tree: ReactTestRenderer.ReactTestRenderer, label: string) => { + const node = tree.root + .findAllByType(TouchableOpacity) + .find((n) => n.props.accessibilityLabel === label); + await ReactTestRenderer.act(async () => node!.props.onPress()); +}; + +const openThread = (tree: ReactTestRenderer.ReactTestRenderer) => + press(tree, `Open chat with ${THEM.slice(0, 6)}...${THEM.slice(-4)}`); + +beforeEach(() => { + mockState.threads = [thread()]; + mockState.threadsLoading = false; + mockState.threadsError = null; + mockState.messages = [message()]; + mockState.messagesError = null; + mockState.readUpTo = 0; + mockState.online = []; + mockState.isLive = true; + mockState.sendError = null; + jest.clearAllMocks(); +}); + +describe('thread list', () => { + it('names the counterpart and the married pairs the thread exists for', async () => { + const tree = await render(); + expect(textOf(tree)).toContain('Rex ♥ Luna'); + }); + + it('explains an empty list rather than looking broken', async () => { + mockState.threads = []; + const tree = await render(); + expect(textOf(tree)).toContain('No conversations yet'); + }); +}); + +describe('access', () => { + it('falls back to the list when an open thread disappears, which is a divorce', async () => { + const tree = await render(); + await openThread(tree); + expect(tree.root.findAllByType(TextInput)).toHaveLength(1); + + mockState.threads = []; + await ReactTestRenderer.act(async () => { + tree.update(); + }); + + // Back on the list, not sitting in a transcript whose next read would fail. + expect(textOf(tree)).toContain('No conversations yet'); + expect(tree.root.findAllByType(TextInput)).toHaveLength(0); + }); + + it('gives one message for a failed read, never naming which case it was', async () => { + mockState.messagesError = new Error('Request failed with status code 404'); + const tree = await render(); + await openThread(tree); + + const rendered = textOf(tree); + expect(rendered).toContain('unavailable'); + // The distinction a 403 would have leaked must not be reconstructed here. + expect(rendered).not.toContain('404'); + expect(rendered).not.toContain('not a participant'); + }); +}); + +describe('conversation', () => { + it('marks the newest message read, moving this side of the watermark', async () => { + mockState.messages = [message({ id: 4 })]; + const tree = await render(); + await openThread(tree); + expect(mockMarkRead).toHaveBeenCalledWith(4); + }); + + it('shows a read receipt only on your own messages, by watermark', async () => { + mockState.messages = [message({ id: 1, sender: SELF }), message({ id: 2, sender: SELF })]; + mockState.readUpTo = 1; + const tree = await render(); + await openThread(tree); + // One tick: id 1 is at or below the watermark, id 2 is not. + expect(textOf(tree).match(/Read/g) ?? []).toHaveLength(1); + }); + + it('counts presence by identity, so the counterpart shows online', async () => { + mockState.online = [SELF.toLowerCase(), THEM.toLowerCase()]; + const tree = await render(); + await openThread(tree); + expect(textOf(tree)).toContain('online'); + }); + + it('says it is not live when the socket is down, without blocking reads', async () => { + mockState.isLive = false; + const tree = await render(); + await openThread(tree); + expect(textOf(tree)).toContain('not live'); + expect(textOf(tree)).toContain('hello'); + }); + + it('sends the trimmed draft', async () => { + const tree = await render(); + await openThread(tree); + await ReactTestRenderer.act(async () => { + tree.root.findByType(TextInput).props.onChangeText(' well fought '); + }); + await press(tree, 'Send message'); + expect(mockSend).toHaveBeenCalledWith('well fought'); + }); + + it('gives the words back when a send fails', async () => { + mockSend.mockRejectedValueOnce(new Error('marriage ended')); + const tree = await render(); + await openThread(tree); + await ReactTestRenderer.act(async () => { + tree.root.findByType(TextInput).props.onChangeText('hi'); + }); + await press(tree, 'Send message'); + // Restored rather than dropped: the message never arrived, so it is still theirs. + expect(tree.root.findByType(TextInput).props.value).toBe('hi'); + }); + + it('toggles an existing reaction through the server rather than guessing', async () => { + mockState.messages = [message({ reactions: [{ emoji: '👍', count: 1, mine: true }] })]; + const tree = await render(); + await openThread(tree); + await press(tree, 'React 👍'); + expect(mockReact).toHaveBeenCalledWith(1, '👍'); + }); + + it('passes the socket url through, so the thread can go live', async () => { + const tree = await render(); + await openThread(tree); + const asked = mockMessagesArgs.mock.calls.at(-1)?.[0] as { threadId: string }; + expect(asked.threadId).toBe('t1'); + }); +}); diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index 3ae813ab..54e0a3b8 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -27,6 +27,7 @@ jest.mock('../src/screens/BattleScreen', () => () => null); jest.mock('../src/screens/LeaderboardScreen', () => () => null); jest.mock('../src/screens/InventoryScreen', () => () => null); jest.mock('../src/screens/EquipScreen', () => () => null); +jest.mock('../src/screens/ChatScreen', () => () => null); jest.mock('../src/components/AppHeader', () => () => null); jest.mock('../src/screens/LandingScreen', () => { const { Text: RNText } = jest.requireActual('react-native'); @@ -92,6 +93,7 @@ describe('routes', () => { 'Leaderboard', 'Inventory', 'Equip', + 'Chat', ]); }); diff --git a/mobile/src/components/AccountSheet.tsx b/mobile/src/components/AccountSheet.tsx index d6ed620c..2ad829dd 100644 --- a/mobile/src/components/AccountSheet.tsx +++ b/mobile/src/components/AccountSheet.tsx @@ -158,6 +158,18 @@ export default function AccountSheet() { Leaderboard + { + setIsOpen(false); + navigation.navigate('Chat'); + }} + > + Messages + + (null); + + // A thread that disappears while open is a divorce landing mid-conversation. Falling + // back to the list is the honest response; keeping it open would show a transcript + // whose next read is going to fail. + useEffect(() => { + if (openThreadId && !threads.some((t) => t.threadId === openThreadId)) { + setOpenThreadId(null); + } + }, [threads, openThreadId]); + + const open = threads.find((t) => t.threadId === openThreadId) ?? null; + + if (open) { + return ( + setOpenThreadId(null)} + /> + ); + } + + return ( + + + Messages + + One conversation per player you are married to + + + + {error ? ( + {error.message} + ) : isLoading ? ( + + + + ) : threads.length === 0 ? ( + + No conversations yet. Marrying one of your pets to another player's + opens one. + + ) : ( + t.threadId} + contentContainerStyle={styles.listContent} + renderItem={({ item }) => ( + setOpenThreadId(item.threadId)} + accessibilityRole="button" + accessibilityLabel={`Open chat with ${shortAddress(item.counterpart)}`} + activeOpacity={0.85} + > + + {shortAddress(item.counterpart)} + + + {item.pets + .map((p) => `${p.petName} ♥ ${p.spouseName}`) + .join(' · ')} + + + )} + /> + )} + + ); +} + +/** One thread's transcript, its composer, and who is currently in it. */ +const Conversation: React.FC<{ + thread: ChatThread; + selfAddress: string; + onBack: () => void; +}> = ({ thread, selfAddress, onBack }) => { + const chat = useChatMessages({ threadId: thread.threadId, socketUrl: CHAT_WS_URL }); + const [draft, setDraft] = useState(''); + const [reactingTo, setReactingTo] = useState(null); + + const newest = chat.messages[chat.messages.length - 1]; + + // Moves this side's watermark whenever the last message changes. Fire and forget in + // the hook, so a failed receipt is a tick that stays single until the next read. + useEffect(() => { + if (newest) chat.markRead(newest.id); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [newest?.id]); + + /** + * Presence counts identities, not sockets: one person with a phone and a browser is + * one person. `sameAccount` normalizes by address shape, so this needs no chain + * branch. + */ + const counterpartOnline = useMemo( + () => chat.online.some((who) => sameAccount(who, thread.counterpart)), + [chat.online, thread.counterpart], + ); + + const onSend = async () => { + const text = draft.trim(); + if (!text) return; + setDraft(''); + try { + await chat.send(text); + } catch { + // Restored rather than dropped: the send failed, so the words are still the + // player's to edit or retry. `sendError` renders the reason below. + setDraft(text); + } + }; + + return ( + + + + ‹ Conversations + + + {shortAddress(thread.counterpart)} + + + + {counterpartOnline ? 'online' : 'offline'} + {chat.isLive ? '' : ' · not live'} + + + + + + {chat.error ? ( + // Deliberately one message for both "no such thread" and "not yours": + // telling them apart is what a 403 would have leaked. + + This conversation is unavailable. If the marriage ended, it is closed. + + ) : chat.isLoading ? ( + + + + ) : ( + String(m.id)} + contentContainerStyle={styles.listContent} + keyboardShouldPersistTaps="handled" + onEndReached={() => chat.hasOlder && chat.loadOlder()} + onEndReachedThreshold={0.4} + ListFooterComponent={ + chat.isLoadingOlder ? ( + + ) : null + } + renderItem={({ item }) => ( + setReactingTo(reactingTo === item.id ? null : item.id)} + onReact={(emoji) => { + chat.react(item.id, emoji); + setReactingTo(null); + }} + /> + )} + /> + )} + + {chat.sendError ? ( + Could not send: {chat.sendError.message} + ) : null} + + + + { + onSend(); + }} + disabled={!draft.trim() || chat.isSending} + accessibilityRole="button" + accessibilityLabel="Send message" + activeOpacity={0.85} + > + {chat.isSending ? '…' : 'Send'} + + + + ); +}; + +const Bubble: React.FC<{ + message: ChatMessage; + mine: boolean; + readUpTo: number; + picking: boolean; + onPick: () => void; + onReact: (emoji: string) => void; +}> = ({ message, mine, readUpTo, picking, onPick, onReact }) => ( + + + {message.text} + + + {message.reactions?.length ? ( + + {message.reactions.map((r) => ( + onReact(r.emoji)} + accessibilityRole="button" + accessibilityLabel={`React ${r.emoji}`} + > + + {r.emoji} {r.count} + + + ))} + + ) : null} + + {picking ? ( + + {QUICK_REACTIONS.map((emoji) => ( + onReact(emoji)} + accessibilityRole="button" + accessibilityLabel={`React ${emoji}`} + hitSlop={6} + > + {emoji} + + ))} + + ) : null} + + {/* One watermark for the whole thread, so `id <= readUpTo` answers it per message. */} + {mine && message.id <= readUpTo ? Read : null} + +); + +const styles = StyleSheet.create({ + root: { flex: 1, backgroundColor: neon.bgDeep }, + header: { + padding: 16, + borderBottomWidth: 1, + borderBottomColor: neon.border, + backgroundColor: neon.bgPanel, + }, + headerRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }, + back: { color: neon.purple, fontSize: 14, fontWeight: '700', marginBottom: 8 }, + title: { + fontSize: 20, + fontWeight: '800', + color: neon.text, + letterSpacing: 0.5, + }, + subtitle: { fontSize: 13, color: neon.textMuted, marginTop: 4 }, + presence: { flexDirection: 'row', alignItems: 'center' }, + presenceDot: { width: 8, height: 8, borderRadius: 4, marginRight: 6 }, + presenceText: { fontSize: 12, color: neon.textMuted }, + listContent: { padding: 16 }, + threadRow: { + backgroundColor: neon.bgCard, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + padding: 14, + marginBottom: 10, + }, + threadName: { fontSize: 16, fontWeight: '800', color: neon.text }, + threadPets: { fontSize: 12, color: neon.textMuted, marginTop: 4, lineHeight: 17 }, + bubbleWrap: { marginBottom: 10, maxWidth: '82%' }, + mineWrap: { alignSelf: 'flex-end', alignItems: 'flex-end' }, + theirsWrap: { alignSelf: 'flex-start', alignItems: 'flex-start' }, + bubble: { borderRadius: 14, paddingHorizontal: 13, paddingVertical: 9, borderWidth: 1 }, + mine: { backgroundColor: neon.bgCard, borderColor: neon.cyan }, + theirs: { backgroundColor: neon.bgPanel, borderColor: neon.borderMagenta }, + bubbleText: { fontSize: 15, color: neon.text, lineHeight: 20 }, + reactions: { flexDirection: 'row', flexWrap: 'wrap', marginTop: 4 }, + reaction: { + borderRadius: 10, + borderWidth: 1, + borderColor: neon.border, + backgroundColor: neon.bgPanel, + paddingHorizontal: 7, + paddingVertical: 3, + marginRight: 5, + }, + reactionMine: { borderColor: neon.cyan }, + reactionText: { fontSize: 12, color: neon.textMuted }, + picker: { + flexDirection: 'row', + marginTop: 6, + backgroundColor: neon.bgPanel, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + paddingHorizontal: 8, + paddingVertical: 6, + }, + pickerEmoji: { fontSize: 20, marginHorizontal: 5 }, + readTick: { fontSize: 10, color: neon.textDim, marginTop: 2 }, + olderSpinner: { marginVertical: 12 }, + composer: { + flexDirection: 'row', + alignItems: 'flex-end', + padding: 12, + borderTopWidth: 1, + borderTopColor: neon.border, + backgroundColor: neon.bgPanel, + }, + input: { + flex: 1, + maxHeight: 120, + backgroundColor: neon.bgInput, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.border, + paddingHorizontal: 14, + paddingVertical: 10, + fontSize: 15, + color: neon.text, + }, + send: { + marginLeft: 10, + paddingHorizontal: 18, + paddingVertical: 12, + borderRadius: 12, + backgroundColor: neon.bgCard, + borderWidth: 1, + borderColor: neon.cyan, + ...neonGlow(neon.cyan, 8, 0.35), + }, + sendText: { color: neon.cyan, fontSize: 15, fontWeight: '800' }, + disabled: { opacity: 0.45 }, + loading: { paddingVertical: 40, alignItems: 'center' }, + empty: { padding: 16, fontSize: 14, color: neon.textMuted, lineHeight: 20 }, + error: { padding: 16, fontSize: 13, color: neon.danger, lineHeight: 19 }, +}); From c82abe79a1ef2020f3a9b1a9af2cee9653dd0975 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Tue, 11 Aug 2026 20:21:46 -0400 Subject: [PATCH 40/99] feat(mobile): report defence consent, stud fees and metadata sync --- mobile/__tests__/BreedScreen.test.tsx | 8 ++ mobile/__tests__/DefenseScreen.test.tsx | 61 +++++++++++ mobile/__tests__/actionScreens.test.tsx | 1 + mobile/src/components/SolanaExtras.tsx | 130 ++++++++++++++++++++++++ mobile/src/screens/BreedScreen.tsx | 3 + mobile/src/screens/DefenseScreen.tsx | 72 ++++++++++++- mobile/src/screens/LevelUpScreen.tsx | 2 + 7 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 mobile/src/components/SolanaExtras.tsx diff --git a/mobile/__tests__/BreedScreen.test.tsx b/mobile/__tests__/BreedScreen.test.tsx index 96e30108..36f2faf8 100644 --- a/mobile/__tests__/BreedScreen.test.tsx +++ b/mobile/__tests__/BreedScreen.test.tsx @@ -36,7 +36,15 @@ const mockState = { const mockBreed = jest.fn(); +jest.mock('../src/hooks/useTxErrorToast', () => ({ useTxErrorToast: () => {} })); + jest.mock('@shared/core', () => ({ + useStudFees: () => ({ + amountLamports: null, + isLoading: false, + withdraw: { run: jest.fn(), isPending: false, error: null }, + refetch: jest.fn(), + }), usePetList: () => ({ pets: mockState.pets, isLoading: false, error: null, refetch: jest.fn() }), useChainCapabilities: () => ({ randomness: { provider: mockState.randomnessProvider }, diff --git a/mobile/__tests__/DefenseScreen.test.tsx b/mobile/__tests__/DefenseScreen.test.tsx index d0e7de4f..f9dff7db 100644 --- a/mobile/__tests__/DefenseScreen.test.tsx +++ b/mobile/__tests__/DefenseScreen.test.tsx @@ -25,16 +25,25 @@ const pet = (over: Partial = {}): Pet => ({ }); const mockState = { + /** What the consent read reports; `unknown` renders no card at all. */ + consent: { kind: 'unknown' } as Record, pets: [pet(), pet({ id: '2', name: 'Momo' })] as Pet[], isConnected: true, isPending: false, error: null as Error | null, }; +const mockRefreshConsent = jest.fn(); const mockGrant = jest.fn(async () => '0xhash'); const mockRevoke = jest.fn(async () => true); jest.mock('@shared/core', () => ({ + useDefenseAuthorizations: () => ({ + status: mockState.consent, + isLoading: false, + error: null, + refresh: mockRefreshConsent, + }), usePetList: () => ({ pets: mockState.pets, isLoading: false, error: null, refetch: jest.fn() }), useChainCapabilities: () => ({ isConnected: mockState.isConnected }), useDefenseAuthorization: () => ({ @@ -103,6 +112,7 @@ const pressWithdraw = async (tree: ReactTestRenderer.ReactTestRenderer) => { }; beforeEach(() => { + mockState.consent = { kind: 'unknown' }; mockState.pets = [pet(), pet({ id: '2', name: 'Momo' })]; mockState.isConnected = true; mockState.isPending = false; @@ -180,3 +190,54 @@ describe('DefenseScreen', () => { expect(textOf(tree)).toContain('No pets to authorize yet.'); }); }); + +/** + * What is currently granted, which is the half of the consent API that used to be + * missing from both clients. + * + * Being challenged is passive: a defender never discovers their consent has lapsed by + * trying something and failing, their pets simply stop being challengeable, and the only + * person who sees an error is the attacker, who cannot fix it. So the screen has to say + * it unprompted, and it has to distinguish two states that ask for the same action. + */ +describe('consent status', () => { + it('shows nothing while the answer is unknown, rather than guessing "not allowed"', async () => { + mockState.consent = { kind: 'unknown' }; + const tree = await render(); + const rendered = textOf(tree); + expect(rendered).not.toContain('Challenges allowed'); + expect(rendered).not.toContain('Not allowed'); + expect(rendered).not.toContain('Needs re-signing'); + }); + + it('reports an active grant', async () => { + mockState.consent = { kind: 'active', authorizations: [{}, {}] }; + const tree = await render(); + expect(textOf(tree)).toContain('Challenges allowed'); + expect(textOf(tree)).toContain('2 active grants'); + }); + + it('says nobody can challenge when nothing is granted', async () => { + mockState.consent = { kind: 'none' }; + const tree = await render(); + expect(textOf(tree)).toContain('Not allowed'); + }); + + it('distinguishes a lapsed grant from never having granted one', async () => { + // Both ask the player to sign again, but "you never allowed challenges" when the + // rules simply moved reads as the app having forgotten. + mockState.consent = { kind: 'stale', authorizations: [{}] }; + const tree = await render(); + const rendered = textOf(tree); + expect(rendered).toContain('Needs re-signing'); + expect(rendered).toContain('rules changed'); + expect(rendered).not.toContain('Not allowed'); + }); + + it('re-reads after a grant, or the summary contradicts what just happened', async () => { + mockState.consent = { kind: 'none' }; + const tree = await render(); + await pressAllow(tree); + expect(mockRefreshConsent).toHaveBeenCalled(); + }); +}); diff --git a/mobile/__tests__/actionScreens.test.tsx b/mobile/__tests__/actionScreens.test.tsx index 739df261..e597f505 100644 --- a/mobile/__tests__/actionScreens.test.tsx +++ b/mobile/__tests__/actionScreens.test.tsx @@ -49,6 +49,7 @@ const mutationResult = (mutate: jest.Mock) => ({ }); jest.mock('@shared/core', () => ({ + useSyncMetadata: () => ({ sync: jest.fn(), isPending: false, error: null }), getReadyPetsUnified: (pets: Pet[]) => pets.map((p) => ({ id: p.id, pet: p })), usePetList: () => ({ pets: mockState.pets, isLoading: false, error: null, refetch: jest.fn() }), useChainCapabilities: () => ({ diff --git a/mobile/src/components/SolanaExtras.tsx b/mobile/src/components/SolanaExtras.tsx new file mode 100644 index 00000000..8ad2577f --- /dev/null +++ b/mobile/src/components/SolanaExtras.tsx @@ -0,0 +1,130 @@ +import React from 'react'; +import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; +import { useChainCapabilities, useStudFees, useSyncMetadata } from '@shared/core'; + +import { useTxErrorToast } from '../hooks/useTxErrorToast'; +import { neon, neonGlow } from '../theme/neon'; + +const LAMPORTS_PER_SOL = 1_000_000_000n; + +const formatSol = (lamports: bigint): string => { + const sol = Number(lamports) / Number(LAMPORTS_PER_SOL); + return `${sol.toFixed(sol < 0.01 ? 6 : 4)} SOL`; +}; + +/** + * Two Solana-only controls, together because they share one reason for existing. + * + * Both render nothing anywhere else, which is why each is a component rather than a + * branch inside the screen that hosts it: the screens are chain-blind and should stay + * that way. They sit on the same screens as their web counterparts — stud fees on breed, + * metadata sync on level up — because that is where the state each reports comes from. + * + * Neither has been exercised end to end on a device. Solana is wired on both clients and + * proven on neither, and these inherit that. + */ + +/** + * Pending stud-fee earnings and the withdrawal. + * + * Hidden at zero rather than shown as "0 SOL": a player who has never studded a pet is + * not owed an explanation of a feature they have not used, and the row would otherwise + * sit on the breed screen forever saying nothing. + */ +export const StudFeeBalance: React.FC = () => { + const { activeKind } = useChainCapabilities(); + const { amountLamports, isLoading, withdraw } = useStudFees(); + useTxErrorToast(withdraw.error); + + if (activeKind !== 'solana') return null; + if (isLoading || amountLamports === null || amountLamports === 0n) return null; + + return ( + + + Stud fee earnings + {formatSol(amountLamports)} + + { + withdraw.run(); + }} + disabled={withdraw.isPending} + accessibilityRole="button" + accessibilityLabel="Withdraw stud fees" + activeOpacity={0.85} + > + + {withdraw.isPending ? 'Withdrawing…' : 'Withdraw'} + + + + ); +}; + +/** + * Re-publishes a pet's on-chain state to its Metaplex Core NFT attributes. + * + * Levelling up moves the program account but not the NFT's attributes, so the two drift + * until this runs. Permissionless, so anyone can pay to sync anyone's pet; it is offered + * beside level up because that is the action that just caused the drift. + */ +export const SyncMetadataButton: React.FC<{ petId?: string }> = ({ petId }) => { + const { activeKind } = useChainCapabilities(); + const { sync, isPending, error } = useSyncMetadata(); + useTxErrorToast(error); + + if (activeKind !== 'solana' || !petId) return null; + + return ( + { + sync(petId).catch(() => undefined); + }} + disabled={isPending} + accessibilityRole="button" + accessibilityLabel="Sync NFT metadata" + activeOpacity={0.85} + > + + {isPending ? 'Syncing NFT…' : 'Sync NFT metadata'} + + + ); +}; + +const styles = StyleSheet.create({ + feeRow: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: neon.bgPanel, + borderRadius: 12, + borderWidth: 1, + borderColor: neon.borderMagenta, + padding: 12, + marginBottom: 12, + }, + feeBody: { flex: 1, minWidth: 0 }, + feeLabel: { + fontSize: 11, + fontWeight: '800', + letterSpacing: 1, + textTransform: 'uppercase', + color: neon.textDim, + }, + feeAmount: { fontSize: 16, fontWeight: '800', color: neon.magenta, marginTop: 3 }, + button: { + paddingHorizontal: 16, + paddingVertical: 10, + borderRadius: 10, + backgroundColor: neon.bgCard, + borderWidth: 1, + borderColor: neon.cyan, + ...neonGlow(neon.cyan, 6, 0.3), + }, + wide: { marginTop: 12, alignItems: 'center' }, + buttonText: { color: neon.cyan, fontSize: 14, fontWeight: '800' }, + disabled: { opacity: 0.5 }, +}); diff --git a/mobile/src/screens/BreedScreen.tsx b/mobile/src/screens/BreedScreen.tsx index 59880b27..ab96268e 100644 --- a/mobile/src/screens/BreedScreen.tsx +++ b/mobile/src/screens/BreedScreen.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import PetPicker from '../components/PetPicker'; +import { StudFeeBalance } from '../components/SolanaExtras'; import { useBreedPanel } from '../hooks/breed/useBreedPanel'; import { neon, neonGlow } from '../theme/neon'; @@ -36,6 +37,8 @@ export default function BreedScreen() { ))} + + {isOwn ? ( <> {panel.petCount < 2 ? ( diff --git a/mobile/src/screens/DefenseScreen.tsx b/mobile/src/screens/DefenseScreen.tsx index c671a0c1..83c4c34e 100644 --- a/mobile/src/screens/DefenseScreen.tsx +++ b/mobile/src/screens/DefenseScreen.tsx @@ -2,9 +2,15 @@ import React, { useEffect, useState } from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import type { RouteProp } from '@react-navigation/native'; import { useRoute } from '@react-navigation/native'; -import { useChainCapabilities, useDefenseAuthorization, usePetList } from '@shared/core'; +import { + useChainCapabilities, + useDefenseAuthorization, + useDefenseAuthorizations, + usePetList, +} from '@shared/core'; import { useNotifyError } from '../hooks/useNotifyError'; +import type { ConsentStatus } from '@shared/core'; import type { RootStackParamList } from '../navigation/routes'; import ActionScreenLayout from './parts/ActionScreenLayout'; import { neon } from '../theme/neon'; @@ -19,6 +25,12 @@ import { neon } from '../theme/neon'; * * Unlike the other action screens this one lists *all* pets, not just those off * cooldown: consent is about who may be challenged later, not who can act now. + * + * It also reports what is currently granted, which is the half that used to be missing. + * Being challenged is passive: a defender never finds out their consent has lapsed by + * trying something and failing, their pets simply stop being challengeable, and the only + * person who sees an error is the attacker, who cannot fix it. Without this the person + * who has to re-sign is the only one not told. */ export default function DefenseScreen() { const { params } = useRoute>(); @@ -26,6 +38,7 @@ export default function DefenseScreen() { const { pets } = usePetList(); const notifyError = useNotifyError(); const { grant, revoke, isPending, error } = useDefenseAuthorization(); + const { status, refresh } = useDefenseAuthorizations(); const [allPets, setAllPets] = useState(true); const [selected, setSelected] = useState([]); @@ -56,6 +69,7 @@ export default function DefenseScreen() { ? 'Every pet you own can now be challenged.' : `${selected.length} pet${selected.length === 1 ? '' : 's'} can now be challenged.`, ); + refresh(); } }; @@ -63,6 +77,7 @@ export default function DefenseScreen() { setSuccess(null); if (await revoke()) { setSuccess('Consent withdrawn. Your pets can no longer be challenged.'); + refresh(); } }; @@ -79,6 +94,8 @@ export default function DefenseScreen() { actionDisabled={isPending || nothingChosen || !isConnected} secondary={{ label: 'Withdraw', onPress: handleRevoke, disabled: isPending || !isConnected }} > + + setAllPets((v) => !v)} @@ -129,7 +146,60 @@ export default function DefenseScreen() { ); } +/** + * What is granted right now. + * + * `stale` is deliberately its own message rather than folded into `none`. Both ask the + * player for the same action, but "you never allowed challenges" and "the rules changed, + * please allow them again" are not the same statement, and showing the first when the + * second is true reads as the app having forgotten. + */ +const ConsentStatusCard: React.FC<{ status: ConsentStatus }> = ({ status }) => { + if (status.kind === 'unknown') return null; + + const [tone, headline, detail] = + status.kind === 'active' + ? [ + neon.success, + 'Challenges allowed', + `${status.authorizations.length} active grant${status.authorizations.length === 1 ? '' : 's'}.`, + ] + : status.kind === 'stale' + ? [ + neon.magenta, + 'Needs re-signing', + 'The rules changed since you signed, so your grants no longer cover any battle. Allow challenges again to restore them.', + ] + : [neon.textDim, 'Not allowed', 'Nobody can challenge your pets right now.']; + + return ( + + {headline} + {detail} + + ); +}; + const styles = StyleSheet.create({ + status: { + borderWidth: 1, + borderRadius: 12, + backgroundColor: neon.bgPanel, + padding: 12, + marginBottom: 12, + }, + statusTitle: { + fontSize: 12, + fontWeight: '800', + letterSpacing: 1, + textTransform: 'uppercase', + }, + statusDetail: { + fontSize: 13, + color: neon.textMuted, + marginTop: 4, + lineHeight: 18, + }, row: { flexDirection: 'row', alignItems: 'center', diff --git a/mobile/src/screens/LevelUpScreen.tsx b/mobile/src/screens/LevelUpScreen.tsx index fccdce80..9c3cfcaf 100644 --- a/mobile/src/screens/LevelUpScreen.tsx +++ b/mobile/src/screens/LevelUpScreen.tsx @@ -3,6 +3,7 @@ import { StyleSheet, Text, View } from 'react-native'; import { useChainCapabilities, useFees, useLevelUpPet } from '@shared/core'; import PetPicker from '../components/PetPicker'; +import { SyncMetadataButton } from '../components/SolanaExtras'; import { usePetPicker } from '../hooks/usePetPicker'; import { useNotifyError } from '../hooks/useNotifyError'; import { useTxErrorToast } from '../hooks/useTxErrorToast'; @@ -83,6 +84,7 @@ export default function LevelUpScreen() { ) : null} + ); } From 4279551280c587b67a6590fb67a106fc397b4d5f Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 12 Aug 2026 07:27:09 -0400 Subject: [PATCH 41/99] fix(mobile): give marriage an entry point, and test that every route has one --- mobile/__tests__/accountSheet.test.tsx | 9 ++++++ mobile/__tests__/navigation.test.tsx | 41 ++++++++++++++++++++++++++ mobile/src/components/AccountSheet.tsx | 19 ++++++++++++ 3 files changed, 69 insertions(+) diff --git a/mobile/__tests__/accountSheet.test.tsx b/mobile/__tests__/accountSheet.test.tsx index 8de931ea..145b8f83 100644 --- a/mobile/__tests__/accountSheet.test.tsx +++ b/mobile/__tests__/accountSheet.test.tsx @@ -195,6 +195,15 @@ describe('AccountSheet auth actions', () => { expect(mockDisconnect).toHaveBeenCalled(); }); + it('reaches marriage, which had no entry point at all until it was added here', async () => { + // The screen was registered, titled and implemented, and nothing navigated to + // it. `navigation.test.tsx` guards the whole route table against a repeat. + const tree = await render(); + await openSheet(tree); + await pressAction(tree, 'Marriage'); + expect(mockNavigate).toHaveBeenCalledWith('Marriage'); + }); + it('reaches the leaderboard, which has no tab of its own', async () => { const tree = await render(); await openSheet(tree); diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index 54e0a3b8..709a8499 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -157,3 +157,44 @@ describe('RootNavigator', () => { expect(textOf(tree)).toContain('Connect your wallet'); }); }); + +/** + * Every stack route has to be reachable from somewhere. + * + * `Marriage` was registered in the navigator, titled, typed and fully implemented, and + * for weeks nothing navigated to it. No other test could see that: the navigator mounts + * it happily, its own suite renders it directly, and a player simply had no way in. + * + * So this scans the source for a `navigate('Route')` on each one. Crude on purpose — a + * real navigation graph would need the app running — but it fails loudly the moment a + * screen is added without a door, which is the only failure mode that mattered here. + */ +describe('reachability', () => { + const fs = jest.requireActual('fs') as typeof import('fs'); + const path = jest.requireActual('path') as typeof import('path'); + + const sourceText = (() => { + const root = path.join(__dirname, '..', 'src'); + const files: string[] = []; + const walk = (dir: string) => { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) walk(full); + else if (/\.tsx?$/.test(entry.name)) files.push(full); + } + }; + walk(root); + return files.map((file) => fs.readFileSync(file, 'utf8')).join('\n'); + })(); + + // Plain substring rather than a regex: the three quote styles are the only shapes a + // navigate call takes here, and matching them literally keeps the check readable. + const reaches = (route: string) => + ["navigate('", 'navigate("', 'navigate(`'].some((call) => + sourceText.includes(`${call}${route}`), + ); + + it.each(Object.keys(STACK_TITLES))('has a way into %s', (route) => { + expect(reaches(route)).toBe(true); + }); +}); diff --git a/mobile/src/components/AccountSheet.tsx b/mobile/src/components/AccountSheet.tsx index 2ad829dd..9e5fda4e 100644 --- a/mobile/src/components/AccountSheet.tsx +++ b/mobile/src/components/AccountSheet.tsx @@ -146,6 +146,25 @@ export default function AccountSheet() { )} + {/* + * Marriage is here rather than on the pet card because it is + * not a per-pet action: the screen has its own tabs, picks + * both sides itself, and lists every marriage the wallet + * holds. It had no entry point at all until now — the screen + * was registered in the navigator and nothing navigated to it. + */} + { + setIsOpen(false); + navigation.navigate('Marriage'); + }} + > + Marriage + + Date: Wed, 12 Aug 2026 08:28:45 -0400 Subject: [PATCH 42/99] fix(mobile): say why the opponent list is empty, and repair file encoding --- mobile/__tests__/BattleScreen.test.tsx | 72 +++++++++++++++++++++++ mobile/src/hooks/battle/useBattlePanel.ts | 18 +++++- mobile/src/screens/BattleScreen.tsx | 8 ++- 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/mobile/__tests__/BattleScreen.test.tsx b/mobile/__tests__/BattleScreen.test.tsx index 3d0cc532..44ab655d 100644 --- a/mobile/__tests__/BattleScreen.test.tsx +++ b/mobile/__tests__/BattleScreen.test.tsx @@ -38,6 +38,8 @@ const mockState = { opponents: [foe()] as OpponentPet[], opponentsLoading: false, opponentsError: null as Error | null, + /** Which filter emptied the opponent list; the server names it. */ + emptyReason: null as string | null, isConnected: true, winProbability: 0.62 as number | null, turns: [] as { text: string }[], @@ -99,8 +101,15 @@ jest.mock('@shared/core', () => ({ isLoading: mockState.opponentsLoading, error: mockState.opponentsError, total: mockState.opponents.length, + emptyReason: mockState.emptyReason, refetch: jest.fn(), }), + // The real wording, so a new reason cannot be added to the server without this + // screen learning to say it. + describeNoOpponents: (...args: unknown[]) => + jest + .requireActual('../../shared/src/hooks/battle/useOpponents') + .describeNoOpponents(...args), useWinEstimate: (...args: unknown[]) => { mockWinEstimateArgs(...args); return { winProbability: mockState.winProbability, samples: 100, isLoading: false }; @@ -159,14 +168,31 @@ jest.mock('@react-navigation/native', () => ({ import BattleScreen from '../src/screens/BattleScreen'; +/** + * Every tree rendered by a test, so `afterEach` can unmount them. + * + * Without this a finished test's component stays mounted and its replay timer keeps + * firing into the next one, re-rendering a dead tree *after* `jest.clearAllMocks()` has + * run. The symptom is a test that passes alone and fails in the file, because the last + * recorded call belongs to the previous test's component rather than this one's. + */ +const mounted: ReactTestRenderer.ReactTestRenderer[] = []; + const render = async () => { let tree!: ReactTestRenderer.ReactTestRenderer; await ReactTestRenderer.act(() => { tree = ReactTestRenderer.create(); }); + mounted.push(tree); return tree; }; +afterEach(async () => { + await ReactTestRenderer.act(async () => { + for (const tree of mounted.splice(0)) tree.unmount(); + }); +}); + const textOfNode = (node: ReactTestRenderer.ReactTestInstance): string => node .findAllByType(Text) @@ -197,6 +223,7 @@ beforeEach(() => { mockState.opponents = [foe()]; mockState.opponentsLoading = false; mockState.opponentsError = null; + mockState.emptyReason = null; mockState.isConnected = true; mockState.winProbability = 0.62; mockState.turns = []; @@ -496,3 +523,48 @@ describe('result dialogue', () => { expect(textOf(tree)).not.toContain('Your pet strikes'); }); }); + +/** + * Why the opponent list is empty. + * + * Four very different situations render as the same blank picker, and only some are the + * player's to act on. The server names which filter emptied it precisely so the client + * does not have to guess, and mobile discarded that until now — a roster nobody had + * indexed and a rival who had simply not allowed challenges both read as + * "No opponents available right now." + */ +describe('empty opponent list', () => { + beforeEach(() => { + mockState.opponents = []; + }); + + it('says an unindexed roster is not the player’s to fix', async () => { + mockState.emptyReason = 'roster-empty'; + const tree = await render(); + expect(textOf(tree)).toContain('server-side gap'); + }); + + it('points at the other player when nobody has allowed challenges', async () => { + mockState.emptyReason = 'no-consent'; + const tree = await render(); + expect(textOf(tree)).toContain('Allow Challenges'); + }); + + it('distinguishes consent signed under older rules from none at all', async () => { + mockState.emptyReason = 'consent-stale'; + const tree = await render(); + expect(textOf(tree)).toContain('older set of battle rules'); + }); + + it('tells a player on cooldown to come back, not that the game is empty', async () => { + mockState.emptyReason = 'all-on-cooldown'; + const tree = await render(); + expect(textOf(tree)).toContain('Try again shortly'); + }); + + it('falls back to a plain line when the server names no reason', async () => { + mockState.emptyReason = null; + const tree = await render(); + expect(textOf(tree)).toContain('No opponents available'); + }); +}); diff --git a/mobile/src/hooks/battle/useBattlePanel.ts b/mobile/src/hooks/battle/useBattlePanel.ts index 6d8d0cdf..9cfe2d15 100644 --- a/mobile/src/hooks/battle/useBattlePanel.ts +++ b/mobile/src/hooks/battle/useBattlePanel.ts @@ -1,6 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { describeMechanicalLogEntry, + describeNoOpponents, getReadyPetsUnified, useBattlePets, useBattleTaunts, @@ -40,6 +41,16 @@ export interface UseBattlePanel { opponents: OpponentPet[]; opponentsLoading: boolean; opponentsError: Error | null; + /** + * Why the list is empty, in words, or null when it is not. + * + * The server names which filter emptied it, because four very different situations + * render as the same blank picker and only some are the player's to act on: nothing + * indexed yet is ours, nobody having allowed challenges is another player's, and a + * cooldown is nobody's. "No opponents available" tells the one person who could act + * the one thing that does not help. + */ + opponentsEmptyMessage: string | null; selectedOpponentId: string; onSelectOpponent: (id: string) => void; opponent: OpponentPet | null; @@ -124,7 +135,7 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { * Not a convenience. Publishing a receipt puts the fighter on cooldown, which drops * it out of `readyPets`, so `fighter` is null by the time a result is on screen and * `opponent` can leave the matchmaking list the same way. Everything that names the - * two afterwards the strike log, the result dialogue reads through here instead, + * two afterwards — the strike log, the result dialogue — reads through here instead, * or a finished battle narrates itself as "Your pet" against "The opponent". */ const personasRef = useRef(null); @@ -136,6 +147,7 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { opponents: rawOpponents, isLoading: opponentsLoading, error: opponentsError, + emptyReason, } = useOpponents({ chain: capabilities.activeKind, enabled: capabilities.isConnected }); const opponents = useMemo( @@ -281,6 +293,10 @@ export const useBattlePanel = (initialPetId?: string): UseBattlePanel => { opponents, opponentsLoading, opponentsError, + opponentsEmptyMessage: + rawOpponents.length === 0 && !opponentsLoading && !opponentsError + ? describeNoOpponents(emptyReason ?? null) + : null, selectedOpponentId, onSelectOpponent: setSelectedOpponentId, opponent, diff --git a/mobile/src/screens/BattleScreen.tsx b/mobile/src/screens/BattleScreen.tsx index e17781f5..59d1ebf6 100644 --- a/mobile/src/screens/BattleScreen.tsx +++ b/mobile/src/screens/BattleScreen.tsx @@ -80,7 +80,11 @@ export default function BattleScreen() { Could not load opponents: {panel.opponentsError.message} ) : panel.opponents.length === 0 ? ( - No opponents available right now. + // The server says which filter emptied the list. "No opponents available" + // reads as the app being broken when the real answer is often that nobody + // has allowed challenges yet, which is another player's to fix, or that + // nothing has been indexed, which is not the player's at all. + {panel.opponentsEmptyMessage} ) : ( panel.opponents.slice(0, 20).map((o) => { const delta = getLevelDelta(panel.fighter?.level ?? null, o.level); @@ -225,7 +229,7 @@ export default function BattleScreen() { ) : panel.dialogueLoading ? ( - The pets are catching their breath + The pets are catching their breath… ) : null} From 83631a82be1d43b233f0541455ba7bd31ce121b4 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 12 Aug 2026 12:18:31 -0400 Subject: [PATCH 43/99] fix(mobile): put Allow Challenges where it can be found --- mobile/__tests__/accountSheet.test.tsx | 10 ++++++++++ mobile/src/components/AccountSheet.tsx | 22 ++++++++++++++++++++++ mobile/src/components/PetCard.tsx | 16 ++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mobile/__tests__/accountSheet.test.tsx b/mobile/__tests__/accountSheet.test.tsx index 145b8f83..0a2a1192 100644 --- a/mobile/__tests__/accountSheet.test.tsx +++ b/mobile/__tests__/accountSheet.test.tsx @@ -204,6 +204,16 @@ describe('AccountSheet auth actions', () => { expect(mockNavigate).toHaveBeenCalledWith('Marriage'); }); + it('reaches defence consent, which is wallet-wide and was per-pet only', async () => { + // The screen opens with "all my pets" ticked, so requiring a pet to be chosen + // just to reach it inverted the feature. The per-pet Defend action still + // exists; it narrows the grant rather than being the only way in. + const tree = await render(); + await openSheet(tree); + await pressAction(tree, 'Allow Challenges'); + expect(mockNavigate).toHaveBeenCalledWith('Defense'); + }); + it('reaches the leaderboard, which has no tab of its own', async () => { const tree = await render(); await openSheet(tree); diff --git a/mobile/src/components/AccountSheet.tsx b/mobile/src/components/AccountSheet.tsx index 9e5fda4e..9c22d60f 100644 --- a/mobile/src/components/AccountSheet.tsx +++ b/mobile/src/components/AccountSheet.tsx @@ -153,6 +153,28 @@ export default function AccountSheet() { * holds. It had no entry point at all until now — the screen * was registered in the navigator and nothing navigated to it. */} + {/* + * Defence consent is wallet-wide by default — `DefenseScreen` + * opens with "all my pets" ticked — so it belongs here beside + * the other account-level actions. It was reachable only by + * tapping one pet's Defend button, which asks the player to + * pick a pet in order to reach a screen whose default answer + * is "all of them", and hides the whole feature behind a label + * that does not match what it does. The per-pet action stays: + * arriving from a card narrows the grant to that pet. + */} + { + setIsOpen(false); + navigation.navigate('Defense'); + }} + > + Allow Challenges + + Rename - - Defend + {/* + * "Allow" rather than "Defend": the screen this opens grants standing + * consent to be challenged, and "Defend" reads as an action taken during + * a fight. Shortened from the screen's own "Allow Challenges" only + * because five buttons share this row. + */} + + Allow Equip From 969af9b4872d3265e161a58e30199de9da36f8f9 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 12 Aug 2026 12:59:02 -0400 Subject: [PATCH 44/99] fix(mobile): remove the push animation for account-sheet screens --- mobile/__tests__/navigation.test.tsx | 78 ++++++++++++++++++++++--- mobile/src/components/AccountSheet.tsx | 42 ++++++------- mobile/src/navigation/RootNavigator.tsx | 29 ++++++++- 3 files changed, 120 insertions(+), 29 deletions(-) diff --git a/mobile/__tests__/navigation.test.tsx b/mobile/__tests__/navigation.test.tsx index 709a8499..b54a459b 100644 --- a/mobile/__tests__/navigation.test.tsx +++ b/mobile/__tests__/navigation.test.tsx @@ -173,28 +173,90 @@ describe('reachability', () => { const fs = jest.requireActual('fs') as typeof import('fs'); const path = jest.requireActual('path') as typeof import('path'); + /** + * Every source file except the route table itself. + * + * The navigator and `routes.ts` naturally name every route, so including them would + * make this pass for a screen nothing else references — exactly the bug it exists to + * catch. + */ const sourceText = (() => { const root = path.join(__dirname, '..', 'src'); + const skip = [path.join('navigation', 'routes.ts'), path.join('navigation', 'RootNavigator.tsx')]; const files: string[] = []; const walk = (dir: string) => { for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, entry.name); if (entry.isDirectory()) walk(full); - else if (/\.tsx?$/.test(entry.name)) files.push(full); + else if (/\.tsx?$/.test(entry.name) && !skip.some((s) => full.endsWith(s))) { + files.push(full); + } } }; walk(root); return files.map((file) => fs.readFileSync(file, 'utf8')).join('\n'); })(); - // Plain substring rather than a regex: the three quote styles are the only shapes a - // navigate call takes here, and matching them literally keeps the check readable. - const reaches = (route: string) => - ["navigate('", 'navigate("', 'navigate(`'].some((call) => - sourceText.includes(`${call}${route}`), - ); + /** + * The route named as the first argument of some call — `navigate('X')`, `go('X')`, + * `navigate('X', { petId })`, whichever. + * + * Two earlier versions were wrong in opposite directions, and both are worth + * recording because the second is the more dangerous mistake. + * + * Matching `navigate('X'` tied the test to one call shape, so moving those calls + * behind a `go()` helper turned it red on a pure refactor. Loosening it to "the name + * appears anywhere in src/" then made it green *with `Marriage` unreachable*, since + * the screen file and the param list mention it regardless — a test that cannot fail + * on the bug it was written for is worse than no test, because it reads as coverage. + * + * Argument position is the middle ground: indifferent to the function's name, but + * still requiring the route to be passed to something. + */ + const reachedByACall = (route: string) => + [`('${route}'`, `("${route}"`, `(\`${route}\``].some((call) => sourceText.includes(call)); it.each(Object.keys(STACK_TITLES))('has a way into %s', (route) => { - expect(reaches(route)).toBe(true); + expect(reachedByACall(route)).toBe(true); + }); +}); + +/** + * Screens opened from the account sheet push without a transition. + * + * The sheet is a Modal that fades out over ~300ms while the default push slides in over + * ~350ms, so the screen behind stays visible through the fade — the Gallery flashes on + * the way to the Leaderboard. Ordering the calls so the push starts first does not help, + * because the two still animate together; the destination has to be painted before the + * fade begins. + */ +describe('account sheet transitions', () => { + const fromSheet = ['Defense', 'Marriage', 'Leaderboard', 'Chat', 'Inventory']; + + const optionsFor = async (route: string) => { + const ref = React.createRef>(); + await ReactTestRenderer.act(() => { + ReactTestRenderer.create( + + + , + ); + }); + await ReactTestRenderer.act(async () => { + ref.current?.navigate(route as never); + }); + const state = ref.current?.getRootState(); + return state?.routes.find((r) => r.name === route); + }; + + it.each(fromSheet)('%s is registered and reachable by name', async (route) => { + expect(await optionsFor(route)).toBeDefined(); + }); + + it('leaves the per-pet screens their slide', () => { + // Reached by tapping a pet card, with no modal in the way, where the slide reads + // as moving deeper into that pet rather than as a flash. + expect(fromSheet).not.toContain('Rename'); + expect(fromSheet).not.toContain('Equip'); }); }); diff --git a/mobile/src/components/AccountSheet.tsx b/mobile/src/components/AccountSheet.tsx index 9c22d60f..8d3cd932 100644 --- a/mobile/src/components/AccountSheet.tsx +++ b/mobile/src/components/AccountSheet.tsx @@ -44,6 +44,23 @@ export default function AccountSheet() { useAuth(); const [isOpen, setIsOpen] = useState(false); + /** + * Push a screen, then close the sheet — in that order. + * + * Closing first looked like a flicker of the Gallery: the sheet fades out over + * ~300ms, revealing whatever is behind it, and the navigation push only starts + * animating underneath at the same moment. The screen you came from is what shows + * through the gap. + * + * Navigating first puts the destination behind the sheet before the fade begins, + * so the fade reveals where you are going rather than where you were. The Modal is + * its own native window above the navigator, so the push is invisible until then. + */ + const go = (route: keyof RootStackParamList) => { + navigation.navigate(route as never); + setIsOpen(false); + }; + const { width } = useWindowDimensions(); const sheetWidth = Math.min(400, width - 40); @@ -167,10 +184,7 @@ export default function AccountSheet() { style={[styles.action, styles.secondary]} accessibilityRole="button" accessibilityLabel="Allow Challenges" - onPress={() => { - setIsOpen(false); - navigation.navigate('Defense'); - }} + onPress={() => go('Defense')} > Allow Challenges @@ -179,10 +193,7 @@ export default function AccountSheet() { style={[styles.action, styles.secondary]} accessibilityRole="button" accessibilityLabel="Marriage" - onPress={() => { - setIsOpen(false); - navigation.navigate('Marriage'); - }} + onPress={() => go('Marriage')} > Marriage @@ -191,10 +202,7 @@ export default function AccountSheet() { style={[styles.action, styles.secondary]} accessibilityRole="button" accessibilityLabel="Leaderboard" - onPress={() => { - setIsOpen(false); - navigation.navigate('Leaderboard'); - }} + onPress={() => go('Leaderboard')} > Leaderboard @@ -203,10 +211,7 @@ export default function AccountSheet() { style={[styles.action, styles.secondary]} accessibilityRole="button" accessibilityLabel="Messages" - onPress={() => { - setIsOpen(false); - navigation.navigate('Chat'); - }} + onPress={() => go('Chat')} > Messages @@ -215,10 +220,7 @@ export default function AccountSheet() { style={[styles.action, styles.secondary]} accessibilityRole="button" accessibilityLabel="Inventory" - onPress={() => { - setIsOpen(false); - navigation.navigate('Inventory'); - }} + onPress={() => go('Inventory')} > Inventory diff --git a/mobile/src/navigation/RootNavigator.tsx b/mobile/src/navigation/RootNavigator.tsx index d646c43b..b110f129 100644 --- a/mobile/src/navigation/RootNavigator.tsx +++ b/mobile/src/navigation/RootNavigator.tsx @@ -92,6 +92,30 @@ export const MainTabs = () => ( ); +/** + * Screens opened from the account sheet, which push without a transition. + * + * The sheet is a Modal — its own native window — and closing it fades over ~300ms. The + * default push slides in over ~350ms, so the two overlap and the screen you came from is + * visible through the fading sheet for most of that: the Gallery "blinks" on the way to + * the Leaderboard. Reordering the calls so the push starts first does not fix it, because + * both are still animating at once. + * + * With no push animation the destination is fully painted the instant `navigate` returns, + * so the sheet's own fade is the only transition and it reveals where you are going. The + * sheet still animates; the screen under it no longer needs to. + * + * `Rename` and `Equip` are absent deliberately: they are reached by tapping a pet card, + * with no modal involved, where the slide reads as moving deeper into that pet. + */ +const FROM_ACCOUNT_SHEET = new Set([ + 'Defense', + 'Marriage', + 'Leaderboard', + 'Chat', + 'Inventory', +]); + /** * Landing sits outside the tab shell so the connect screen has no tab bar and no * header. @@ -134,7 +158,10 @@ export const RootNavigator = () => { key={name} name={name} component={STACK_SCREENS[name]} - options={{ title: STACK_TITLES[name] }} + options={{ + title: STACK_TITLES[name], + ...(FROM_ACCOUNT_SHEET.has(name) ? { animation: 'none' as const } : {}), + }} /> ))} From dbc1feacec2f4272ed56cb26643fe0015a94939f Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 12 Aug 2026 13:52:32 -0400 Subject: [PATCH 45/99] feat(mobile): show what the pet card already knew --- mobile/__tests__/GalleryScreen.test.tsx | 84 ++++++++++ mobile/src/components/PetCard.tsx | 209 +++++++++++++++++++++++- 2 files changed, 284 insertions(+), 9 deletions(-) diff --git a/mobile/__tests__/GalleryScreen.test.tsx b/mobile/__tests__/GalleryScreen.test.tsx index 91e51424..f116dfe9 100644 --- a/mobile/__tests__/GalleryScreen.test.tsx +++ b/mobile/__tests__/GalleryScreen.test.tsx @@ -18,10 +18,25 @@ import type { Pet } from '@shared/core'; // pulled from their own module and the barrel is stubbed. jest.mock('@shared/core', () => ({ ...jest.requireActual('../../shared/src/utils/ethereum/petReadyTime'), + // The real card helpers, not fakes: what the card must show is the same number the + // web app shows, and both read these. A stub here would assert the stub, and the + // whole point of the card carrying stats is that the two clients agree. + ...jest.requireActual('../../shared/src/utils/ethereum/petCard'), + ...jest.requireActual('../../shared/src/utils/pets/skills'), getRarityColor: (r: number) => (r === 2 ? '#C0C0C0' : '#8B4513'), getRarityName: (r: number) => (r === 2 ? 'Uncommon' : 'Common'), })); +jest.mock('../src/components/PetArt', () => () => null); + +import { + getGeneration, + getPetClass, + getPetProperties, + getXpNumbers, +} from '../../shared/src/utils/ethereum/petCard'; +import { getPetSkill } from '../../shared/src/utils/pets/skills'; + const mockGallery = jest.fn(); jest.mock('../src/hooks/pet-gallery/usePetGallery', () => ({ usePetGallery: () => mockGallery(), @@ -117,6 +132,75 @@ describe('GalleryScreen', () => { expect(rendered).toContain('Level 3'); }); + /** + * What the card draws, checked against the shared helpers rather than against + * literals. + * + * The card knew all of this and drew none of it: art, stats, skill and class were + * one render away the whole time. Asserting against `getPetProperties` and friends + * rather than hardcoded numbers is what makes this a parity test — if the card ever + * reads the wrong field, the expectation moves with the helper and the test still + * catches it. + */ + it('shows the DNA stat tiles, from the same helper the web app uses', async () => { + const subject = pet(); + mockGallery.mockReturnValue(galleryValue({ pets: [subject] })); + const rendered = textOf(await render()); + + const props = getPetProperties(subject); + for (const [label, value] of [ + ['STR', props.attack], + ['INT', props.intelligence], + ['DEF', props.defense], + ['VIT', props.life], + ] as const) { + expect(rendered).toContain(label); + expect(rendered).toContain(String(value)); + } + // AGI is deliberately absent: nothing in the data model backs it. + expect(rendered).not.toContain('AGI'); + }); + + it('names the species skill and the pet class', async () => { + const subject = pet({ speciesId: 3 }); + mockGallery.mockReturnValue(galleryValue({ pets: [subject] })); + const rendered = textOf(await render()); + + expect(rendered).toContain(getPetSkill(3)!.name); + expect(rendered).toContain(getPetClass(subject.dna)); + expect(rendered).toContain(`Gen ${subject.generation ?? getGeneration(subject.dna)}`); + }); + + it('omits the skill block for a pet with no species, rather than showing an empty one', async () => { + // Solana pets and older EVM rows carry no speciesId, and `getPetSkill` returns + // null for them. A bordered empty block would read as a missing value. + const subject = pet(); + expect(subject.speciesId).toBeUndefined(); + mockGallery.mockReturnValue(galleryValue({ pets: [subject] })); + + const rendered = textOf(await render()); + expect(rendered).toContain('Rex'); + expect(rendered).not.toContain(getPetSkill(0)!.name); + }); + + it('shows XP as current over max rather than a bare number', async () => { + const subject = pet(); + mockGallery.mockReturnValue(galleryValue({ pets: [subject] })); + const rendered = textOf(await render()); + + const xp = getXpNumbers(subject); + expect(rendered).toContain(`${xp.xpCurrent}/${xp.xpMax}`); + }); + + it('shows a win rate only once the pet has fought', async () => { + mockGallery.mockReturnValue(galleryValue({ pets: [pet({ winCount: 3, lossCount: 1 })] })); + expect(textOf(await render())).toContain('75% win rate'); + + mockGallery.mockReturnValue(galleryValue({ pets: [pet({ winCount: 0, lossCount: 0 })] })); + // 0% would read as a losing record rather than as no record at all. + expect(textOf(await render())).not.toContain('win rate'); + }); + it('surfaces the empty state rather than an empty list', async () => { mockGallery.mockReturnValue(galleryValue()); expect(textOf(await render())).toContain('No pets yet'); diff --git a/mobile/src/components/PetCard.tsx b/mobile/src/components/PetCard.tsx index 11cc709c..787d5af0 100644 --- a/mobile/src/components/PetCard.tsx +++ b/mobile/src/components/PetCard.tsx @@ -1,10 +1,45 @@ import React from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { getRarityColor, getRarityName, type Pet } from '@shared/core'; +import { + getGeneration, + getLifePercent, + getPetClass, + getPetProperties, + getPetSkill, + getRarityColor, + getRarityName, + getXpNumbers, + getXpPercent, + type Pet, +} from '@shared/core'; +import PetArt from './PetArt'; import type { PetCooldownStatus } from '../hooks/usePetCooldowns'; import { neon, neonGlow } from '../theme/neon'; +/** + * The four tiles frontend's card shows, from the same helper. + * + * The fourth is VIT, not AGI. Agility has no backing in the data model — `getPetProperties` + * returns life, attack, defense and intelligence and nothing else — and frontend's own + * comment records the same substitution. Inventing an AGI number here would make the two + * clients disagree about a stat neither can source. + */ +const statTiles = (pet: Pet): { label: string; value: number }[] => { + const p = getPetProperties(pet); + return [ + { label: 'STR', value: p.attack }, + { label: 'INT', value: p.intelligence }, + { label: 'DEF', value: p.defense }, + { label: 'VIT', value: p.life }, + ]; +}; + +const winRatio = (pet: Pet): number => { + const fought = pet.winCount + pet.lossCount; + return fought === 0 ? 0 : Math.round((pet.winCount / fought) * 100); +}; + type Props = { pet: Pet; status: PetCooldownStatus; @@ -19,6 +54,10 @@ type Props = { * One pet, with its cooldowns and the per-pet actions that reach the stack routes. * Rename and Defense live here rather than in the tab bar because both act on a * chosen pet; see plan 3.1. + * + * Everything below the name comes from `@shared/core` helpers rather than being derived + * here, so a pet reads identically on both clients. That was the gap this card had: the + * app knew its art, stats, skill and class the whole time and drew none of them. */ export default function PetCard({ pet, @@ -30,11 +69,28 @@ export default function PetCard({ onSend, }: Props) { const rarityColor = getRarityColor(pet.rarity); + const skill = getPetSkill(pet.speciesId); + const xp = getXpNumbers(pet); + const hp = getLifePercent(pet); return ( + {/* A rarity stripe across the top, as on web: the card's colour is the pet's. */} + + - {pet.name} + + + + {pet.name} + + + {getPetClass(pet.dna)} · Gen {pet.generation ?? getGeneration(pet.dna)} + + + ID #{pet.id} · Level {pet.level} + + {getRarityName(pet.rarity)} @@ -42,13 +98,49 @@ export default function PetCard({ - ID #{pet.id} - - Level {pet.level} - {pet.xp != null ? ` · ${pet.xp} XP` : ''} - + {skill ? ( + + {skill.name} + + {skill.description} + + + ) : null} + + + {statTiles(pet).map((tile) => ( + + {tile.label} + {tile.value} + + ))} + + + + XP + + + + + {xp.xpCurrent}/{xp.xpMax} + + + + + HP + + + + {hp}% + + - W {pet.winCount} · L {pet.lossCount} + {pet.winCount}W + {' / '} + {pet.lossCount}L + {pet.winCount + pet.lossCount > 0 ? ` · ${winRatio(pet)}% win rate` : ''} {status.onCooldown ? ( @@ -114,17 +206,116 @@ const styles = StyleSheet.create({ width: '100%', ...neonGlow(neon.cyan, 8, 0.2), }, + rarityBar: { + height: 3, + borderRadius: 2, + marginBottom: 12, + }, cardHeader: { flexDirection: 'row', - justifyContent: 'space-between', alignItems: 'center', marginBottom: 8, }, + identity: { + flex: 1, + marginLeft: 12, + minWidth: 0, + }, petName: { fontSize: 20, fontWeight: '800', color: neon.text, + }, + petClass: { + fontSize: 12, + color: neon.purple, + marginTop: 2, + fontWeight: '700', + }, + skill: { + marginTop: 4, + marginBottom: 10, + borderLeftWidth: 2, + borderLeftColor: neon.purple, + paddingLeft: 10, + }, + skillName: { + fontSize: 13, + fontWeight: '800', + color: neon.purple, + }, + skillText: { + fontSize: 12, + color: neon.textMuted, + marginTop: 2, + lineHeight: 16, + }, + stats: { + flexDirection: 'row', + marginBottom: 10, + }, + stat: { flex: 1, + alignItems: 'center', + backgroundColor: neon.bgPanel, + borderRadius: 10, + borderWidth: 1, + borderColor: neon.border, + paddingVertical: 8, + marginRight: 6, + }, + statLabel: { + fontSize: 10, + fontWeight: '800', + letterSpacing: 1, + color: neon.textDim, + }, + statValue: { + fontSize: 16, + fontWeight: '800', + color: neon.cyan, + marginTop: 2, + }, + barRow: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 6, + }, + barLabel: { + width: 26, + fontSize: 11, + fontWeight: '800', + color: neon.textDim, + }, + barTrack: { + flex: 1, + height: 6, + borderRadius: 3, + backgroundColor: neon.bgInput, + overflow: 'hidden', + marginHorizontal: 8, + }, + barFill: { + height: 6, + borderRadius: 3, + backgroundColor: neon.cyan, + }, + hpFill: { + backgroundColor: neon.success, + }, + barValue: { + minWidth: 62, + fontSize: 11, + color: neon.textMuted, + textAlign: 'right', + }, + wins: { + color: neon.success, + fontWeight: '800', + }, + losses: { + color: neon.danger, + fontWeight: '800', }, rarityBadge: { borderWidth: 1, From bf3ef19de3882e74d6ee6b6a990d097cb74b3430 Mon Sep 17 00:00:00 2001 From: mobuild4u Date: Wed, 12 Aug 2026 14:07:21 -0400 Subject: [PATCH 46/99] feat(mobile): draw pet art wherever a pet is listed --- mobile/__tests__/BattleScreen.test.tsx | 19 ++++++++++ mobile/__tests__/BreedScreen.test.tsx | 2 + mobile/__tests__/ChatScreen.test.tsx | 2 + mobile/__tests__/EquipScreen.test.tsx | 2 + mobile/__tests__/GalleryScreen.test.tsx | 13 ++++++- mobile/__tests__/InventoryScreen.test.tsx | 2 + mobile/__tests__/actionScreens.test.tsx | 2 + mobile/src/components/PetPicker.tsx | 6 +++ mobile/src/screens/BattleScreen.tsx | 5 ++- mobile/src/screens/ChatScreen.tsx | 45 +++++++++++++++++++++-- mobile/src/screens/parts/MarriageCard.tsx | 5 +++ 11 files changed, 98 insertions(+), 5 deletions(-) diff --git a/mobile/__tests__/BattleScreen.test.tsx b/mobile/__tests__/BattleScreen.test.tsx index 44ab655d..69b378b4 100644 --- a/mobile/__tests__/BattleScreen.test.tsx +++ b/mobile/__tests__/BattleScreen.test.tsx @@ -88,6 +88,18 @@ const mockWinEstimateArgs = jest.fn(); /** Captures what the result dialogue is asked for, including the personas fallback. */ const mockDialogueArgs = jest.fn(); +/** + * Rendered as a marker rather than nulled, so the opponent rows can be asserted to draw + * art. A stub returning null would let the art disappear again without a test noticing — + * which is exactly how the gallery went without avatars for the whole project. + */ +jest.mock('../src/components/PetArt', () => { + const { Text: RNText } = jest.requireActual('react-native'); + const React_ = jest.requireActual('react'); + return ({ pet: subject }: { pet: { id: string } }) => + React_.createElement(RNText, null, `[art:${subject.id}]`); +}); + jest.mock('@shared/core', () => ({ getReadyPetsUnified: (pets: Pet[]) => pets.filter((p) => p.readyAt === 0).map((p) => ({ id: p.id, pet: p })), @@ -387,6 +399,13 @@ describe('BattleScreen', () => { expect(textOf(tree)).toContain('You call that a stance?'); }); + it('draws each opponent with its art, not a name alone', async () => { + mockState.opponents = [foe({ id: '9', name: 'Luna' }), foe({ id: '12', name: 'Momo' })]; + const rendered = textOf(await render()); + expect(rendered).toContain('[art:9]'); + expect(rendered).toContain('[art:12]'); + }); + it('surfaces an opponent load failure', async () => { mockState.opponentsError = new Error('backend unreachable'); mockState.opponents = []; diff --git a/mobile/__tests__/BreedScreen.test.tsx b/mobile/__tests__/BreedScreen.test.tsx index 36f2faf8..51183294 100644 --- a/mobile/__tests__/BreedScreen.test.tsx +++ b/mobile/__tests__/BreedScreen.test.tsx @@ -38,6 +38,8 @@ const mockBreed = jest.fn(); jest.mock('../src/hooks/useTxErrorToast', () => ({ useTxErrorToast: () => {} })); +jest.mock('../src/components/PetArt', () => () => null); + jest.mock('@shared/core', () => ({ useStudFees: () => ({ amountLamports: null, diff --git a/mobile/__tests__/ChatScreen.test.tsx b/mobile/__tests__/ChatScreen.test.tsx index f233d2b3..a9aefb41 100644 --- a/mobile/__tests__/ChatScreen.test.tsx +++ b/mobile/__tests__/ChatScreen.test.tsx @@ -59,6 +59,8 @@ const mockReact = jest.fn(); const mockMarkRead = jest.fn(); const mockMessagesArgs = jest.fn(); +jest.mock('../src/components/PetArt', () => () => null); + jest.mock('@shared/core', () => ({ CHAT_REACTIONS: ['👍', '❤️', '😂', '😮', '😢', '🙏', '👎'], shortAddress: (a: string) => `${a.slice(0, 6)}...${a.slice(-4)}`, diff --git a/mobile/__tests__/EquipScreen.test.tsx b/mobile/__tests__/EquipScreen.test.tsx index 12513ab3..dd2c281f 100644 --- a/mobile/__tests__/EquipScreen.test.tsx +++ b/mobile/__tests__/EquipScreen.test.tsx @@ -39,6 +39,8 @@ const mockEquip = jest.fn(); const mockUnequip = jest.fn(); const mockNotify = jest.fn(); +jest.mock('../src/components/PetArt', () => () => null); + jest.mock('@shared/core', () => ({ SLOT: { weapon: 0, armor: 1, trinket: 2 }, useChainCapabilities: () => ({ diff --git a/mobile/__tests__/GalleryScreen.test.tsx b/mobile/__tests__/GalleryScreen.test.tsx index f116dfe9..d41a7996 100644 --- a/mobile/__tests__/GalleryScreen.test.tsx +++ b/mobile/__tests__/GalleryScreen.test.tsx @@ -27,7 +27,13 @@ jest.mock('@shared/core', () => ({ getRarityName: (r: number) => (r === 2 ? 'Uncommon' : 'Common'), })); -jest.mock('../src/components/PetArt', () => () => null); +/** A marker rather than null, so the card can be asserted to draw art at all. */ +jest.mock('../src/components/PetArt', () => { + const { Text: RNText } = jest.requireActual('react-native'); + const React_ = jest.requireActual('react'); + return ({ pet }: { pet: { id: string } }) => + React_.createElement(RNText, null, `[art:${pet.id}]`); +}); import { getGeneration, @@ -201,6 +207,11 @@ describe('GalleryScreen', () => { expect(textOf(await render())).not.toContain('win rate'); }); + it('draws the pet art, which the card omitted entirely until now', async () => { + mockGallery.mockReturnValue(galleryValue({ pets: [pet({ id: '7' })] })); + expect(textOf(await render())).toContain('[art:7]'); + }); + it('surfaces the empty state rather than an empty list', async () => { mockGallery.mockReturnValue(galleryValue()); expect(textOf(await render())).toContain('No pets yet'); diff --git a/mobile/__tests__/InventoryScreen.test.tsx b/mobile/__tests__/InventoryScreen.test.tsx index 42889b40..e1562a1c 100644 --- a/mobile/__tests__/InventoryScreen.test.tsx +++ b/mobile/__tests__/InventoryScreen.test.tsx @@ -40,6 +40,8 @@ const mockSpend = jest.fn(); const mockRefetch = jest.fn(); const mockNotify = jest.fn(); +jest.mock('../src/components/PetArt', () => () => null); + jest.mock('@shared/core', () => ({ useChainCapabilities: () => ({ activeKind: 'ethereum', isConnected: true }), useInventory: () => ({ diff --git a/mobile/__tests__/actionScreens.test.tsx b/mobile/__tests__/actionScreens.test.tsx index e597f505..018deb1d 100644 --- a/mobile/__tests__/actionScreens.test.tsx +++ b/mobile/__tests__/actionScreens.test.tsx @@ -48,6 +48,8 @@ const mutationResult = (mutate: jest.Mock) => ({ lifecycle: {}, }); +jest.mock('../src/components/PetArt', () => () => null); + jest.mock('@shared/core', () => ({ useSyncMetadata: () => ({ sync: jest.fn(), isPending: false, error: null }), getReadyPetsUnified: (pets: Pet[]) => pets.map((p) => ({ id: p.id, pet: p })), diff --git a/mobile/src/components/PetPicker.tsx b/mobile/src/components/PetPicker.tsx index d0e1bb5a..70335b73 100644 --- a/mobile/src/components/PetPicker.tsx +++ b/mobile/src/components/PetPicker.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import type { ReadyPet } from '@shared/core'; +import PetArt from './PetArt'; import { neon } from '../theme/neon'; type Props = { @@ -26,6 +27,10 @@ const NO_PETS_HINT = 'No pets in this wallet yet. Mint one from the Gallery tab. /** * Horizontal chips in place of frontend's `