diff --git a/.gitignore b/.gitignore
index 00703a3..0343544 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,6 @@ snfoundry_cache/
.env
accounts/
.snfoundry_cache/
-coverage/
\ No newline at end of file
+coverage/
+node_modules/
+dist/
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..4bf964e
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,3 @@
+node_modules/
+dist/
+*.png
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000..60a4939
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,114 @@
+# Add a Beast
+
+Self-service web app for adding a species to the bestiary. Upload pixel art,
+name it, choose where it can be minted — one transaction, no permission needed.
+
+```bash
+pnpm install
+pnpm build:sdk # the app consumes the SDK's build output
+pnpm dev:app
+```
+
+## Configuration
+
+Defaults point at the Sepolia deployment in `docs/sepolia-v3-deployment.md`.
+Override with a `.env`:
+
+```
+VITE_STARKNET_RPC_URL=https://api.cartridge.gg/x/starknet/sepolia
+VITE_BEASTS_NFT=0x...
+VITE_BEASTS_REGISTRY=0x...
+```
+
+## Pages
+
+Hash routing, so every page is a real shareable URL on a static host.
+
+| URL | |
+|---|---|
+| `#/` | Add a Beast |
+| `#/collection/0xabc…` | Every Beast an address holds. **Swap the address to view any wallet** — no connection needed |
+| `#/beasts` | The bestiary, one card per species. The original 75 are behind a toggle |
+| `#/beasts/76` | Every Beast of one species, strongest first |
+| `#/manage` | Species you control |
+| `#/manage/76` | Per-species controls |
+
+Grouping the bestiary by species is the default because the collection is
+unbounded and a single species can hold 1,243 Beasts — a flat list of every
+token would be unreadable long before it was useful.
+
+Species pages read the contract's own per-species rank list rather than
+scanning, so the ordering shown is the one the collection itself uses.
+
+## What the app does
+
+**Register.** Four art variants are required — which one a Beast shows is
+decided by the shiny and animated bits in its token ID, so a species cannot ship
+a partial set. Art is validated client-side against the same rules the contract
+enforces (media type, base64 structure, PNG/GIF magic bytes) *and* decoded by
+the browser, because a file that will not decode here renders broken for every
+holder. Registration mints the artist's Genesis Beast in the same transaction.
+
+**Manage.** Lists every species the connected wallet holds the artist role for,
+with its live art, and opens the per-species controls: replace art, rotate or
+pause the minter, lock either one permanently, opt into kill stats, transfer
+the artist role, or graduate to a custom art provider.
+
+The list comes from the wallet's own tokens: the collection exposes
+`token_of_owner_by_index`, and a Genesis Beast is any token with no affixes, so
+the species a wallet controls fall straight out of a local decode. That works
+because the **artist role is ownership of the Genesis Beast** — there is no
+separate role to drift from the token. Everything is artist-only on-chain; the
+UI hides what the caller cannot do and the contract is the real gate.
+
+Transferring a species means sending its Genesis Beast, which the dashboard
+spells out before it asks for a signature.
+
+Art thumbnails come from each species' own provider, which for a custom
+provider is arbitrary contract code. One that reverts costs its own thumbnail,
+not the whole list.
+
+## Art loading
+
+Art is fetched per Beast, not per species. A community provider receives the
+whole decoded Beast, so it may legitimately vary art by affix, tier or level —
+caching by species would show the wrong picture for exactly the providers that
+make the interface worth having. Requests are batched and the cache is keyed by
+token ID, shared across pages.
+
+The contract validates art structurally — media type, base64, magic bytes — but
+cannot prove a payload decodes. A tile whose art will not render says so rather
+than showing a broken-image icon.
+
+## The preview card is an approximation
+
+`CardPreview` mirrors the layout of the on-chain SVG so an artist can judge
+their work in context before paying for a transaction. It is **not** the
+contract's renderer — that lives in `src/beast_svg.cairo` and only produces
+output once a species exists. Porting it byte-for-byte to TypeScript would let
+the preview be exact; until then, treat the card as indicative and `token_uri`
+as the truth.
+
+## Session policy
+
+The Cartridge connector pre-approves the registry's *management* entrypoints, so
+an artist signs once and can then iterate without a popup per change.
+`register_beast_with_art` is deliberately excluded: it mints a provenance token
+and permanently assigns a species ID, so it should always be an explicit
+signature.
+
+## Smoke test
+
+`scripts/smoke.mjs` drives the built app in headless Chromium against the live
+deployment — it checks the chain read renders, name validation rejects an
+injection attempt, the preview derives power correctly, and the dashboard loads
+a real species.
+
+```bash
+pnpm build && pnpm preview &
+node scripts/smoke.mjs
+```
+
+It needs a Playwright browser; in this dev container that means
+`LD_LIBRARY_PATH=/workspace/.playwright-libs/root/usr/lib/x86_64-linux-gnu` and
+an `executablePath` pointing at the cached Chromium.
diff --git a/app/index.html b/app/index.html
new file mode 100644
index 0000000..6d78a75
--- /dev/null
+++ b/app/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Add a Beast — onchain bestiary
+
+
+
+
+
+
diff --git a/app/package.json b/app/package.json
new file mode 100644
index 0000000..0bd5e2d
--- /dev/null
+++ b/app/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@provable-games/beasts-app",
+ "private": true,
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "preview": "vite preview",
+ "typecheck": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@cartridge/connector": "^0.13.12",
+ "@cartridge/controller": "^0.13.12",
+ "@provable-games/beasts-sdk": "workspace:*",
+ "@starknet-react/chains": "5.0.3",
+ "@starknet-react/core": "^5.0.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "starknet": "9.4.2"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
+ "@vitejs/plugin-react": "^4.3.0",
+ "playwright": "^1.62.1",
+ "typescript": "^5.8.3",
+ "vite": "^5.4.0"
+ }
+}
diff --git a/app/scripts/smoke.mjs b/app/scripts/smoke.mjs
new file mode 100644
index 0000000..c5bfaad
--- /dev/null
+++ b/app/scripts/smoke.mjs
@@ -0,0 +1,83 @@
+import { chromium } from 'playwright';
+import { mkdtempSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+
+// 32x32 PNG: magenta border on all four sides, green corner-to-corner
+// diagonal. Real Beast art is this size, and the border is the tell — if the
+// preview crops, an edge goes missing.
+const TEST_PNG =
+ 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAiklEQVR4nLXNSw6AIAyEYQ7B2vvfEk1sULFAHzOZf9FVv9JKoyar9WAk76+LZDwAyfgADGME4IYCYA0dABpTAGWsAIixAfLGHkgaJiBjWIGw4QBihg8IGG7Aa0QAlxEE7EYcMBopwGJkga0BANYGBlgYMGBmIAHVAAN/Aw8MBgV4GyygG0TgNmTUTqHjAu38soSbAAAAAElFTkSuQmCC';
+
+const fixtureDir = mkdtempSync(join(tmpdir(), 'beasts-smoke-'));
+const pngPath = join(fixtureDir, 'test.png');
+writeFileSync(pngPath, Buffer.from(TEST_PNG, 'base64'));
+
+const browser = await chromium.launch({
+ executablePath:
+ '/home/ubuntu/.cache/ms-playwright/chromium_headless_shell-1228/chrome-headless-shell-linux64/chrome-headless-shell',
+});
+const page = await browser.newPage({ viewport: { width: 1280, height: 1400 } });
+const errors = [];
+page.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); });
+page.on('pageerror', (e) => errors.push(`pageerror: ${e.message}`));
+
+await page.goto('http://localhost:4173/', { waitUntil: 'domcontentloaded' });
+await page.waitForTimeout(5000);
+
+console.log('H1:', await page.textContent('h1'));
+const body = await page.textContent('body');
+const m = body.match(/(\d+) species in the bestiary so far/);
+console.log('LIVE CHAIN READ:', m ? m[0] : 'FAILED — no species count rendered');
+console.log('art slots:', await page.locator('.art-slot').count());
+console.log('preview card:', await page.locator('.card').count());
+
+// Client-side name validation, no wallet needed.
+await page.fill('input[placeholder="Gloomfang"]', 'bad"name');
+await page.waitForTimeout(200);
+console.log('rejects injection name:', JSON.stringify(await page.locator('.field__error').first().textContent()));
+
+await page.fill('input[placeholder="Gloomfang"]', 'Gloomfang');
+await page.waitForTimeout(200);
+console.log('accepts valid name — card title:', JSON.stringify(await page.textContent('.card__title')));
+
+// Tier drives the power number on the preview card.
+await page.selectOption('select >> nth=1', '1');
+await page.waitForTimeout(200);
+const power = await page.locator('.stat', { hasText: 'Power' }).textContent();
+console.log('tier 1 power (level 10 x 5):', JSON.stringify(power));
+
+// Preview sizing. A percentage height against an `aspect-ratio` parent
+// resolves to `auto`, so a square Beast used to size itself from its own 1:1
+// ratio, overflow the wider frame, and get cropped by `overflow: hidden`.
+await page.locator('.art-slot__drop input[type=file]').first().setInputFiles(pngPath);
+await page.waitForTimeout(1200);
+const artBox = await page.locator('.card__art').boundingBox();
+const imgBox = await page.locator('.card__art img').boundingBox();
+console.log('preview art fits its frame:',
+ imgBox.height <= artBox.height + 1 && imgBox.width <= artBox.width + 1,
+ `(img ${Math.round(imgBox.width)}x${Math.round(imgBox.height)} in frame ${Math.round(artBox.width)}x${Math.round(artBox.height)})`);
+
+await page.screenshot({ path: 'smoke-register.png', fullPage: true });
+
+// Manage lists the species the connected wallet controls, so with no wallet
+// it has to ask for one rather than opening an empty page.
+await page.click('button:has-text("Manage")');
+await page.waitForTimeout(800);
+console.log('Manage without a wallet prompts connect:',
+ (await page.locator('.modal').count()) > 0 && (await page.locator('.mine').count()) === 0);
+
+// Wallet picker: both wallet families must be offered, and a wallet whose
+// extension is absent must say so rather than fail silently.
+const wallets = await page.locator('.wallet__name').allTextContents();
+const states = await page.locator('.wallet__state').allTextContents();
+console.log('wallets offered:', wallets.map((w, i) => `${w}${states[i] ? ` (${states[i]})` : ''}`));
+// A centred fixed overlay: narrow, and vertically centred in the viewport
+// whatever the page scroll position.
+const box = await page.locator('.modal').boundingBox();
+const vh = page.viewportSize().height;
+const centred = Math.abs(box.y + box.height / 2 - vh / 2) < 40;
+console.log('modal is a centred overlay:', box.width <= 400 && centred);
+
+console.log('CONSOLE ERRORS:', errors.length ? errors.slice(0, 4) : 'none');
+await browser.close();
diff --git a/app/src/App.tsx b/app/src/App.tsx
new file mode 100644
index 0000000..cc6df82
--- /dev/null
+++ b/app/src/App.tsx
@@ -0,0 +1,223 @@
+import { useAccount, useDisconnect } from '@starknet-react/core';
+import { BeastsClient, type BeastDefinition } from '@provable-games/beasts-sdk';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { ADDRESSES, provider } from './lib/chain';
+import { href, useRoute } from './lib/router';
+import { Collection } from './components/Collection';
+import { ConnectModal } from './components/ConnectModal';
+import { Dashboard } from './components/Dashboard';
+import { MySpecies } from './components/MySpecies';
+import { RegisterForm, type RegistrationInput } from './components/RegisterForm';
+import { SpeciesCollection } from './components/SpeciesCollection';
+import { SpeciesIndex } from './components/SpeciesIndex';
+
+export function App() {
+ const { address, account } = useAccount();
+ const { disconnect } = useDisconnect();
+ const [route, navigate] = useRoute();
+
+ const [connecting, setConnecting] = useState(false);
+ const [submitting, setSubmitting] = useState(false);
+ const [error, setError] = useState();
+ const [definition, setDefinition] = useState(null);
+ const [speciesCount, setSpeciesCount] = useState(null);
+
+ const client = useMemo(() => new BeastsClient(provider(), ADDRESSES, account), [account]);
+
+ const refresh = useCallback(async () => {
+ setSpeciesCount(await client.speciesCount().catch(() => null));
+ if (route.name !== 'manage-species') {
+ setDefinition(null);
+ return;
+ }
+ try {
+ setDefinition(await client.getDefinition(route.beastId));
+ setError(undefined);
+ } catch {
+ setDefinition(null);
+ setError(`Species ${route.beastId} is not registered`);
+ }
+ }, [client, route]);
+
+ useEffect(() => {
+ void refresh();
+ }, [refresh]);
+
+ async function register(input: RegistrationInput) {
+ setSubmitting(true);
+ setError(undefined);
+ try {
+ const before = await client.speciesCount();
+ await client.execute(
+ client.registerWithArtCall({
+ name: input.name,
+ beastType: input.beastType,
+ tier: input.tier,
+ minter: input.minter,
+ art: input.art,
+ }),
+ );
+ // species_count counts genesis too, so the new ID is the old count + 1.
+ navigate({ name: 'manage-species', beastId: before + 1n });
+ } catch (e) {
+ setError(e instanceof Error ? e.message : String(e));
+ } finally {
+ setSubmitting(false);
+ }
+ }
+
+ const isArtist = !!address && !!definition && BigInt(definition.artist) === BigInt(address);
+
+ function openMine() {
+ if (address) navigate({ name: 'manage' });
+ else setConnecting(true);
+ }
+
+ function openMyCollection() {
+ if (address) navigate({ name: 'collection', address });
+ else setConnecting(true);
+ }
+
+ return (
+
+
+
+ Add a Beast
+
+
+
+
+ Bestiary
+
+
+ Collection
+
+
+ Manage
+
+
+ {address ? (
+ disconnect()} title="Disconnect">
+ {`0x${BigInt(address).toString(16).slice(0, 6)}…`}
+
+ ) : (
+ setConnecting(true)}>
+ Connect
+
+ )}
+
+
+
+
+ {route.name === 'register' && (
+ <>
+
+
Put your Beast onchain
+
+ Anyone can add a species to the bestiary. Upload pixel art, name it,
+ pick where it lives — one transaction, no permission needed. You keep
+ the Genesis Beast: the creator's token, one per species, forever.
+
+ {speciesCount !== null && (
+
+ {speciesCount.toString()} species in the bestiary so far.
+
+ )}
+
+
+ >
+ )}
+
+ {route.name === 'collection' && (
+ navigate({ name: 'species', beastId })}
+ onViewAddress={(next) => navigate({ name: 'collection', address: next })}
+ />
+ )}
+
+ {route.name === 'species-index' && (
+ navigate({ name: 'species', beastId })}
+ />
+ )}
+
+ {route.name === 'species' && (
+ navigate({ name: 'species-index' })}
+ onViewOwner={(owner) => navigate({ name: 'collection', address: owner })}
+ />
+ )}
+
+ {route.name === 'manage' &&
+ (address ? (
+ navigate({ name: 'manage-species', beastId })}
+ onRegister={() => navigate({ name: 'register' })}
+ />
+ ) : (
+
+
Connect a wallet to see the species you control.
+
setConnecting(true)}>
+ Connect
+
+
+ ))}
+
+ {route.name === 'manage-species' &&
+ (definition ? (
+ <>
+
+ ← Your Beasts
+
+ void refresh()}
+ />
+ >
+ ) : (
+
+ ))}
+
+
+
+
+ Sepolia · Registry {shortAddr(ADDRESSES.registry)} · Collection{' '}
+ {shortAddr(ADDRESSES.nft)}
+
+
+
+ {connecting &&
setConnecting(false)} />}
+
+ );
+}
+
+/** Addresses differ in padding and case, so compare numerically. */
+function safeEquals(a: string, b: string): boolean {
+ try {
+ return BigInt(a) === BigInt(b);
+ } catch {
+ return false;
+ }
+}
+
+function shortAddr(address: string): string {
+ const hex = BigInt(address).toString(16);
+ return `0x${hex.slice(0, 6)}…${hex.slice(-4)}`;
+}
diff --git a/app/src/components/ArtUpload.tsx b/app/src/components/ArtUpload.tsx
new file mode 100644
index 0000000..44b9df2
--- /dev/null
+++ b/app/src/components/ArtUpload.tsx
@@ -0,0 +1,74 @@
+import { useState } from 'react';
+import { ART_SLOTS, ArtLoadError, loadArtFile, type ArtSlot, type LoadedArt } from '../lib/art';
+
+interface Props {
+ loaded: Partial>;
+ onChange: (slot: ArtSlot, art: LoadedArt | undefined) => void;
+ onSelect: (slot: ArtSlot) => void;
+ selected: ArtSlot;
+ disabled?: boolean;
+}
+
+export function ArtUpload({ loaded, onChange, onSelect, selected, disabled }: Props) {
+ const [errors, setErrors] = useState>>({});
+
+ async function handleFile(slot: ArtSlot, kind: 'png' | 'gif', file: File | undefined) {
+ if (!file) return;
+ setErrors((e) => ({ ...e, [slot]: undefined }));
+ try {
+ const art = await loadArtFile(file, kind);
+ onChange(slot, art);
+ onSelect(slot);
+ } catch (error) {
+ const message =
+ error instanceof ArtLoadError ? error.message : 'Could not process that file';
+ setErrors((e) => ({ ...e, [slot]: message }));
+ onChange(slot, undefined);
+ }
+ }
+
+ return (
+
+ {ART_SLOTS.map(({ slot, label, hint, kind, accept }) => {
+ const art = loaded[slot];
+ const error = errors[slot];
+ return (
+
art && onSelect(slot)}
+ >
+
+ {label}
+ {kind.toUpperCase()}
+
+
+
+ {art ? (
+
+ ) : (
+ Choose {kind.toUpperCase()}
+ )}
+ handleFile(slot, kind, e.target.files?.[0])}
+ />
+
+
+
{hint}
+ {art && (
+
+ {(art.bytes / 1024).toFixed(1)} KB · {art.slots.toLocaleString()} slots
+
+ )}
+ {error &&
{error}
}
+
+ );
+ })}
+
+ );
+}
diff --git a/app/src/components/BeastTile.tsx b/app/src/components/BeastTile.tsx
new file mode 100644
index 0000000..15be85a
--- /dev/null
+++ b/app/src/components/BeastTile.tsx
@@ -0,0 +1,72 @@
+import { useState } from 'react';
+import {
+ BEAST_TYPE_NAMES,
+ type Beast,
+ beastPower,
+ fullBeastName,
+ isGenesis,
+} from '@provable-games/beasts-sdk';
+
+interface Props {
+ beast: Beast;
+ speciesName: string;
+ /** `undefined` while loading, `null` when the provider could not be read. */
+ art: string | null | undefined;
+ rank?: number;
+ onClick?: () => void;
+ subtitle?: string;
+}
+
+/**
+ * One Beast, as a tile. Everything shown except the species name and the art
+ * comes straight out of the token ID.
+ */
+export function BeastTile({ beast, speciesName, art, rank, onClick, subtitle }: Props) {
+ const genesis = isGenesis(beast);
+ // The contract validates art structurally — media type, base64, magic bytes
+ // — but cannot prove the payload decodes. A species whose art is malformed
+ // must degrade to a note, not a browser's broken-image icon.
+ const [decodeFailed, setDecodeFailed] = useState(false);
+ const body = (
+ <>
+
+ {art === undefined ? (
+
…
+ ) : art === null || decodeFailed ? (
+
+ {decodeFailed ? 'Art will not render' : 'Art unavailable'}
+
+ ) : (
+
setDecodeFailed(true)} />
+ )}
+ {genesis &&
Genesis }
+ {beast.animated === 1 &&
GIF }
+
+
+
+ {fullBeastName(beast, speciesName)}
+
+
+
+ {subtitle ??
+ `${BEAST_TYPE_NAMES[beast.beastType]} · T${beast.tier} · Power ${beastPower(beast)}`}
+
+
+
+ Lv {beast.level}
+ HP {beast.health}
+ {/* Genesis Beasts sit outside the ranked list, so rank 0 is "unranked",
+ not "first". */}
+ {genesis ? 'Unranked' : rank ? `Rank ${rank}` : ''}
+
+ >
+ );
+
+ return onClick ? (
+
+ {body}
+
+ ) : (
+ {body}
+ );
+}
diff --git a/app/src/components/CardPreview.tsx b/app/src/components/CardPreview.tsx
new file mode 100644
index 0000000..91dde9d
--- /dev/null
+++ b/app/src/components/CardPreview.tsx
@@ -0,0 +1,84 @@
+import { BEAST_TYPE_NAMES, BeastType, prefixName, suffixName } from '@provable-games/beasts-sdk';
+
+interface Props {
+ name: string;
+ tier: number;
+ beastType: BeastType;
+ art?: string;
+ shiny: boolean;
+ /** Sample affixes, so the artist can see how a named variant reads. */
+ prefix: number;
+ suffix: number;
+ level: number;
+ health: number;
+}
+
+/**
+ * Approximation of the card the contract renders.
+ *
+ * This is NOT the on-chain SVG — that is built by `src/beast_svg.cairo` and
+ * only exists once a species is registered. This preview mirrors its layout
+ * and the values it derives so an artist can judge their art in context
+ * before paying for a transaction. After registration the app shows the real
+ * `token_uri` output instead.
+ */
+export function CardPreview({
+ name,
+ tier,
+ beastType,
+ art,
+ shiny,
+ prefix,
+ suffix,
+ level,
+ health,
+}: Props) {
+ const power = level * (6 - tier);
+ const displayName =
+ prefix > 0 && suffix > 0
+ ? `"${prefixName(prefix)} ${suffixName(suffix)}" ${name || 'Unnamed'}`
+ : name || 'Unnamed';
+
+ return (
+
+
+ {displayName}
+
+
+
+ {art ? (
+
+ ) : (
+
Upload art to preview
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Preview only — the collection renders this card fully onchain.
+ {prefix > 0 && ' Affixes shown are a sample: every mint draws its own.'}{' '}
+ Ranks and kill stats appear once a Beast is minted.
+
+
+ );
+}
+
+function Stat({ label, value }: { label: string; value: string }) {
+ return (
+
+ );
+}
diff --git a/app/src/components/Collection.tsx b/app/src/components/Collection.tsx
new file mode 100644
index 0000000..81da932
--- /dev/null
+++ b/app/src/components/Collection.tsx
@@ -0,0 +1,128 @@
+import { type Beast, type BeastsClient, isGenesis } from '@provable-games/beasts-sdk';
+import { useEffect, useMemo, useState } from 'react';
+import { artFor, useArt } from '../lib/useArt';
+import { BeastTile } from './BeastTile';
+
+interface Props {
+ client: BeastsClient;
+ address: string;
+ isYou: boolean;
+ onOpenSpecies: (beastId: bigint) => void;
+ onViewAddress: (address: string) => void;
+}
+
+/**
+ * Every Beast an address holds.
+ *
+ * The address is a route parameter, not component state, so the URL can be
+ * edited to any wallet and shared — viewing someone else's collection needs no
+ * connection at all.
+ */
+export function Collection({ client, address, isYou, onOpenSpecies, onViewAddress }: Props) {
+ const [beasts, setBeasts] = useState(null);
+ const [names, setNames] = useState>(new Map());
+ const [error, setError] = useState(null);
+ const [lookup, setLookup] = useState('');
+
+ useEffect(() => {
+ let cancelled = false;
+ setBeasts(null);
+ setError(null);
+
+ async function load() {
+ try {
+ const held = await client.getTokensOfOwner(address);
+ if (cancelled) return;
+ setBeasts(held);
+
+ // One name lookup per distinct species, not per token.
+ const species = [...new Set(held.map((b) => b.id.toString()))];
+ const resolved = new Map();
+ for (const id of species) {
+ try {
+ resolved.set(id, await client.getSpeciesName(BigInt(id)));
+ } catch {
+ resolved.set(id, `Species ${id}`);
+ }
+ }
+ if (!cancelled) setNames(resolved);
+ } catch (e) {
+ if (!cancelled) setError(e instanceof Error ? e.message : String(e));
+ }
+ }
+
+ void load();
+ return () => {
+ cancelled = true;
+ };
+ }, [client, address]);
+
+ const art = useArt(client, beasts ?? []);
+
+ const sorted = useMemo(
+ () =>
+ [...(beasts ?? [])].sort(
+ (a, b) => Number(a.id - b.id) || a.prefix - b.prefix || a.suffix - b.suffix,
+ ),
+ [beasts],
+ );
+
+ const genesisCount = sorted.filter(isGenesis).length;
+
+ return (
+
+
+
+ {error &&
{error}
}
+ {beasts === null && !error &&
Reading the collection…
}
+ {beasts?.length === 0 && (
+
+
{isYou ? 'You hold no Beasts yet.' : 'This address holds no Beasts.'}
+
+ )}
+
+
+ {sorted.map((beast) => (
+ onOpenSpecies(beast.id)}
+ />
+ ))}
+
+
+ );
+}
diff --git a/app/src/components/ConnectModal.tsx b/app/src/components/ConnectModal.tsx
new file mode 100644
index 0000000..579ce2b
--- /dev/null
+++ b/app/src/components/ConnectModal.tsx
@@ -0,0 +1,108 @@
+import { useConnect } from '@starknet-react/core';
+import type { Connector } from '@starknet-react/core';
+import { useState } from 'react';
+
+interface Props {
+ onClose: () => void;
+}
+
+/**
+ * Wallet picker.
+ *
+ * Connectors arrive from `WalletProvider`: Cartridge Controller first (it
+ * needs no extension, which is the likely case for a first-time artist), then
+ * any injected wallet. Recommended-but-not-installed wallets are still listed
+ * so the choice is visible rather than hidden — clicking one sends the artist
+ * to its download page, which is `InjectedConnector`'s own behaviour.
+ *
+ * Connection failures are shown here. Swallowing them is what makes a Connect
+ * button look broken.
+ */
+export function ConnectModal({ onClose }: Props) {
+ const { connect, connectors } = useConnect();
+ const [pending, setPending] = useState(null);
+ const [error, setError] = useState(null);
+
+ async function pick(connector: Connector) {
+ setPending(connector.id);
+ setError(null);
+ try {
+ await connect({ connector });
+ onClose();
+ } catch (e) {
+ setError(describe(e));
+ } finally {
+ setPending(null);
+ }
+ }
+
+ return (
+
+
e.stopPropagation()}>
+
+ Connect a wallet
+
+ ×
+
+
+
+
+ You need Sepolia STRK to register a Beast. Browsing and previewing
+ work without a wallet.
+
+
+
+ {connectors.map((connector) => {
+ // Controller runs in a hosted iframe, so it is always available;
+ // injected wallets are only there if their extension is.
+ const installed = connector.available();
+ return (
+
+ void pick(connector)}
+ >
+
+ {connector.name}
+
+ {pending === connector.id
+ ? 'Connecting…'
+ : installed
+ ? ''
+ : 'Not detected'}
+
+
+
+ );
+ })}
+
+
+ {connectors.some((c) => !c.available()) && (
+
+ Wallets marked “Not detected” need their browser extension
+ installed. Install it, then reload this page.
+
+ )}
+
+ {error &&
{error}
}
+
+
+ );
+}
+
+function WalletIcon({ connector }: { connector: Connector }) {
+ const icon = connector.icon;
+ const src = typeof icon === 'string' ? icon : (icon?.dark ?? icon?.light);
+ if (!src) return ;
+ return ;
+}
+
+function describe(error: unknown): string {
+ const message = error instanceof Error ? error.message : String(error);
+ if (/reject|denied|cancel/i.test(message)) return 'Connection cancelled.';
+ if (/not found|no wallet|unavailable/i.test(message)) {
+ return 'That wallet is not installed in this browser.';
+ }
+ return message;
+}
diff --git a/app/src/components/Dashboard.tsx b/app/src/components/Dashboard.tsx
new file mode 100644
index 0000000..72c23d2
--- /dev/null
+++ b/app/src/components/Dashboard.tsx
@@ -0,0 +1,335 @@
+import {
+ BEAST_TYPE_NAMES,
+ type BeastDefinition,
+ type BeastsClient,
+} from '@provable-games/beasts-sdk';
+import { useEffect, useState } from 'react';
+import { ART_SLOTS, loadArtFile, type ArtSlot, type LoadedArt } from '../lib/art';
+
+interface Props {
+ /** Connected wallet, needed as the `from` of a Genesis Beast transfer. */
+ address?: string;
+ beastId: bigint;
+ definition: BeastDefinition;
+ client: BeastsClient;
+ isArtist: boolean;
+ onChanged: () => void;
+}
+
+const ZERO = '0x0';
+
+/**
+ * Per-species controls. Every action here is artist-only on-chain; the UI
+ * simply hides what the caller cannot do, and the contract is the real gate.
+ */
+export function Dashboard({ address, beastId, definition, client, isArtist, onChanged }: Props) {
+ const [busy, setBusy] = useState(null);
+ const [error, setError] = useState(null);
+ const [minter, setMinter] = useState(definition.minter);
+ const [statsSource, setStatsSource] = useState(definition.statsSource);
+ const [newArtist, setNewArtist] = useState('');
+ const [customProvider, setCustomProvider] = useState('');
+ const [art, setArt] = useState>>({});
+ const [genesisTokenId, setGenesisTokenId] = useState(null);
+
+ // The creator token's ID is derivable, but read it from the registry so the
+ // address shown is the one the contract will actually check.
+ useEffect(() => {
+ let cancelled = false;
+ void client
+ .getGenesisTokenId(beastId)
+ .then((id) => !cancelled && setGenesisTokenId(id))
+ .catch(() => !cancelled && setGenesisTokenId(null));
+ return () => {
+ cancelled = true;
+ };
+ }, [client, beastId]);
+
+ async function run(label: string, build: () => Parameters[0]) {
+ setBusy(label);
+ setError(null);
+ try {
+ await client.execute(build());
+ onChanged();
+ } catch (e) {
+ setError(e instanceof Error ? e.message : String(e));
+ } finally {
+ setBusy(null);
+ }
+ }
+
+ const paused = BigInt(definition.minter) === 0n;
+ const artComplete = ART_SLOTS.every(({ slot }) => art[slot]);
+
+ return (
+
+
+
+ {!isArtist && (
+
+ You are not the artist for this species. These controls are read-only.
+
+ )}
+ {error &&
{error}
}
+
+
+ Minting
+ {definition.minterLocked ? (
+
+ The minter is locked to {short(definition.minter)} and can
+ never change. Holders can rely on that.
+
+ ) : (
+ <>
+
+ Set to zero to pause. Pausing stops new mints; it never affects
+ Beasts already minted.
+
+
+ setMinter(e.target.value)}
+ />
+ run('minter', () => client.setMinterCall(beastId, minter))}
+ >
+ {busy === 'minter' ? 'Saving…' : 'Set minter'}
+
+ run('pause', () => client.setMinterCall(beastId, ZERO))}
+ >
+ Pause
+
+
+ {
+ if (
+ confirm(
+ 'Locking the minter is permanent. The minting address can never change again. Continue?',
+ )
+ ) {
+ run('lockMinter', () => client.lockMinterCall(beastId));
+ }
+ }}
+ >
+ Lock minter forever
+
+ >
+ )}
+
+
+
+ Artwork
+ {definition.artLocked ? (
+
+ Art is locked.{' '}
+ {definition.factoryProvider
+ ? 'This species is frozen: the art is stored onchain and can never change.'
+ : 'The provider address is frozen, but a custom provider can still change what it returns — so refreshes stay available.'}
+
+ ) : definition.factoryProvider ? (
+ <>
+
+ Replacing art re-renders every Beast of this species and notifies
+ marketplaces automatically. Limited to one refresh per hour.
+
+
+
+ run('art', () =>
+ client.updateArtCall(beastId, {
+ pngRegular: art.pngRegular!.dataUri,
+ pngShiny: art.pngShiny!.dataUri,
+ gifRegular: art.gifRegular!.dataUri,
+ gifShiny: art.gifShiny!.dataUri,
+ }),
+ )
+ }
+ >
+ {busy === 'art' ? 'Updating…' : 'Replace all four variants'}
+
+ >
+ ) : (
+ <>
+
+ This species renders through your own provider at{' '}
+ {short(definition.artProvider)}. Announce changes so
+ marketplaces re-read it.
+
+ run('notify', () => client.notifyArtUpdatedCall(beastId))}
+ >
+ {busy === 'notify' ? 'Refreshing…' : 'Refresh metadata'}
+
+ >
+ )}
+
+
+ Advanced: swap art provider
+
+ Point this species at your own IBeastArtProvider contract
+ to vary art by affix, tier or level. Your provider must return an
+ allowlisted image data URI or rendering will fail for your species.
+
+
+ setCustomProvider(e.target.value)}
+ />
+
+ run('provider', () => client.setArtProviderCall(beastId, customProvider))
+ }
+ >
+ Swap provider
+
+
+
+
+ {!definition.artLocked && (
+ {
+ if (
+ confirm(
+ 'Locking art is permanent. For verified (factory) art this freezes your species forever. Continue?',
+ )
+ ) {
+ run('lockArt', () => client.lockArtCall(beastId));
+ }
+ }}
+ >
+ Lock art forever
+
+ )}
+
+
+
+
+
+ Transfer this species
+
+ Control of {definition.name} is ownership of its
+ Genesis Beast — there is no separate role. Sending the token hands the
+ new holder everything on this page, and you lose it. Selling the
+ Genesis Beast on any marketplace does the same thing.
+
+
+ Genesis Beast #{beastId.toString()} · token{' '}
+ {genesisTokenId === null ? '…' : shortHex(genesisTokenId)}
+
+
+ setNewArtist(e.target.value)}
+ />
+ {
+ if (
+ confirm(
+ `Send the Genesis Beast for ${definition.name} to ${newArtist}?\n\n` +
+ 'This transfers the token AND every control on this page. It cannot be undone from here — only the new holder can send it back.',
+ )
+ ) {
+ run('artist', () =>
+ client.transferGenesisBeastCall(address!, newArtist, genesisTokenId!),
+ );
+ }
+ }}
+ >
+ Transfer
+
+
+
+
+ );
+}
+
+function shortHex(value: bigint): string {
+ const hex = value.toString(16);
+ return hex.length <= 12 ? `0x${hex}` : `0x${hex.slice(0, 6)}…${hex.slice(-4)}`;
+}
+
+function short(address: string): string {
+ const hex = BigInt(address).toString(16);
+ if (hex === '0') return '0x0';
+ return `0x${hex.slice(0, 4)}…${hex.slice(-4)}`;
+}
diff --git a/app/src/components/MySpecies.tsx b/app/src/components/MySpecies.tsx
new file mode 100644
index 0000000..16f4af6
--- /dev/null
+++ b/app/src/components/MySpecies.tsx
@@ -0,0 +1,154 @@
+import {
+ BEAST_TYPE_NAMES,
+ type BeastsClient,
+ type OwnedSpecies,
+ decodeTokenId,
+} from '@provable-games/beasts-sdk';
+import { useCallback, useEffect, useState } from 'react';
+
+interface Props {
+ client: BeastsClient;
+ address: string;
+ onOpen: (beastId: bigint) => void;
+ onRegister: () => void;
+}
+
+interface Row extends OwnedSpecies {
+ /** Undefined while loading; null when the provider could not be read. */
+ art?: string | null;
+}
+
+/**
+ * Everything the connected wallet controls.
+ *
+ * "Controls" means holding the artist role, which is what the registry's
+ * permissioned entrypoints actually check — not holding the Genesis Beast.
+ * The two start together but diverge the moment either is transferred, and
+ * showing the wrong one would offer controls that revert.
+ */
+export function MySpecies({ client, address, onOpen, onRegister }: Props) {
+ const [rows, setRows] = useState(null);
+ const [error, setError] = useState(null);
+ const [lookup, setLookup] = useState('');
+
+ const load = useCallback(async () => {
+ setRows(null);
+ setError(null);
+ try {
+ const owned = await client.getOwnedSpecies(address);
+ setRows(owned);
+
+ // Art comes from each species' own provider, which for a custom
+ // provider is arbitrary contract code. One that reverts must cost its
+ // own thumbnail, not the whole list.
+ const withArt = await Promise.all(
+ owned.map(async (species) => {
+ try {
+ const beast = decodeTokenId(species.genesisTokenId);
+ return { ...species, art: await client.getArt(beast) };
+ } catch {
+ return { ...species, art: null };
+ }
+ }),
+ );
+ setRows(withArt);
+ } catch (e) {
+ setError(e instanceof Error ? e.message : String(e));
+ }
+ }, [client, address]);
+
+ useEffect(() => {
+ void load();
+ }, [load]);
+
+ return (
+
+
+
+ {error &&
{error}
}
+
+ {rows === null && !error &&
Looking up your species…
}
+
+ {rows?.length === 0 && (
+
+
You haven’t added a Beast yet.
+
+ Add your first Beast
+
+
+ )}
+
+ {rows && rows.length > 0 && (
+
+ {rows.map((row) => {
+ const paused = BigInt(row.definition.minter) === 0n;
+ return (
+
+ onOpen(row.beastId)}>
+
+ {row.art ? (
+
+ ) : (
+
+ {row.art === null ? 'Art unavailable' : '…'}
+
+ )}
+
+
+
+
+ {row.definition.name}
+ #{row.beastId.toString()}
+
+
+ {BEAST_TYPE_NAMES[row.definition.beastType]} · Tier{' '}
+ {row.definition.tier} ·{' '}
+ {row.definition.factoryProvider ? 'Verified art' : 'Custom provider'}
+
+
+
+ {paused ? (
+ Minting paused
+ ) : (
+ Minting live
+ )}
+ {row.definition.artLocked && Art locked }
+ {row.definition.minterLocked && (
+ Minter locked
+ )}
+
+
+
+
+ );
+ })}
+
+ )}
+
+ );
+}
diff --git a/app/src/components/RegisterForm.tsx b/app/src/components/RegisterForm.tsx
new file mode 100644
index 0000000..8393287
--- /dev/null
+++ b/app/src/components/RegisterForm.tsx
@@ -0,0 +1,243 @@
+import { useAccount } from '@starknet-react/core';
+import {
+ BEAST_TYPE_NAMES,
+ BeastType,
+ MAX_NAME_BYTES,
+ MAX_SUPPLY_PER_SPECIES,
+ validateSpeciesName,
+ validateTier,
+} from '@provable-games/beasts-sdk';
+import { useMemo, useState } from 'react';
+import { ART_SLOTS, totalStorageSlots, type ArtSlot, type LoadedArt } from '../lib/art';
+import { ArtUpload } from './ArtUpload';
+import { CardPreview } from './CardPreview';
+
+export interface RegistrationInput {
+ name: string;
+ tier: number;
+ beastType: BeastType;
+ minter: string;
+ art: { pngRegular: string; pngShiny: string; gifRegular: string; gifShiny: string };
+}
+
+interface Props {
+ onSubmit: (input: RegistrationInput) => void;
+ submitting: boolean;
+ error?: string;
+}
+
+const ZERO = '0x0';
+
+export function RegisterForm({ onSubmit, submitting, error }: Props) {
+ const { address } = useAccount();
+ const [name, setName] = useState('');
+ const [tier, setTier] = useState(3);
+ const [beastType, setBeastType] = useState(BeastType.Magic);
+ const [minterMode, setMinterMode] = useState<'later' | 'custom'>('later');
+ const [minter, setMinter] = useState('');
+ const [loaded, setLoaded] = useState>>({});
+ const [preview, setPreview] = useState('pngRegular');
+
+ const nameCheck = name ? validateSpeciesName(name) : { valid: false };
+ const tierCheck = validateTier(tier);
+ const missingArt = ART_SLOTS.filter(({ slot }) => !loaded[slot]);
+ const minterValid = minterMode === 'later' || /^0x[0-9a-fA-F]{1,64}$/.test(minter.trim());
+
+ const ready =
+ nameCheck.valid && tierCheck.valid && missingArt.length === 0 && minterValid && !!address;
+
+ const slots = useMemo(() => totalStorageSlots(loaded), [loaded]);
+
+ function submit() {
+ if (!ready) return;
+ onSubmit({
+ name,
+ tier,
+ beastType,
+ minter: minterMode === 'later' ? ZERO : minter.trim(),
+ art: {
+ pngRegular: loaded.pngRegular!.dataUri,
+ pngShiny: loaded.pngShiny!.dataUri,
+ gifRegular: loaded.gifRegular!.dataUri,
+ gifShiny: loaded.gifShiny!.dataUri,
+ },
+ });
+ }
+
+ return (
+
+
+
+ 1. Artwork
+
+ All four variants are required. Which one a Beast shows is decided by
+ its token ID, so a species cannot ship a partial set.
+
+ setLoaded((l) => ({ ...l, [slot]: art }))}
+ disabled={submitting}
+ />
+ {slots > 0 && (
+
+ About {slots.toLocaleString()} storage slots. There is no size cap —
+ if you are willing to pay for it and the network accepts it, it is
+ valid — but larger art means a more expensive registration.
+
+ )}
+
+
+
+
+
+
+
+ 4. Register
+
+
+ Your wallet receives the Genesis Beast — the
+ creator's token, one per species, in the same transaction.
+
+
+ Your species is capped at {MAX_SUPPLY_PER_SPECIES.toLocaleString()}{' '}
+ Beasts forever.
+
+
+ Name, type and tier can never change. Art and
+ minter can, until you lock them.
+
+
+
+ {!address && Connect a wallet to register.
}
+ {missingArt.length > 0 && (
+
+ Still needed: {missingArt.map((s) => s.label).join(', ')}
+
+ )}
+ {error && {error}
}
+
+
+ {submitting ? 'Registering…' : 'Register Beast'}
+
+
+
+
+
+
+ );
+}
diff --git a/app/src/components/SpeciesCollection.tsx b/app/src/components/SpeciesCollection.tsx
new file mode 100644
index 0000000..dd7e9ee
--- /dev/null
+++ b/app/src/components/SpeciesCollection.tsx
@@ -0,0 +1,140 @@
+import {
+ BEAST_TYPE_NAMES,
+ MAX_SUPPLY_PER_SPECIES,
+ type Beast,
+ type BeastsClient,
+ type SpeciesSummary,
+ decodeTokenId,
+ isGenesis,
+} from '@provable-games/beasts-sdk';
+import { useEffect, useState } from 'react';
+import { artFor, useArt } from '../lib/useArt';
+import { BeastTile } from './BeastTile';
+
+interface Props {
+ client: BeastsClient;
+ beastId: bigint;
+ onBack: () => void;
+ onViewOwner: (address: string) => void;
+}
+
+interface Entry {
+ beast: Beast;
+ rank: number;
+ owner?: string;
+}
+
+/**
+ * Every Beast of one species, strongest first.
+ *
+ * Read from the contract's own per-species rank list rather than by scanning:
+ * the NFT already keeps `rank -> token_id` to drive metadata refreshes, so the
+ * ordering here is the same one the collection itself uses.
+ */
+export function SpeciesCollection({ client, beastId, onBack, onViewOwner }: Props) {
+ const [summary, setSummary] = useState(null);
+ const [entries, setEntries] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ let cancelled = false;
+ setEntries([]);
+ setSummary(null);
+ setLoading(true);
+ setError(null);
+
+ async function load() {
+ try {
+ const info = await client.getSpeciesSummary(beastId);
+ if (cancelled) return;
+ setSummary(info);
+
+ const tokens = await client.getSpeciesTokens(beastId);
+ if (cancelled) return;
+
+ const collected: Entry[] = [];
+ for (let i = 0; i < tokens.length && !cancelled; i += 4) {
+ const batch = await Promise.all(
+ tokens.slice(i, i + 4).map(async (tokenId) => {
+ const beast = decodeTokenId(tokenId);
+ const owner = await client.ownerOf(tokenId).catch(() => undefined);
+ return { beast, rank: isGenesis(beast) ? 0 : 0, owner };
+ }),
+ );
+ collected.push(...batch);
+ if (!cancelled) setEntries([...collected]);
+ }
+
+ // Tokens arrive in rank order from the contract's list, with the
+ // Genesis Beast appended last.
+ if (!cancelled) {
+ setEntries(
+ collected.map((entry, index) => ({
+ ...entry,
+ rank: isGenesis(entry.beast) ? 0 : index + 1,
+ })),
+ );
+ }
+ } catch (e) {
+ if (!cancelled) setError(e instanceof Error ? e.message : String(e));
+ } finally {
+ if (!cancelled) setLoading(false);
+ }
+ }
+
+ void load();
+ return () => {
+ cancelled = true;
+ };
+ }, [client, beastId]);
+
+ const art = useArt(
+ client,
+ entries.map((e) => e.beast),
+ );
+
+ return (
+
+
+ ← The bestiary
+
+
+
+
+ {error &&
{error}
}
+ {loading && entries.length === 0 && !error &&
Reading the species…
}
+ {!loading && entries.length === 0 && !error && (
+
+
No Beasts of this species have been minted yet.
+
+ )}
+
+
+ {entries.map((entry) => (
+ onViewOwner(entry.owner!) : undefined}
+ />
+ ))}
+
+
+ );
+}
diff --git a/app/src/components/SpeciesIndex.tsx b/app/src/components/SpeciesIndex.tsx
new file mode 100644
index 0000000..0e4f430
--- /dev/null
+++ b/app/src/components/SpeciesIndex.tsx
@@ -0,0 +1,137 @@
+import {
+ BEAST_TYPE_NAMES,
+ type BeastsClient,
+ type SpeciesSummary,
+ genesisBeast,
+} from '@provable-games/beasts-sdk';
+import { useEffect, useState } from 'react';
+import { artFor, useArt } from '../lib/useArt';
+
+interface Props {
+ client: BeastsClient;
+ onOpen: (beastId: bigint) => void;
+}
+
+/**
+ * The whole bestiary, one card per species.
+ *
+ * Grouping by species is the default because the collection is unbounded and
+ * a species can hold up to 1,243 Beasts — a flat list of every token would be
+ * unreadable long before it was useful. Selecting a species opens its own
+ * collection.
+ *
+ * Each card shows the species' Genesis Beast as the representative art: it is
+ * the one Beast guaranteed to exist for every registered species.
+ */
+export function SpeciesIndex({ client, onOpen }: Props) {
+ const [species, setSpecies] = useState([]);
+ const [total, setTotal] = useState(null);
+ const [error, setError] = useState(null);
+ const [showGenesis, setShowGenesis] = useState(false);
+
+ useEffect(() => {
+ let cancelled = false;
+ setSpecies([]);
+ setError(null);
+
+ async function load() {
+ try {
+ const count = Number(await client.speciesCount());
+ if (cancelled) return;
+ setTotal(count);
+
+ // Community species first — they are the ones that change.
+ const order = [
+ ...range(76, count),
+ ...(showGenesis ? range(1, Math.min(75, count)) : []),
+ ];
+
+ const collected: SpeciesSummary[] = [];
+ for (let i = 0; i < order.length && !cancelled; i += 4) {
+ const batch = await Promise.all(
+ order.slice(i, i + 4).map((id) =>
+ client.getSpeciesSummary(BigInt(id)).catch(() => null),
+ ),
+ );
+ collected.push(...batch.filter((s): s is SpeciesSummary => s !== null));
+ if (!cancelled) setSpecies([...collected]);
+ }
+ } catch (e) {
+ if (!cancelled) setError(e instanceof Error ? e.message : String(e));
+ }
+ }
+
+ void load();
+ return () => {
+ cancelled = true;
+ };
+ }, [client, showGenesis]);
+
+ const representatives = species.map((s) => genesisBeast(s.beastId, s.tier, s.beastType));
+ const art = useArt(client, representatives);
+
+ return (
+
+
+
+ {error &&
{error}
}
+ {species.length === 0 && !error &&
Loading species…
}
+
+
+ {species.map((s, index) => (
+
onOpen(s.beastId)}
+ >
+
+ {(() => {
+ const uri = artFor(art, representatives[index]);
+ if (uri === undefined) return
… ;
+ if (uri === null) return
Art unavailable ;
+ return
;
+ })()}
+ {!s.community &&
Original }
+
+
+
+ {s.name} #{s.beastId.toString()}
+
+
+ {BEAST_TYPE_NAMES[s.beastType]} · Tier {s.tier}
+
+
+
+ {s.minted} minted
+
+ of 1,243
+
+
+ ))}
+
+
+ );
+}
+
+function range(from: number, to: number): number[] {
+ return to < from ? [] : Array.from({ length: to - from + 1 }, (_, i) => from + i);
+}
diff --git a/app/src/lib/WalletProvider.tsx b/app/src/lib/WalletProvider.tsx
new file mode 100644
index 0000000..da3a732
--- /dev/null
+++ b/app/src/lib/WalletProvider.tsx
@@ -0,0 +1,47 @@
+import {
+ StarknetConfig,
+ braavos,
+ jsonRpcProvider,
+ ready,
+ useInjectedConnectors,
+ voyager,
+} from '@starknet-react/core';
+import type { PropsWithChildren } from 'react';
+import { RPC_URL, chains, controllerConnector } from './chain';
+
+/**
+ * Wallet wiring for the app.
+ *
+ * Two kinds of wallet, deliberately both supported: Cartridge Controller
+ * (no extension, good for a first-time artist) and any injected browser
+ * wallet — Ready (formerly Argent) and Braavos are surfaced as recommended
+ * even when not installed, so the picker shows what is possible rather than
+ * only what is present.
+ *
+ * `useInjectedConnectors` scans `window.starknet*`, so it must run inside a
+ * component; the connector list is then handed to `StarknetConfig` as a prop.
+ */
+export function WalletProvider({ children }: PropsWithChildren) {
+ const { connectors: injected } = useInjectedConnectors({
+ recommended: [ready(), braavos()],
+ includeRecommended: 'always',
+ order: 'alphabetical',
+ });
+
+ // `publicProvider()` pins RPC spec 0.8.1, which starknet 9.x dropped — it
+ // throws before the tree ever renders. Naming the node lets the provider
+ // negotiate whatever that node actually speaks.
+ const rpc = () => ({ nodeUrl: RPC_URL });
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/src/lib/art.ts b/app/src/lib/art.ts
new file mode 100644
index 0000000..13a016e
--- /dev/null
+++ b/app/src/lib/art.ts
@@ -0,0 +1,109 @@
+import { validateFactoryArt, type ValidationResult } from '@provable-games/beasts-sdk';
+
+export type ArtSlot = 'pngRegular' | 'pngShiny' | 'gifRegular' | 'gifShiny';
+
+export interface ArtSlotSpec {
+ slot: ArtSlot;
+ label: string;
+ hint: string;
+ kind: 'png' | 'gif';
+ accept: string;
+}
+
+/**
+ * The four variants a factory-provider species stores. Which one a token
+ * renders is decided by the shiny and animated bits in its token ID, so all
+ * four are required — a species cannot ship a partial set.
+ */
+export const ART_SLOTS: readonly ArtSlotSpec[] = [
+ {
+ slot: 'pngRegular',
+ label: 'Standard',
+ hint: 'The default look. Shown when a Beast is neither shiny nor animated.',
+ kind: 'png',
+ accept: 'image/png',
+ },
+ {
+ slot: 'pngShiny',
+ label: 'Shiny',
+ hint: 'The rare colourway. Static.',
+ kind: 'png',
+ accept: 'image/png',
+ },
+ {
+ slot: 'gifRegular',
+ label: 'Animated',
+ hint: 'The default look, in motion.',
+ kind: 'gif',
+ accept: 'image/gif',
+ },
+ {
+ slot: 'gifShiny',
+ label: 'Animated + Shiny',
+ hint: 'The rarest combination. Both bits set.',
+ kind: 'gif',
+ accept: 'image/gif',
+ },
+];
+
+export interface LoadedArt {
+ dataUri: string;
+ bytes: number;
+ /** On-chain storage cost: art is stored 31 bytes per felt slot. */
+ slots: number;
+}
+
+export class ArtLoadError extends Error {}
+
+/**
+ * Reads a file into a base64 data URI and checks it against the same rules
+ * the factory provider enforces on write.
+ *
+ * The browser's own decode is the real format check — magic bytes only prove
+ * the header, and a file that cannot be decoded here would render as a broken
+ * image for every holder of the species.
+ */
+export async function loadArtFile(file: File, kind: 'png' | 'gif'): Promise {
+ const dataUri = await readAsDataUri(file);
+
+ const validation: ValidationResult = validateFactoryArt(dataUri, kind);
+ if (!validation.valid) throw new ArtLoadError(validation.error ?? 'Invalid art');
+
+ await assertDecodable(dataUri);
+
+ const bytes = dataUri.length;
+ return { dataUri, bytes, slots: Math.ceil(bytes / 31) };
+}
+
+function readAsDataUri(file: File): Promise {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onerror = () => reject(new ArtLoadError('Could not read that file'));
+ reader.onload = () => {
+ const result = reader.result;
+ if (typeof result !== 'string') {
+ reject(new ArtLoadError('Could not read that file'));
+ return;
+ }
+ resolve(result);
+ };
+ reader.readAsDataURL(file);
+ });
+}
+
+function assertDecodable(dataUri: string): Promise {
+ return new Promise((resolve, reject) => {
+ const image = new Image();
+ image.onload = () => resolve();
+ image.onerror = () => reject(new ArtLoadError('That file is not a valid image'));
+ image.src = dataUri;
+ });
+}
+
+/**
+ * Rough cost signal for the registration transaction. Advisory only — the
+ * contract imposes no size cap, and the network decides what it will accept.
+ */
+export function totalStorageSlots(loaded: Partial>): number {
+ return ART_SLOTS.reduce((sum, { slot }) => sum + (loaded[slot]?.slots ?? 0), 0);
+}
diff --git a/app/src/lib/chain.ts b/app/src/lib/chain.ts
new file mode 100644
index 0000000..2f00f34
--- /dev/null
+++ b/app/src/lib/chain.ts
@@ -0,0 +1,49 @@
+import ControllerConnector from '@cartridge/connector/controller';
+import { sepolia } from '@starknet-react/chains';
+import { SEPOLIA_ADDRESSES } from '@provable-games/beasts-sdk';
+import { RpcProvider } from 'starknet';
+
+export const RPC_URL =
+ import.meta.env.VITE_STARKNET_RPC_URL ??
+ 'https://api.cartridge.gg/x/starknet/sepolia';
+
+export const ADDRESSES = {
+ nft: import.meta.env.VITE_BEASTS_NFT ?? SEPOLIA_ADDRESSES.nft,
+ registry: import.meta.env.VITE_BEASTS_REGISTRY ?? SEPOLIA_ADDRESSES.registry,
+};
+
+/** Sepolia only. Everything this app talks to is deployed there. */
+export const chains = [sepolia];
+
+export const provider = () => new RpcProvider({ nodeUrl: RPC_URL });
+
+/**
+ * Cartridge Controller with the registry's *management* entrypoints
+ * pre-approved, so an artist signs once and can then iterate on their species —
+ * update art, rotate the minter, refresh metadata — without a popup for every
+ * change.
+ *
+ * `register_beast_with_art` is deliberately NOT in the session policy: it
+ * mints the artist's provenance token and permanently assigns a species ID, so
+ * it should always be an explicit, visible signature.
+ */
+export const controllerConnector = new ControllerConnector({
+ chains: [{ rpcUrl: RPC_URL }],
+ // Must be 0x-prefixed hex; the bare digits parse as neither hex nor decimal.
+ defaultChainId: `0x${sepolia.id.toString(16)}`,
+ propagateSessionErrors: true,
+ policies: {
+ contracts: {
+ [ADDRESSES.registry]: {
+ name: 'Beast Registry',
+ methods: [
+ { name: 'Update art', entrypoint: 'update_art' },
+ { name: 'Set minter', entrypoint: 'set_minter' },
+ { name: 'Set art provider', entrypoint: 'set_art_provider' },
+ { name: 'Refresh metadata', entrypoint: 'notify_art_updated' },
+ { name: 'Set stats source', entrypoint: 'set_stats_source' },
+ ],
+ },
+ },
+ },
+});
diff --git a/app/src/lib/router.ts b/app/src/lib/router.ts
new file mode 100644
index 0000000..60d2372
--- /dev/null
+++ b/app/src/lib/router.ts
@@ -0,0 +1,72 @@
+import { useCallback, useEffect, useState } from 'react';
+
+/**
+ * Hash routing, hand-rolled.
+ *
+ * A hash keeps every page a real, shareable URL without needing server
+ * rewrites — this app is a static bundle. The address lives in the path
+ * rather than in component state precisely so `#/collection/0xabc…` can be
+ * edited to any wallet and shared as-is.
+ */
+export type Route =
+ | { name: 'register' }
+ | { name: 'collection'; address: string }
+ | { name: 'species-index' }
+ | { name: 'species'; beastId: bigint }
+ | { name: 'manage' }
+ | { name: 'manage-species'; beastId: bigint };
+
+export function parseRoute(hash: string): Route {
+ const path = hash.replace(/^#\/?/, '').split('?')[0];
+ const [head, tail] = path.split('/');
+
+ switch (head) {
+ case 'collection':
+ return tail ? { name: 'collection', address: tail } : { name: 'register' };
+ case 'beasts':
+ if (!tail) return { name: 'species-index' };
+ return isDigits(tail) ? { name: 'species', beastId: BigInt(tail) } : { name: 'species-index' };
+ case 'manage':
+ if (!tail) return { name: 'manage' };
+ return isDigits(tail) ? { name: 'manage-species', beastId: BigInt(tail) } : { name: 'manage' };
+ default:
+ return { name: 'register' };
+ }
+}
+
+export function href(route: Route): string {
+ switch (route.name) {
+ case 'collection':
+ return `#/collection/${route.address}`;
+ case 'species-index':
+ return '#/beasts';
+ case 'species':
+ return `#/beasts/${route.beastId}`;
+ case 'manage':
+ return '#/manage';
+ case 'manage-species':
+ return `#/manage/${route.beastId}`;
+ default:
+ return '#/';
+ }
+}
+
+export function useRoute(): [Route, (route: Route) => void] {
+ const [hash, setHash] = useState(() => window.location.hash);
+
+ useEffect(() => {
+ const onChange = () => setHash(window.location.hash);
+ window.addEventListener('hashchange', onChange);
+ return () => window.removeEventListener('hashchange', onChange);
+ }, []);
+
+ const navigate = useCallback((route: Route) => {
+ window.location.hash = href(route);
+ }, []);
+
+ return [parseRoute(hash), navigate];
+}
+
+function isDigits(value: string | undefined): value is string {
+ return !!value && /^\d+$/.test(value);
+}
diff --git a/app/src/lib/useArt.ts b/app/src/lib/useArt.ts
new file mode 100644
index 0000000..7d4d016
--- /dev/null
+++ b/app/src/lib/useArt.ts
@@ -0,0 +1,58 @@
+import { type Beast, type BeastsClient, encodeTokenId } from '@provable-games/beasts-sdk';
+import { useEffect, useState } from 'react';
+
+/**
+ * Art is fetched per Beast, not per species.
+ *
+ * A community provider receives the whole decoded Beast, so it may legitimately
+ * vary art by affix, tier or level — caching by species would show the wrong
+ * picture for exactly the providers that make the interface worth having.
+ * Keyed by token ID and shared across pages, so navigating back is free.
+ */
+const cache = new Map();
+
+/** Fetches art for a list of Beasts, filling in progressively. */
+export function useArt(
+ client: BeastsClient,
+ beasts: Beast[],
+): Map {
+ const [, setTick] = useState(0);
+ const key = beasts.map((b) => encodeTokenId(b).toString()).join(',');
+
+ useEffect(() => {
+ let cancelled = false;
+
+ async function load() {
+ // Bounded batches: one request per Beast will out-run a public node's
+ // per-second budget on any collection worth showing.
+ const pending = beasts.filter((b) => !cache.has(encodeTokenId(b).toString()));
+ for (let i = 0; i < pending.length && !cancelled; i += 4) {
+ await Promise.all(
+ pending.slice(i, i + 4).map(async (beast) => {
+ const id = encodeTokenId(beast).toString();
+ try {
+ cache.set(id, await client.getArt(beast));
+ } catch {
+ // A provider that reverts costs its own thumbnail, nothing more.
+ cache.set(id, null);
+ }
+ }),
+ );
+ if (!cancelled) setTick((t) => t + 1);
+ }
+ }
+
+ void load();
+ return () => {
+ cancelled = true;
+ };
+ // `key` collapses the beast list to a stable identity.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [client, key]);
+
+ return cache;
+}
+
+export function artFor(cache: Map, beast: Beast): string | null | undefined {
+ return cache.get(encodeTokenId(beast).toString());
+}
diff --git a/app/src/main.tsx b/app/src/main.tsx
new file mode 100644
index 0000000..7aac99c
--- /dev/null
+++ b/app/src/main.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import { App } from './App';
+import { WalletProvider } from './lib/WalletProvider';
+import './styles.css';
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+
+
+
+
+ ,
+);
diff --git a/app/src/styles.css b/app/src/styles.css
new file mode 100644
index 0000000..321cf8b
--- /dev/null
+++ b/app/src/styles.css
@@ -0,0 +1,929 @@
+:root {
+ --bg: #131316;
+ --panel: #1e1e22;
+ --panel-2: #2d2d32;
+ --line: #ffffff14;
+ --text: #ececf0;
+ --muted: #9a9aa4;
+ --gold: #b79a5e;
+ --gold-bright: #e5d8b2;
+ --danger: #d4674f;
+ --radius: 10px;
+ color-scheme: dark;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ background: var(--bg);
+ color: var(--text);
+ font: 15px/1.55 ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
+}
+
+code {
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
+ font-size: 0.9em;
+ color: var(--gold-bright);
+}
+
+.app {
+ max-width: 1140px;
+ margin: 0 auto;
+ padding: 0 20px 64px;
+}
+
+/* ------------------------------------------------------------- topbar */
+
+.topbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 18px 0;
+ border-bottom: 1px solid var(--line);
+ flex-wrap: wrap;
+}
+
+.brand {
+ background: none;
+ border: 0;
+ padding: 0;
+ color: var(--gold-bright);
+ font-size: 17px;
+ font-weight: 600;
+ letter-spacing: 0.01em;
+ cursor: pointer;
+}
+
+.topbar__right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.lookup {
+ display: flex;
+ gap: 6px;
+}
+
+.lookup input {
+ width: 110px;
+}
+
+/* The collection page's lookup takes a whole address, not an ID. */
+.page__header .lookup input {
+ width: 240px;
+}
+
+/* ------------------------------------------------------------ controls */
+
+button {
+ background: var(--panel-2);
+ color: var(--text);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 9px 14px;
+ font: inherit;
+ font-size: 14px;
+ cursor: pointer;
+ transition: background 0.15s, border-color 0.15s;
+}
+
+button:hover:not(:disabled) {
+ border-color: #ffffff2e;
+ background: #35353c;
+}
+
+button:disabled {
+ opacity: 0.45;
+ cursor: not-allowed;
+}
+
+button.primary {
+ background: linear-gradient(135deg, var(--gold-bright), var(--gold));
+ color: #23201a;
+ border-color: transparent;
+ font-weight: 600;
+}
+
+button.danger {
+ border-color: #d4674f4d;
+ color: var(--danger);
+ background: transparent;
+ margin-top: 12px;
+}
+
+button.danger:hover:not(:disabled) {
+ background: #d4674f1a;
+}
+
+input,
+select {
+ background: #16161a;
+ color: var(--text);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 9px 11px;
+ font: inherit;
+ font-size: 14px;
+ width: 100%;
+}
+
+input:focus,
+select:focus {
+ outline: none;
+ border-color: var(--gold);
+}
+
+/* --------------------------------------------------------------- hero */
+
+.hero {
+ padding: 44px 0 28px;
+ max-width: 640px;
+}
+
+.hero h1 {
+ margin: 0 0 12px;
+ font-size: 34px;
+ line-height: 1.15;
+ letter-spacing: -0.02em;
+}
+
+.hero p {
+ margin: 0 0 8px;
+ color: #c9c9d2;
+}
+
+.muted {
+ color: var(--muted);
+ font-size: 14px;
+}
+
+/* ----------------------------------------------------------- register */
+
+.register {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) 300px;
+ gap: 36px;
+ align-items: start;
+}
+
+@media (max-width: 900px) {
+ .register {
+ grid-template-columns: 1fr;
+ }
+}
+
+.register__form section {
+ padding: 22px 0;
+ border-top: 1px solid var(--line);
+}
+
+.register__form h2 {
+ margin: 0 0 6px;
+ font-size: 16px;
+ letter-spacing: 0.01em;
+}
+
+.register__preview {
+ position: sticky;
+ top: 20px;
+}
+
+.field {
+ display: block;
+ margin: 14px 0;
+}
+
+.field > span {
+ display: block;
+ margin-bottom: 6px;
+ font-size: 13px;
+ color: var(--muted);
+}
+
+.field__hint,
+.field__error {
+ display: block;
+ margin-top: 6px;
+ font-size: 12.5px;
+ font-style: normal;
+}
+
+.field__hint {
+ color: var(--muted);
+}
+
+.field__error {
+ color: var(--danger);
+}
+
+.radio {
+ display: flex;
+ gap: 10px;
+ align-items: flex-start;
+ padding: 11px 0;
+ cursor: pointer;
+}
+
+.radio input {
+ width: auto;
+ margin-top: 3px;
+}
+
+.radio span {
+ display: block;
+}
+
+.radio em {
+ display: block;
+ color: var(--muted);
+ font-size: 13px;
+ font-style: normal;
+ margin-top: 2px;
+}
+
+.summary {
+ margin: 0 0 18px;
+ padding-left: 18px;
+ color: #c9c9d2;
+ font-size: 14px;
+}
+
+.summary li {
+ margin: 6px 0;
+}
+
+/* ------------------------------------------------------------ art grid */
+
+.art-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
+ gap: 12px;
+ margin: 16px 0;
+}
+
+.art-slot {
+ background: var(--panel);
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 12px;
+}
+
+.art-slot--selected {
+ border-color: var(--gold);
+}
+
+.art-slot--error {
+ border-color: var(--danger);
+}
+
+.art-slot__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ margin-bottom: 8px;
+}
+
+.art-slot__label {
+ font-size: 13px;
+ font-weight: 600;
+}
+
+.art-slot__kind {
+ font-size: 11px;
+ color: var(--muted);
+}
+
+.art-slot__drop {
+ display: block;
+ position: relative;
+ aspect-ratio: 1;
+ background: #000;
+ border-radius: 6px;
+ overflow: hidden;
+ cursor: pointer;
+ display: grid;
+ place-items: center;
+}
+
+.art-slot__drop input,
+.art-slot--compact input {
+ position: absolute;
+ inset: 0;
+ opacity: 0;
+ cursor: pointer;
+ width: 100%;
+}
+
+.art-slot img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ image-rendering: pixelated;
+}
+
+.art-slot__placeholder {
+ color: var(--muted);
+ font-size: 12px;
+}
+
+.art-slot__hint {
+ margin: 8px 0 0;
+ font-size: 12px;
+ color: var(--muted);
+}
+
+.art-slot__meta {
+ margin: 4px 0 0;
+ font-size: 11.5px;
+ color: var(--gold);
+}
+
+.art-slot__error {
+ margin: 6px 0 0;
+ font-size: 12px;
+ color: var(--danger);
+}
+
+.art-grid--compact {
+ grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
+}
+
+.art-slot--compact {
+ position: relative;
+ display: grid;
+ gap: 6px;
+ place-items: center;
+ cursor: pointer;
+}
+
+.art-slot--compact img {
+ aspect-ratio: 1;
+}
+
+/* ---------------------------------------------------------------- card */
+
+.card {
+ background: linear-gradient(180deg, var(--panel-2), var(--panel));
+ border: 2px solid transparent;
+ border-radius: 14px;
+ padding: 14px;
+ background-clip: padding-box;
+ box-shadow: 0 0 0 2px #ffffff10;
+}
+
+.card--shiny {
+ box-shadow: 0 0 0 2px var(--gold), 0 0 22px #b79a5e40;
+}
+
+.card__title {
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--gold-bright);
+ text-align: center;
+ margin-bottom: 10px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.card__art {
+ position: relative;
+ aspect-ratio: 220 / 144;
+ background: #000;
+ border-radius: 8px;
+ display: grid;
+ place-items: center;
+ overflow: hidden;
+}
+
+/* Absolute inset is what gives the image a definite box to fit inside.
+ A percentage height against an `aspect-ratio` parent resolves to `auto`,
+ so a square Beast would size itself from its own 1:1 ratio, overflow the
+ wider frame, and get cropped top and bottom by `overflow: hidden`. */
+.card__art img {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ image-rendering: pixelated;
+}
+
+.card__art-empty {
+ color: var(--muted);
+ font-size: 12px;
+}
+
+.card__stats {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 8px;
+ margin-top: 10px;
+}
+
+.stat {
+ background: var(--panel);
+ border-radius: 6px;
+ padding: 7px 8px;
+ text-align: center;
+}
+
+.stat__label {
+ font-size: 10px;
+ color: var(--muted);
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+}
+
+.stat__value {
+ font-size: 15px;
+ font-weight: 600;
+ color: var(--gold-bright);
+}
+
+.card__note {
+ margin: 12px 0 0;
+ font-size: 11.5px;
+ color: var(--muted);
+ text-align: center;
+}
+
+/* ----------------------------------------------------------- dashboard */
+
+.dashboard {
+ padding-top: 32px;
+}
+
+.dashboard__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 16px;
+ flex-wrap: wrap;
+ padding-bottom: 18px;
+ border-bottom: 1px solid var(--line);
+}
+
+.dashboard__header h2 {
+ margin: 0;
+ font-size: 24px;
+}
+
+.dashboard__header p {
+ margin: 4px 0 0;
+}
+
+.badges {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
+.badge {
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ padding: 4px 11px;
+ font-size: 12px;
+ color: var(--muted);
+}
+
+.badge--warn {
+ border-color: #d4674f4d;
+ color: var(--danger);
+}
+
+.panel {
+ padding: 22px 0;
+ border-bottom: 1px solid var(--line);
+}
+
+.panel h3 {
+ margin: 0 0 6px;
+ font-size: 15px;
+}
+
+.panel p {
+ margin: 0 0 12px;
+}
+
+.row {
+ display: flex;
+ gap: 8px;
+ margin: 12px 0;
+ flex-wrap: wrap;
+}
+
+.row input {
+ flex: 1 1 240px;
+}
+
+.row button {
+ white-space: nowrap;
+}
+
+.advanced {
+ margin-top: 16px;
+ border-top: 1px solid var(--line);
+ padding-top: 14px;
+}
+
+.advanced summary {
+ cursor: pointer;
+ font-size: 14px;
+ color: var(--muted);
+}
+
+.notice {
+ background: #b79a5e1a;
+ border: 1px solid #b79a5e33;
+ border-radius: var(--radius);
+ padding: 11px 14px;
+ font-size: 14px;
+ margin: 18px 0;
+}
+
+.empty {
+ padding: 80px 0;
+ text-align: center;
+ display: grid;
+ gap: 14px;
+ place-items: center;
+}
+
+.footer {
+ margin-top: 48px;
+ padding-top: 18px;
+ border-top: 1px solid var(--line);
+ font-size: 12.5px;
+ color: var(--muted);
+}
+
+.modal__hint {
+ margin: 14px 0 0;
+ font-size: 12.5px;
+}
+
+/* ---------------------------------------------------------- connect modal */
+
+.modal-backdrop {
+ position: fixed;
+ inset: 0;
+ background: #000000b8;
+ display: grid;
+ place-items: center;
+ padding: 20px;
+ z-index: 50;
+}
+
+.modal {
+ background: var(--panel);
+ border: 1px solid var(--line);
+ border-radius: 14px;
+ padding: 22px;
+ width: 100%;
+ max-width: 380px;
+ box-shadow: 0 20px 60px #00000080;
+}
+
+.modal__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 6px;
+}
+
+.modal__header h3 {
+ margin: 0;
+ font-size: 17px;
+}
+
+.modal__close {
+ background: none;
+ border: 0;
+ color: var(--muted);
+ font-size: 24px;
+ line-height: 1;
+ padding: 0 4px;
+ cursor: pointer;
+}
+
+.wallets {
+ list-style: none;
+ margin: 18px 0 0;
+ padding: 0;
+ display: grid;
+ gap: 8px;
+}
+
+.wallet {
+ display: flex;
+ align-items: center;
+ gap: 11px;
+ width: 100%;
+ text-align: left;
+ padding: 12px 14px;
+}
+
+.wallet__icon {
+ width: 24px;
+ height: 24px;
+ border-radius: 6px;
+ object-fit: contain;
+ flex: none;
+}
+
+.wallet__icon--blank {
+ background: var(--panel-2);
+}
+
+.wallet__name {
+ flex: 1;
+ font-weight: 500;
+}
+
+.wallet__state {
+ font-size: 12px;
+ color: var(--muted);
+}
+
+/* ------------------------------------------------------------ my species */
+
+.mine {
+ padding-top: 36px;
+}
+
+.mine__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 20px;
+ flex-wrap: wrap;
+ padding-bottom: 20px;
+ border-bottom: 1px solid var(--line);
+}
+
+.mine__header h1 {
+ margin: 0 0 6px;
+ font-size: 26px;
+ letter-spacing: -0.01em;
+}
+
+.mine__header p {
+ margin: 0;
+ max-width: 46ch;
+}
+
+.species-grid {
+ list-style: none;
+ margin: 22px 0 0;
+ padding: 0;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
+ gap: 14px;
+}
+
+.species-card {
+ display: flex;
+ gap: 14px;
+ width: 100%;
+ text-align: left;
+ align-items: center;
+ padding: 14px;
+ background: var(--panel);
+}
+
+.species-card__art {
+ position: relative;
+ width: 72px;
+ height: 72px;
+ flex: none;
+ background: #000;
+ border-radius: 8px;
+ overflow: hidden;
+ display: grid;
+ place-items: center;
+}
+
+.species-card__art img {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ image-rendering: pixelated;
+}
+
+.species-card__art-empty {
+ font-size: 10.5px;
+ color: var(--muted);
+ text-align: center;
+ padding: 0 6px;
+}
+
+.species-card__body {
+ min-width: 0;
+}
+
+.species-card__title {
+ font-weight: 600;
+ margin-bottom: 3px;
+}
+
+.species-card .badges {
+ margin-top: 8px;
+}
+
+.badge--ok {
+ border-color: #6f9e6a4d;
+ color: #8fbe89;
+}
+
+.backlink {
+ background: none;
+ border: 0;
+ padding: 0;
+ margin: 26px 0 0;
+ color: var(--muted);
+ font-size: 14px;
+ cursor: pointer;
+}
+
+.backlink:hover {
+ color: var(--text);
+ background: none;
+}
+
+/* ---------------------------------------------------------------- pages */
+
+.page {
+ padding-top: 32px;
+}
+
+.page__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 20px;
+ flex-wrap: wrap;
+ padding-bottom: 20px;
+ border-bottom: 1px solid var(--line);
+}
+
+.page__header h1 {
+ margin: 0 0 6px;
+ font-size: 26px;
+ letter-spacing: -0.01em;
+}
+
+.page__header p {
+ margin: 0 0 4px;
+ max-width: 60ch;
+ word-break: break-all;
+}
+
+.navlink {
+ color: var(--text);
+ text-decoration: none;
+ border: 1px solid var(--line);
+ border-radius: var(--radius);
+ padding: 9px 14px;
+ font-size: 14px;
+ background: var(--panel-2);
+ transition: background 0.15s, border-color 0.15s;
+}
+
+.navlink:hover {
+ border-color: #ffffff2e;
+ background: #35353c;
+}
+
+a.brand {
+ text-decoration: none;
+}
+
+.toggle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 13.5px;
+ color: var(--muted);
+ cursor: pointer;
+ white-space: nowrap;
+}
+
+.toggle input {
+ width: auto;
+}
+
+/* ---------------------------------------------------------------- tiles */
+
+.tiles {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
+ gap: 14px;
+ margin-top: 22px;
+}
+
+.tile {
+ background: linear-gradient(180deg, var(--panel-2), var(--panel));
+ border: 1px solid var(--line);
+ border-radius: 12px;
+ padding: 12px;
+ text-align: left;
+ width: 100%;
+ display: block;
+}
+
+.tile--clickable {
+ cursor: pointer;
+}
+
+.tile--clickable:hover {
+ border-color: var(--gold);
+ background: linear-gradient(180deg, #35353c, var(--panel));
+}
+
+.tile__art {
+ position: relative;
+ aspect-ratio: 1;
+ background: #000;
+ border-radius: 8px;
+ overflow: hidden;
+ display: grid;
+ place-items: center;
+ margin-bottom: 10px;
+}
+
+.tile__art--shiny {
+ box-shadow: inset 0 0 0 2px var(--gold);
+}
+
+/* Absolute inset gives the image a definite box; a percentage height against
+ an aspect-ratio parent resolves to auto and a square Beast would overflow. */
+.tile__art img {
+ position: absolute;
+ inset: 0;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ image-rendering: pixelated;
+}
+
+.tile__art-note {
+ font-size: 11px;
+ color: var(--muted);
+ text-align: center;
+ padding: 0 8px;
+}
+
+.tile__badge {
+ position: absolute;
+ top: 6px;
+ left: 6px;
+ background: #000000b0;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ padding: 2px 8px;
+ font-size: 10px;
+ color: var(--gold-bright);
+ letter-spacing: 0.03em;
+}
+
+.tile__badge--corner {
+ left: auto;
+ right: 6px;
+ color: var(--muted);
+}
+
+.tile__name {
+ font-size: 13.5px;
+ font-weight: 600;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.tile__meta {
+ font-size: 12px;
+ color: var(--muted);
+ margin-top: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.tile__stats {
+ display: flex;
+ justify-content: space-between;
+ gap: 6px;
+ margin-top: 8px;
+ padding-top: 8px;
+ border-top: 1px solid var(--line);
+ font-size: 11.5px;
+ color: var(--muted);
+}
diff --git a/app/src/vite-env.d.ts b/app/src/vite-env.d.ts
new file mode 100644
index 0000000..8e73e6d
--- /dev/null
+++ b/app/src/vite-env.d.ts
@@ -0,0 +1,11 @@
+///
+
+interface ImportMetaEnv {
+ readonly VITE_STARKNET_RPC_URL?: string;
+ readonly VITE_BEASTS_NFT?: string;
+ readonly VITE_BEASTS_REGISTRY?: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/app/tsconfig.json b/app/tsconfig.json
new file mode 100644
index 0000000..c9d766b
--- /dev/null
+++ b/app/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "jsx": "react-jsx",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "resolveJsonModule": true,
+ "noEmit": true,
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true
+ },
+ "include": ["src"]
+}
diff --git a/app/vite.config.ts b/app/vite.config.ts
new file mode 100644
index 0000000..fabde1a
--- /dev/null
+++ b/app/vite.config.ts
@@ -0,0 +1,6 @@
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ plugins: [react()],
+});
diff --git a/docs/sepolia-v3-deployment.md b/docs/sepolia-v3-deployment.md
index e26fc0e..b501a89 100644
--- a/docs/sepolia-v3-deployment.md
+++ b/docs/sepolia-v3-deployment.md
@@ -1,7 +1,8 @@
# Beasts V3 — Sepolia deployment
-Deployed 2026-07-31 from branch `feat/nft-registry-integration` (PR #20,
-stacked on #19). Tooling: **sncast 0.60.0** (`--network sepolia`). Not
+Redeployed 2026-07-31 from `feat/nft-registry-integration` (PR #20) after
+owner enumeration merged (#14) and the artist role became Genesis Beast
+ownership. Supersedes the earlier deployment; those addresses are dead. Tooling: **sncast 0.60.0** (`--network sepolia`). Not
starkli — it is unsupported and absent from this environment.
Deployer / owner / royalty receiver: sncast account `commit-reveal-sepolia`
@@ -13,8 +14,8 @@ Total cost: ~10 STRK.
| Contract | Address |
|---|---|
-| **beasts_nft** | `0x01dac77837c6751777d917051a6e405967c5c75f46df5ab7c635e52819634bfd` |
-| **beast_registry** | `0x06d46c98087a1246182c6cd8ef144ee0a67da6e6cc9e44e39aef08cf92d30045` |
+| **beasts_nft** | `0x017e2cb5d7c4a86ff2bdee182ce53386a7cc57c63b943878de21b681e336a89a` |
+| **beast_registry** | `0x0797a19c0b267e91ea17f886f155310e38196261ec5683e3a12a35772718d723` |
| beast_png_regular_data | `0x045f6cf8249ebee56f699a46cb66f02cbd23419f1c2cd3e62a3dfdedaf894279` |
| beast_png_shiny_data | `0x0291ad81a428262fd709f0075dedf69814173bf5b60f989cf7095f5efa72c670` |
| beast_gif_regular_data | `0x04a15db02fc7c991f2080e349cfbfb8f96f5fd61dd92c1cbe60ed7dbd4d49bfe` |
@@ -24,8 +25,8 @@ Total cost: ~10 STRK.
| Contract | Class hash |
|---|---|
-| beasts_nft | `0x350e97a3244fecad9f850d84843a0effc26a364c392c2e8c4379cb5de0193ea` |
-| beast_registry | `0x2afeefe9818b1c3fa839cef077cad5c6767bda41e6737e31ed44ed1a3fd6a97` |
+| beasts_nft | `0x20f43e08d7d6e8802809b12af5692bf596ef929079607eed48de71afceee8ff` |
+| beast_registry | `0x24809e1053dae99db897c32bb67fe323ac74d1e1fc47a26ddf7362a3f883041` |
| stored_art_provider | `0x2e3011cf968bbea8b72e75efdfe120318ccf61fe711d2f7f927114e2d8da56e` |
| beast_png_regular_data | `0x15d5742d2e7804531ac456b7ba82e9dc961ba154cbaaad631e2e7b4e887b68b` |
| beast_png_shiny_data | `0x3a1bfcae2737a12df248675d57c3a1a94eeceb5a696f14fa6f23fd99bf3d247` |
@@ -41,10 +42,15 @@ Both pointers are write-once and both are required; a stack missing either
accepts no community species at all.
```
-registry.set_nft_address(0x01dac778...) tx 0x06a0634be77503b1e32507406b046d320098f2f17a0142cc56dba07639e22fd5
-nft.set_registry_address(0x06d46c98...) tx 0x02af8798debaea3fbd5949bafe2b506e048a8fed8cde08101e63149fa4236ded
+registry.set_nft_address(0x017e2cb5...) tx 0x058ba4ac366347b3271fa061219d17c29efe9b4dbe98666a1906a9a87cf059c7
+nft.set_registry_address(0x0797a19c...) tx (same session)
```
+The four art data contracts and the `stored_art_provider` class are unchanged
+from the first deployment and were reused — `stored_art_provider` recompiled
+to a byte-identical class hash, which the network confirmed by rejecting the
+redeclare.
+
`dungeon_address` is **unset (zero)**, so genesis species 1–75 cannot be
minted yet. That is deliberate: it is also the state mainnet must launch in
until the `burn_and_mint` migration completes, or a dungeon could claim an
@@ -58,10 +64,14 @@ until the `burn_and_mint` migration completes, or a dungeon could claim an
| Genesis token ownership | `owner_of(0x7006400010000000000000000001)` → deployer |
| Genesis render (legacy art path) | `token_uri` → `"Warlock"`, new bestiary description |
| Permissionless registration | `register_beast_with_art('Gloomfang', Hunter, 3, ...)` → species **76** |
-| Factory art provider auto-deploy | `0x4b11caad7b2b29949f957c0854d2fa3a37fc40519bfee2eb844d8f319ac19b9`, `factory_provider: true` |
+| Factory art provider auto-deploy | `0x0bdc56ee6a9fef516d311188bc563c43f3d49e2af640b9d4c5b11fb134ad95d`, `factory_provider: true` |
| Provenance mint | `total_supply()` 75 → 76 |
| Per-species mint auth | `mint(..., 76, 1, 1, 10, 100, 0, 1)` from the registered minter succeeded |
| Community render | `"Agony Bane" Gloomfang`, Rank 1, 20,970-byte SVG |
+| Owner enumeration | `token_of_owner_by_index(owner, 0)` → `0x7006400010000000000000000001`, the genesis Warlock |
+| Artist = Genesis Beast | `get_artist(76)` returns the holder of `get_genesis_token_id(76)` |
+| Role follows the token | transferring the creator token moved `get_artist(76)` to the new holder |
+| Seller loses control | the previous holder's `set_minter` then reverted `Registry: not artist`, while the new holder's succeeded |
Decoded attributes of the community mint — every value routed correctly:
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b8aedb0
--- /dev/null
+++ b/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "beasts-monorepo",
+ "private": true,
+ "scripts": {
+ "test:sdk": "pnpm --filter @provable-games/beasts-sdk test",
+ "build:sdk": "pnpm --filter @provable-games/beasts-sdk build",
+ "dev:app": "pnpm --filter @provable-games/beasts-app dev",
+ "build:app": "pnpm --filter @provable-games/beasts-app build",
+ "typecheck": "pnpm -r typecheck",
+ "gen:tables": "node scripts/gen-tables.mjs"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..29e6fa3
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,5924 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .: {}
+
+ app:
+ dependencies:
+ '@cartridge/connector':
+ specifier: ^0.13.12
+ version: 0.13.16(@starknet-react/core@5.0.3(get-starknet-core@4.0.0)(react@18.3.1)(starknet@9.4.2(typescript@5.9.3)(zod@3.25.76))(typescript@5.9.3))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@cartridge/controller':
+ specifier: ^0.13.12
+ version: 0.13.16(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@provable-games/beasts-sdk':
+ specifier: workspace:*
+ version: link:../sdk
+ '@starknet-react/chains':
+ specifier: 5.0.3
+ version: 5.0.3
+ '@starknet-react/core':
+ specifier: ^5.0.1
+ version: 5.0.3(get-starknet-core@4.0.0)(react@18.3.1)(starknet@9.4.2(typescript@5.9.3)(zod@3.25.76))(typescript@5.9.3)
+ react:
+ specifier: ^18.2.0
+ version: 18.3.1
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.3.1(react@18.3.1)
+ starknet:
+ specifier: 9.4.2
+ version: 9.4.2(typescript@5.9.3)(zod@3.25.76)
+ devDependencies:
+ '@types/react':
+ specifier: ^18.2.0
+ version: 18.3.31
+ '@types/react-dom':
+ specifier: ^18.2.0
+ version: 18.3.7(@types/react@18.3.31)
+ '@vitejs/plugin-react':
+ specifier: ^4.3.0
+ version: 4.7.0(vite@5.4.21(@types/node@22.7.5))
+ playwright:
+ specifier: ^1.62.1
+ version: 1.62.1
+ typescript:
+ specifier: ^5.8.3
+ version: 5.9.3
+ vite:
+ specifier: ^5.4.0
+ version: 5.4.21(@types/node@22.7.5)
+
+ sdk:
+ devDependencies:
+ starknet:
+ specifier: 9.4.2
+ version: 9.4.2(typescript@5.9.3)(zod@3.25.76)
+ typescript:
+ specifier: ^5.8.3
+ version: 5.9.3
+ vitest:
+ specifier: ^3.0.0
+ version: 3.2.7(@types/node@22.7.5)
+
+packages:
+
+ '@adraffy/ens-normalize@1.11.1':
+ resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==}
+
+ '@babel/code-frame@7.29.7':
+ resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.7':
+ resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.7':
+ resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.8':
+ resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.29.7':
+ resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.29.7':
+ resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.29.7':
+ resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.29.7':
+ resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.29.7':
+ resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.29.7':
+ resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.29.7':
+ resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.29.7':
+ resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.7':
+ resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.8':
+ resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.29.7':
+ resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.29.7':
+ resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.29.7':
+ resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.8':
+ resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.8':
+ resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@base-org/account@2.4.0':
+ resolution: {integrity: sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==}
+
+ '@cartridge/connector@0.13.16':
+ resolution: {integrity: sha512-pXFRrWIqhb7GwNa4FJUr46Ke/v+68AyMKbeEwyoPgejtJQ2+WXSdJVE9E7AZ5v8EThLfCfHbQm7Ls0C9zZbe2g==}
+ peerDependencies:
+ '@starknet-react/core': ^5.0.1
+
+ '@cartridge/controller-wasm@0.10.1':
+ resolution: {integrity: sha512-NweHJ98lFrV103sT+ud0WOUT+j92bBdaTdT+cFRwPA+XmRB39UekMu35iWlFcBhlnxQF+GdX4G/IrQtfoXf9+A==}
+
+ '@cartridge/controller@0.13.16':
+ resolution: {integrity: sha512-fb43enXNabH8jj2pIqBVNuzZE9NBEXuecbw9VfJxK1ARwF/fM0ZDdCFGHe7n4eD+vA4/P8W9v4tPE1alUIZaIw==}
+ peerDependencies:
+ react: ^18.2.0 || ^19.0.0
+ react-dom: ^18.2.0 || ^19.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+
+ '@cartridge/penpal@6.2.4':
+ resolution: {integrity: sha512-tdpOnSJJBFMlgLZ1+z9Ho5e6cG5EgMAb1Cmmh1lGT2tmplogU/XPMjLE6CwvKAPDoe6a38iMnbH+ySTAWWIOKA==}
+
+ '@cbor-extract/cbor-extract-darwin-arm64@2.2.2':
+ resolution: {integrity: sha512-ZKZ/F8US7JR92J4DMct6cLW/Y66o2K576+zjlEN/MevH70bFIsB10wkZEQPLzl2oNh2SMGy55xpJ9JoBRl5DOA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@cbor-extract/cbor-extract-darwin-x64@2.2.2':
+ resolution: {integrity: sha512-32b1mgc+P61Js+KW9VZv/c+xRw5EfmOcPx990JbCBSkYJFY0l25VinvyyWfl+3KjibQmAcYwmyzKF9J4DyKP/Q==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@cbor-extract/cbor-extract-linux-arm64@2.2.2':
+ resolution: {integrity: sha512-wfqgzqCAy/Vn8i6WVIh7qZd0DdBFaWBjPdB6ma+Wihcjv0gHqD/mw3ouVv7kbbUNrab6dKEx/w3xQZEdeXIlzg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@cbor-extract/cbor-extract-linux-arm@2.2.2':
+ resolution: {integrity: sha512-tNg0za41TpQfkhWjptD+0gSD2fggMiDCSacuIeELyb2xZhr7PrhPe5h66Jc67B/5dmpIhI2QOUtv4SBsricyYQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@cbor-extract/cbor-extract-linux-x64@2.2.2':
+ resolution: {integrity: sha512-rpiLnVEsqtPJ+mXTdx1rfz4RtUGYIUg2rUAZgd1KjiC1SehYUSkJN7Yh+aVfSjvCGtVP0/bfkQkXpPXKbmSUaA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@cbor-extract/cbor-extract-win32-x64@2.2.2':
+ resolution: {integrity: sha512-dI+9P7cfWxkTQ+oE+7Aa6onEn92PHgfWXZivjNheCRmTBDBf2fx6RyTi0cmgpYLnD1KLZK9ZYrMxaPZ4oiXhGA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@coinbase/cdp-sdk@1.54.0':
+ resolution: {integrity: sha512-FfIJVEKAXgmr+dkXn/NBQO04/pps+oIgqEIdcmG67WZh+m07OsVnvSBEqEvbFO+VjSdaQAKu69EpO3NdHJd2Iw==}
+ peerDependencies:
+ '@x402/core': ^2.19.0
+ '@x402/evm': ^2.19.0
+ '@x402/extensions': ^2.19.0
+ '@x402/svm': ^2.19.0
+ peerDependenciesMeta:
+ '@x402/core':
+ optional: true
+ '@x402/evm':
+ optional: true
+ '@x402/extensions':
+ optional: true
+ '@x402/svm':
+ optional: true
+
+ '@esbuild/aix-ppc64@0.21.5':
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.21.5':
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.21.5':
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.21.5':
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.21.5':
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.21.5':
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.21.5':
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.21.5':
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.21.5':
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.21.5':
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.21.5':
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.21.5':
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.21.5':
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.21.5':
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.21.5':
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.21.5':
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-x64@0.21.5':
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-x64@0.21.5':
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.21.5':
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.21.5':
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.21.5':
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.21.5':
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
+ '@hpke/chacha20poly1305@1.8.0':
+ resolution: {integrity: sha512-FcBfAQ+Y99vMNJP2yrZ9wpL8V0GOwp1+zMyzvc6alasrBygfFjFm1yeUtyADJCu/27C3Lm5mJzx6u7pwg+cX5w==}
+ engines: {node: '>=16.0.0'}
+
+ '@hpke/common@1.10.1':
+ resolution: {integrity: sha512-moJwhmtLtuxiUzzNp1jpfBfx8yefKoO9D/RCR9dmwrnc7qjJqId1rEtQz+lSlU5cabX8daToMSx/7HayXOiaFw==}
+ engines: {node: '>=16.0.0'}
+
+ '@hpke/core@1.9.0':
+ resolution: {integrity: sha512-pFxWl1nNJeQCSUFs7+GAblHvXBCjn9EPN65vdKlYQil2aURaRxfGMO6vBKGqm1YHTKwiAxJQNEI70PbSowMP9Q==}
+ engines: {node: '>=16.0.0'}
+
+ '@hpke/dhkem-x25519@1.8.0':
+ resolution: {integrity: sha512-S1MWWkAfu+TFxySgv5+2P3O4Mx/jk7BsoplzQaA1s3sfUJVJ2UsZsSzSsMc+FXJumLXncoJFlO6mK6mDGspfmA==}
+ engines: {node: '>=16.0.0'}
+
+ '@hpke/dhkem-x448@1.8.0':
+ resolution: {integrity: sha512-mFfnZfgp4OKkUIS/FKikfUgdnDKRy25ytCKBQiV+N+HbYy3I4v4ZCPBQ69QL+TYmKmCZJeUEnYeS5K+OBRP+Eg==}
+ engines: {node: '>=16.0.0'}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@lit-labs/ssr-dom-shim@1.6.0':
+ resolution: {integrity: sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==}
+
+ '@lit/react@1.0.8':
+ resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==}
+ peerDependencies:
+ '@types/react': 17 || 18 || 19
+
+ '@lit/reactive-element@2.1.2':
+ resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==}
+
+ '@module-federation/error-codes@0.12.0':
+ resolution: {integrity: sha512-DEXQjopcBuGzp/NA9OVtASO0uZ6grVK5TIe0PjrbDRyZDxVaYQXKrISxBLOE+3nSIELE98tYpfxptm8WC9A8zA==}
+
+ '@module-federation/runtime-core@0.12.0':
+ resolution: {integrity: sha512-373zBM54196KHURs/O8lry9trCAM3PPidvsF4YdrtahNc8YaQynml0mE3zdZeBnqP6H0/4OpPqMMjACI80Ht8w==}
+
+ '@module-federation/runtime@0.12.0':
+ resolution: {integrity: sha512-Cz9/7+gSvrdencwA8LXUMKnZdu0/flyN+yk6t3pkxfhvPJi3W65ZcalAKyOgyk2x8rEYrRSyEXu+/2DIFgrzmA==}
+
+ '@module-federation/sdk@0.12.0':
+ resolution: {integrity: sha512-vh3GcG90fxjbkMghK7iSWcMayi/y8U5DxI6mhEFuz11St3y1UgQO2TZYephL8nISFBld7DdiqAkimx+6Hb3hjQ==}
+
+ '@msgpack/msgpack@3.1.3':
+ resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==}
+ engines: {node: '>= 18'}
+
+ '@noble/ciphers@1.3.0':
+ resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/curves@1.2.0':
+ resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==}
+
+ '@noble/curves@1.7.0':
+ resolution: {integrity: sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/curves@1.8.0':
+ resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/curves@1.9.0':
+ resolution: {integrity: sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/curves@1.9.1':
+ resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/curves@1.9.7':
+ resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/hashes@1.3.2':
+ resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==}
+ engines: {node: '>= 16'}
+
+ '@noble/hashes@1.4.0':
+ resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
+ engines: {node: '>= 16'}
+
+ '@noble/hashes@1.6.0':
+ resolution: {integrity: sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/hashes@1.6.1':
+ resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/hashes@1.7.0':
+ resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@noble/hashes@1.8.0':
+ resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
+ engines: {node: ^14.21.3 || >=16}
+
+ '@peculiar/asn1-cms@2.8.0':
+ resolution: {integrity: sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA==}
+
+ '@peculiar/asn1-csr@2.8.0':
+ resolution: {integrity: sha512-akbF8+uvleHs8sejNPQxwmVFuInAg6FMNHOwMILXfP518YfFJwdR3jr6oNUPOaEJfuEhn/vkNOCIT6ASUd4mbg==}
+
+ '@peculiar/asn1-ecc@2.8.0':
+ resolution: {integrity: sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ==}
+
+ '@peculiar/asn1-pfx@2.8.0':
+ resolution: {integrity: sha512-5yof1ytoB++RQtaFbqSUJ8pxDJtZT6vbVqZ8XoJ61ph7UjNVvfFwAilnCodqkNsAodpy13gDhoxZXw00pghnyg==}
+
+ '@peculiar/asn1-pkcs8@2.8.0':
+ resolution: {integrity: sha512-qAKXtLpBEw9LqhKpjw3ajZSXlBur+ipW+y2ivVBQAG6F6qRx94yO+1ZR4mvw+YaCfKSaOzLeYEzsPaBp4SJELA==}
+
+ '@peculiar/asn1-pkcs9@2.8.0':
+ resolution: {integrity: sha512-b5nDWCnkV60+cQ141D6sVVwK9nz64R5n3zSVnklGd+ECdkW2Ol3U1a6yYFlalpSOaD557yuJB64A+q42jG7lUQ==}
+
+ '@peculiar/asn1-rsa@2.8.0':
+ resolution: {integrity: sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg==}
+
+ '@peculiar/asn1-schema@2.8.0':
+ resolution: {integrity: sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==}
+
+ '@peculiar/asn1-x509-attr@2.8.0':
+ resolution: {integrity: sha512-tHjkfS/qhMnmrlB2J9NhflQlQ7In3khO3CfmVrriOlpTeErY9ZIKOso1hQ5JQiyrJ7ShvqVPk7E5fQmbclkSKA==}
+
+ '@peculiar/asn1-x509@2.8.0':
+ resolution: {integrity: sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg==}
+
+ '@peculiar/utils@2.0.3':
+ resolution: {integrity: sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==}
+
+ '@peculiar/x509@1.12.3':
+ resolution: {integrity: sha512-+Mzq+W7cNEKfkNZzyLl6A6ffqc3r21HGZUezgfKxpZrkORfOqgRXnS80Zu0IV6a9Ue9QBJeKD7kN0iWfc3bhRQ==}
+
+ '@phosphor-icons/webcomponents@2.1.5':
+ resolution: {integrity: sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q==}
+
+ '@reown/appkit-common@1.8.19':
+ resolution: {integrity: sha512-z5wDrYjUGY7YbM4b14NHVo54WKZ5++PQtGkcsXhiOP39yAVijubBQD8BfHs/Pu2fSFqnqLIFoCVvIEfNWWccRw==}
+
+ '@reown/appkit-controllers@1.8.19':
+ resolution: {integrity: sha512-JFNT8CfAVit9FJXh596Ye4U8A/oIapW+Y0KQqjB59DXyTCDZbxZDB32rULBQrSkZ6PufTEa239Dil4kABCQKtg==}
+
+ '@reown/appkit-pay@1.8.19':
+ resolution: {integrity: sha512-HO/tQT0TbTQO3eONxNNPJAOZAOzUiHvjM0Mty1rFFeRBH68auiqQxQi2YFNMs014gNkRN+cb84VYau7+MCC0fQ==}
+
+ '@reown/appkit-polyfills@1.8.19':
+ resolution: {integrity: sha512-PSoetRSuZg7f2YFPzdfs4BayQl51zcGqYr7frwOe6td0XEsspLrrVFn/zk5QFbFHZVsMdfRZ+TTunt84ozRdnQ==}
+
+ '@reown/appkit-scaffold-ui@1.8.19':
+ resolution: {integrity: sha512-Ak767x0VzeDIXb0wbzkl19kx6udw7vkb1EU0SAweG3iKc9BunW87Rfcd48/YimzMZycJaYmlbtfmqQQDYs6Few==}
+
+ '@reown/appkit-ui@1.8.19':
+ resolution: {integrity: sha512-fCAwW8yyyC3JcgKLBPvCtYuDGC4H8anO7u4LTaAXGEzdcU5H+IrCgNFSPNK7NuTSmgXm1TnoYxPxRFKNiNwFdA==}
+
+ '@reown/appkit-utils@1.8.19':
+ resolution: {integrity: sha512-VQPgUMTFqoh4UD3EDZSw9wyMkyZsmIVmu8CdQ2FUxIuqYW4fLd0VIpkDeO64MMhSv8b0X8Vd6m4+eGcqSwlUAg==}
+ peerDependencies:
+ valtio: 2.1.7
+
+ '@reown/appkit-wallet@1.8.19':
+ resolution: {integrity: sha512-NVdIKceUhkXYtsG32925ctmVn0QJFNyDlr+mWheMLCEZ/IUPn+6aA53vTVaSUquhyeFxUXtrCOh3ln6v1tup5w==}
+
+ '@reown/appkit@1.8.19':
+ resolution: {integrity: sha512-wB+xatkRbOy0AY1cZxxtcKzzPk3l3CTFulDbaISLVmZI6ZnQrOFuLnYc285zGsC6DB4d6bmwYUh89zcMLa4PvQ==}
+
+ '@rolldown/pluginutils@1.0.0-beta.27':
+ resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+
+ '@rollup/rollup-android-arm-eabi@4.62.3':
+ resolution: {integrity: sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.62.3':
+ resolution: {integrity: sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.62.3':
+ resolution: {integrity: sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.62.3':
+ resolution: {integrity: sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.62.3':
+ resolution: {integrity: sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.62.3':
+ resolution: {integrity: sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.62.3':
+ resolution: {integrity: sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.62.3':
+ resolution: {integrity: sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.62.3':
+ resolution: {integrity: sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.62.3':
+ resolution: {integrity: sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loong64-gnu@4.62.3':
+ resolution: {integrity: sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loong64-musl@4.62.3':
+ resolution: {integrity: sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.62.3':
+ resolution: {integrity: sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-musl@4.62.3':
+ resolution: {integrity: sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.62.3':
+ resolution: {integrity: sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.62.3':
+ resolution: {integrity: sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.62.3':
+ resolution: {integrity: sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.62.3':
+ resolution: {integrity: sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.62.3':
+ resolution: {integrity: sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-openbsd-x64@4.62.3':
+ resolution: {integrity: sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.62.3':
+ resolution: {integrity: sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.62.3':
+ resolution: {integrity: sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.62.3':
+ resolution: {integrity: sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.62.3':
+ resolution: {integrity: sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.62.3':
+ resolution: {integrity: sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==}
+ cpu: [x64]
+ os: [win32]
+
+ '@safe-global/safe-apps-provider@0.18.6':
+ resolution: {integrity: sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==}
+
+ '@safe-global/safe-apps-sdk@9.1.0':
+ resolution: {integrity: sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==}
+
+ '@safe-global/safe-gateway-typescript-sdk@3.23.1':
+ resolution: {integrity: sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==}
+ engines: {node: '>=16'}
+ deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
+
+ '@scure/base@1.2.6':
+ resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==}
+
+ '@scure/bip32@1.7.0':
+ resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==}
+
+ '@scure/bip39@1.6.0':
+ resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==}
+
+ '@scure/starknet@1.1.0':
+ resolution: {integrity: sha512-83g3M6Ix2qRsPN4wqLDqiRZ2GBNbjVWfboJE/9UjfG+MHr6oDSu/CWgy8hsBSJejr09DkkL+l0Ze4KVrlCIdtQ==}
+
+ '@solana-program/system@0.10.0':
+ resolution: {integrity: sha512-Go+LOEZmqmNlfr+Gjy5ZWAdY5HbYzk2RBewD9QinEU/bBSzpFfzqDRT55JjFRBGJUvMgf3C2vfXEGT4i8DSI4g==}
+ peerDependencies:
+ '@solana/kit': ^5.0
+
+ '@solana-program/token@0.9.0':
+ resolution: {integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==}
+ peerDependencies:
+ '@solana/kit': ^5.0
+
+ '@solana/accounts@5.5.1':
+ resolution: {integrity: sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/addresses@5.5.1':
+ resolution: {integrity: sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/assertions@5.5.1':
+ resolution: {integrity: sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/codecs-core@5.5.1':
+ resolution: {integrity: sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/codecs-data-structures@5.5.1':
+ resolution: {integrity: sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/codecs-numbers@5.5.1':
+ resolution: {integrity: sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/codecs-strings@5.5.1':
+ resolution: {integrity: sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ fastestsmallesttextencoderdecoder: ^1.0.22
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ fastestsmallesttextencoderdecoder:
+ optional: true
+ typescript:
+ optional: true
+
+ '@solana/codecs@5.5.1':
+ resolution: {integrity: sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/errors@5.5.1':
+ resolution: {integrity: sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==}
+ engines: {node: '>=20.18.0'}
+ hasBin: true
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/fast-stable-stringify@5.5.1':
+ resolution: {integrity: sha512-Ni7s2FN33zTzhTFgRjEbOVFO+UAmK8qi3Iu0/GRFYK4jN696OjKHnboSQH/EacQ+yGqS54bfxf409wU5dsLLCw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/functional@5.5.1':
+ resolution: {integrity: sha512-tTHoJcEQq3gQx5qsdsDJ0LEJeFzwNpXD80xApW9o/PPoCNimI3SALkZl+zNW8VnxRrV3l3yYvfHWBKe/X3WG3w==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/instruction-plans@5.5.1':
+ resolution: {integrity: sha512-7z3CB7YMcFKuVvgcnNY8bY6IsZ8LG61Iytbz7HpNVGX2u1RthOs1tRW8luTzSG1MPL0Ox7afyAVMYeFqSPHnaQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/instructions@5.5.1':
+ resolution: {integrity: sha512-h0G1CG6S+gUUSt0eo6rOtsaXRBwCq1+Js2a+Ps9Bzk9q7YHNFA75/X0NWugWLgC92waRp66hrjMTiYYnLBoWOQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/keys@5.5.1':
+ resolution: {integrity: sha512-KRD61cL7CRL+b4r/eB9dEoVxIf/2EJ1Pm1DmRYhtSUAJD2dJ5Xw8QFuehobOGm9URqQ7gaQl+Fkc1qvDlsWqKg==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/kit@5.5.1':
+ resolution: {integrity: sha512-irKUGiV2yRoyf+4eGQ/ZeCRxa43yjFEL1DUI5B0DkcfZw3cr0VJtVJnrG8OtVF01vT0OUfYOcUn6zJW5TROHvQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/nominal-types@5.5.1':
+ resolution: {integrity: sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/offchain-messages@5.5.1':
+ resolution: {integrity: sha512-g+xHH95prTU+KujtbOzj8wn+C7ZNoiLhf3hj6nYq3MTyxOXtBEysguc97jJveUZG0K97aIKG6xVUlMutg5yxhw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/options@5.5.1':
+ resolution: {integrity: sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/plugin-core@5.5.1':
+ resolution: {integrity: sha512-VUZl30lDQFJeiSyNfzU1EjYt2QZvoBFKEwjn1lilUJw7KgqD5z7mbV7diJhT+dLFs36i0OsjXvq5kSygn8YJ3A==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/programs@5.5.1':
+ resolution: {integrity: sha512-7U9kn0Jsx1NuBLn5HRTFYh78MV4XN145Yc3WP/q5BlqAVNlMoU9coG5IUTJIG847TUqC1lRto3Dnpwm6T4YRpA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/promises@5.5.1':
+ resolution: {integrity: sha512-T9lfuUYkGykJmppEcssNiCf6yiYQxJkhiLPP+pyAc2z84/7r3UVIb2tNJk4A9sucS66pzJnVHZKcZVGUUp6wzA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-api@5.5.1':
+ resolution: {integrity: sha512-XWOQQPhKl06Vj0xi3RYHAc6oEQd8B82okYJ04K7N0Vvy3J4PN2cxeK7klwkjgavdcN9EVkYCChm2ADAtnztKnA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-parsed-types@5.5.1':
+ resolution: {integrity: sha512-HEi3G2nZqGEsa3vX6U0FrXLaqnUCg4SKIUrOe8CezD+cSFbRTOn3rCLrUmJrhVyXlHoQVaRO9mmeovk31jWxJg==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-spec-types@5.5.1':
+ resolution: {integrity: sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-spec@5.5.1':
+ resolution: {integrity: sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-subscriptions-api@5.5.1':
+ resolution: {integrity: sha512-5Oi7k+GdeS8xR2ly1iuSFkAv6CZqwG0Z6b1QZKbEgxadE1XGSDrhM2cn59l+bqCozUWCqh4c/A2znU/qQjROlw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-subscriptions-channel-websocket@5.5.1':
+ resolution: {integrity: sha512-7tGfBBrYY8TrngOyxSHoCU5shy86iA9SRMRrPSyBhEaZRAk6dnbdpmUTez7gtdVo0BCvh9nzQtUycKWSS7PnFQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-subscriptions-spec@5.5.1':
+ resolution: {integrity: sha512-iq+rGq5fMKP3/mKHPNB6MC8IbVW41KGZg83Us/+LE3AWOTWV1WT20KT2iH1F1ik9roi42COv/TpoZZvhKj45XQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-subscriptions@5.5.1':
+ resolution: {integrity: sha512-CTMy5bt/6mDh4tc6vUJms9EcuZj3xvK0/xq8IQ90rhkpYvate91RjBP+egvjgSayUg9yucU9vNuUpEjz4spM7w==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-transformers@5.5.1':
+ resolution: {integrity: sha512-OsWqLCQdcrRJKvHiMmwFhp9noNZ4FARuMkHT5us3ustDLXaxOjF0gfqZLnMkulSLcKt7TGXqMhBV+HCo7z5M8Q==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-transport-http@5.5.1':
+ resolution: {integrity: sha512-yv8GoVSHqEV0kUJEIhkdOVkR2SvJ6yoWC51cJn2rSV7plr6huLGe0JgujCmB7uZhhaLbcbP3zxXxu9sOjsi7Fg==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc-types@5.5.1':
+ resolution: {integrity: sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/rpc@5.5.1':
+ resolution: {integrity: sha512-ku8zTUMrkCWci66PRIBC+1mXepEnZH/q1f3ck0kJZ95a06bOTl5KU7HeXWtskkyefzARJ5zvCs54AD5nxjQJ+A==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/signers@5.5.1':
+ resolution: {integrity: sha512-FY0IVaBT2kCAze55vEieR6hag4coqcuJ31Aw3hqRH7mv6sV8oqwuJmUrx+uFwOp1gwd5OEAzlv6N4hOOple4sQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/subscribable@5.5.1':
+ resolution: {integrity: sha512-9K0PsynFq0CsmK1CDi5Y2vUIJpCqkgSS5yfDN0eKPgHqEptLEaia09Kaxc90cSZDZU5mKY/zv1NBmB6Aro9zQQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/sysvars@5.5.1':
+ resolution: {integrity: sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/transaction-confirmation@5.5.1':
+ resolution: {integrity: sha512-j4mKlYPHEyu+OD7MBt3jRoX4ScFgkhZC6H65on4Fux6LMScgivPJlwnKoZMnsgxFgWds0pl+BYzSiALDsXlYtw==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/transaction-messages@5.5.1':
+ resolution: {integrity: sha512-aXyhMCEaAp3M/4fP0akwBBQkFPr4pfwoC5CLDq999r/FUwDax2RE/h4Ic7h2Xk+JdcUwsb+rLq85Y52hq84XvQ==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@solana/transactions@5.5.1':
+ resolution: {integrity: sha512-8hHtDxtqalZ157pnx6p8k10D7J/KY/biLzfgh9R09VNLLY3Fqi7kJvJCr7M2ik3oRll56pxhraAGCC9yIT6eOA==}
+ engines: {node: '>=20.18.0'}
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@starknet-io/get-starknet-core@5.0.0':
+ resolution: {integrity: sha512-FVKYeNGHWG978482ZdCf7VQMoMn0xxHS0mWYbNB6zwkpo2yForHJwN4/EIHQkd2xp2mfAD1VcIHSZ4SLWGV1zw==}
+
+ '@starknet-io/get-starknet-discovery@5.0.0':
+ resolution: {integrity: sha512-b40ZfhbisiEonxWLe/naOraZvNc1hfhy4TEs0TP/cYppfECDhBKncvvFTGu++/rm+xV3SjmSzwNQGQmIn5DMLQ==}
+
+ '@starknet-io/get-starknet-virtual-wallet@5.0.0':
+ resolution: {integrity: sha512-ne9Svr0tHj7a5OJOvC82ewth/GJTa78Gal/iiiRzQmvIDpZcu+nzrPAi350RKEtErxjG5rZSPv2DLz7VBClN0Q==}
+
+ '@starknet-io/get-starknet-wallet-standard@5.0.0':
+ resolution: {integrity: sha512-isDNGDlp16W24HE4IuweYXLDRZN0JbsDnazAieeKXE87Mn+jqhsjgTsMxcwWTjX7v906Bjz39FiDjGUddnr36g==}
+
+ '@starknet-io/get-starknet-wallets@5.0.0':
+ resolution: {integrity: sha512-fuywFgoal4Al2KdFQCNTYgioK0ubu3cP+mM6OxE8ti78Nmd9ySlh78LwdKNXIp2Alq4kaQ5XMf6HMgkStCWhkw==}
+
+ '@starknet-io/types-js@0.10.0':
+ resolution: {integrity: sha512-7ALSydz6pq3YIOpq5a7OkkxqwJciMc9Nlph0OGjhcC3xX0xH30XgizmziLyYVN10oO9+BJk8M9KbJjpzdbtRSw==}
+
+ '@starknet-io/types-js@0.7.10':
+ resolution: {integrity: sha512-1VtCqX4AHWJlRRSYGSn+4X1mqolI1Tdq62IwzoU2vUuEE72S1OlEeGhpvd6XsdqXcfHmVzYfj8k1XtKBQqwo9w==}
+
+ '@starknet-io/types-js@0.8.4':
+ resolution: {integrity: sha512-0RZ3TZHcLsUTQaq1JhDSCM8chnzO4/XNsSCozwDET64JK5bjFDIf2ZUkta+tl5Nlbf4usoU7uZiDI/Q57kt2SQ==}
+
+ '@starknet-io/types-js@0.9.1':
+ resolution: {integrity: sha512-ngLjOFuWOI4EFij8V+nl5tgHVACr6jqgLNUQbgD+AgnTcAN33SemBPXDIsovwK1Mz1U04Cz3qjDOnTq7067ZQw==}
+
+ '@starknet-io/types-js@0.9.2':
+ resolution: {integrity: sha512-vWOc0FVSn+RmabozIEWcEny1I73nDGTvOrLYJsR1x7LGA3AZmqt4i/aW69o/3i2NN5CVP8Ok6G1ayRQJKye3Wg==}
+
+ '@starknet-react/chains@5.0.3':
+ resolution: {integrity: sha512-TxP391OTWgaqujT9Hu1Siljye54IHjEXrgkUuhMfxzf9sCu5q42ZzZgu9hLm0NcJgg9Fx2t75J0WB6eYmQ26fw==}
+
+ '@starknet-react/core@5.0.3':
+ resolution: {integrity: sha512-BxtcYL+SPqqDo1cpzfNYcYmSY4Ifjz1O5vq5vDdjx2iHEvHYzxBMjnyacJ+JsdRlQiuLNRGInooC/yzFkMrHAQ==}
+ peerDependencies:
+ get-starknet-core: ^4.0.0
+ react: ^18.0
+ starknet: ^8.1.2
+
+ '@tanstack/query-core@5.101.4':
+ resolution: {integrity: sha512-gNwcvOJcRbLWPOLG/2OBm+zM+Yv+MKsXKEOWC57USuZDEsI71hEErQsiEGx5wX9rzWWkfwM0fVSPoiIFSsxfiw==}
+
+ '@tanstack/react-query@5.101.4':
+ resolution: {integrity: sha512-yRg2pfOCxIs4ZJW3XYYHU/WgtD04FHSnfHlpRT7h7pR77hwkdRG4wxbKe4aq6P0RvXUTBSQpQeadS1SUYUe+KA==}
+ peerDependencies:
+ react: ^18 || ^19
+
+ '@turnkey/api-key-stamper@0.6.5':
+ resolution: {integrity: sha512-dSINHLIzYVw+ZNLwjM1wnEYFkYHPjQDSi43opCUhvow/ws6Fsn6gWkYpzbH+6Ej3rvSJTuaTwsld+dsTG/3HnA==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/crypto@2.8.14':
+ resolution: {integrity: sha512-UZU+DEwhSUyyMHC9VZbp5av8NY/IJsfJ+g1E4dndQjMSAJd5NPKGS7sItlBy1ifN6wBb9JP5AcvmcfCdCfj9bw==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/encoding@0.6.0':
+ resolution: {integrity: sha512-IC8qXvy36+iGAeiaVIuJvB35uU2Ld/RAWI/DRTKS+ttBej0GXhOn48Ouu5mlca4jt8ZEuwXmDVv74A8uBQclsA==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/http@3.18.1':
+ resolution: {integrity: sha512-KXhDAtohx3PPRigdU0qjdgSTuomD0xl3mONly5hn8/jgrp0Gs7BKXv0OGiw/3Sj02IPmlza3SRWBKGtWyGwNmg==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/iframe-stamper@2.11.0':
+ resolution: {integrity: sha512-Iyf4W4S4Hx/RVsXl07PkRTh3g5Ca+vpN6SdUbRy8lt9IQZAJel/vxAk9XMyB7utX9TJx+icSjNYHvC0XGqJ47A==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/indexed-db-stamper@1.2.6':
+ resolution: {integrity: sha512-RSlCpH96e46PYgc029/TK3nE/HOW4QgKo9bXIYjoUR8J7+xkq+0Z0wjHrp27Yn3PbW8743hEppqK9jxsYc8ptA==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/sdk-browser@5.16.1':
+ resolution: {integrity: sha512-AXBUJVW83nZKnSVNUH235dbsu4S+a4F0Swo25Fm/gHWKPVh4nvpT/Pr2cr6PVh3UR15p787AVUkxO9ZgtNclPw==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/sdk-types@0.14.0':
+ resolution: {integrity: sha512-FLN4p3Jc3rBMvM17tgFrO4VpqkQN0RgWtLknqcqpLuNgTJ7oqgvzm42YIrzvBlW6DPsnFjVZMzc4yCfaRN7Lmg==}
+ engines: {node: '>=18.0.0'}
+
+ '@turnkey/wallet-stamper@1.1.16':
+ resolution: {integrity: sha512-IdgoIRQr5RoiHAPnVag2QyaYg6cmmkZQs1rOig57/tQ/fXdPsC1+2660RisIAvv69ZFrArG8Z8wHaGSQMkStlw==}
+
+ '@turnkey/webauthn-stamper@0.6.0':
+ resolution: {integrity: sha512-jdN17QEnn7RBykEOhtKIialWmDjnDAH8DzbyITwn8jsKcwT1TBNYge89hTUTjbdsDLBAqQw8cHujPdy0RaAqvw==}
+ engines: {node: '>=18.0.0'}
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/chai@5.2.3':
+ resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
+
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
+ '@types/estree@1.0.9':
+ resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
+
+ '@types/node@22.7.5':
+ resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==}
+
+ '@types/prop-types@15.7.15':
+ resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
+
+ '@types/react-dom@18.3.7':
+ resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==}
+ peerDependencies:
+ '@types/react': ^18.0.0
+
+ '@types/react@18.3.31':
+ resolution: {integrity: sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==}
+
+ '@types/trusted-types@2.0.7':
+ resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
+
+ '@vitejs/plugin-react@4.7.0':
+ resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+
+ '@vitest/expect@3.2.7':
+ resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==}
+
+ '@vitest/mocker@3.2.7':
+ resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@3.2.7':
+ resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==}
+
+ '@vitest/runner@3.2.7':
+ resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==}
+
+ '@vitest/snapshot@3.2.7':
+ resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==}
+
+ '@vitest/spy@3.2.7':
+ resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==}
+
+ '@vitest/utils@3.2.7':
+ resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==}
+
+ '@wallet-standard/base@1.1.1':
+ resolution: {integrity: sha512-gggIHTtxicF9XFMQ12DkfS6NAG92Ak795JeSA7f2whAQ6Y3AkMWWuCMxSZXG2NIPN42kEaZSNVjqMsJRaJRxMQ==}
+ engines: {node: '>=22'}
+
+ '@wallet-standard/features@1.1.1':
+ resolution: {integrity: sha512-aCWYmVeSCGViyEU5k7GMoW8zxE4Gs+C1s1Pp2XLesvSNlnZ4PMES9HUnTB3hl0b3RVj7C61yze3IWyrncqg4MA==}
+ engines: {node: '>=22'}
+
+ '@wallet-standard/wallet@1.1.0':
+ resolution: {integrity: sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==}
+ engines: {node: '>=16'}
+
+ '@wallet-standard/wallet@1.1.1':
+ resolution: {integrity: sha512-8WiRPaKk/wNNRZhB2eVhpR/JW7/aqTCMoZhgVUCujuzDmxxmGvsosMxdCG4NAdYkoyozAHCX8/xLtlWUn5mNdQ==}
+ engines: {node: '>=22'}
+
+ '@walletconnect/core@2.23.10':
+ resolution: {integrity: sha512-Qq2btHEoCgruvkZCWLSrVsvg/dYbM9Z045qeClwhJR4meL32jbIRT0mKWjf0HkRc2LA82MsnszVnfuZl3yWl5A==}
+ engines: {node: '>=18.20.8'}
+
+ '@walletconnect/core@2.23.7':
+ resolution: {integrity: sha512-yTyymn9mFaDZkUfLfZ3E9VyaSDPeHAXlrPxQRmNx2zFsEt/25GmTU2A848aomimLxZnAG2jNLhxbJ8I0gyNV+w==}
+ engines: {node: '>=18.20.8'}
+
+ '@walletconnect/environment@1.0.1':
+ resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==}
+
+ '@walletconnect/ethereum-provider@2.23.10':
+ resolution: {integrity: sha512-OpmTS2s+zrqK7cr8yfGu62tCv6Dsoe/TI1SFYQd2tKyAaBYjrKVzZPfqbRYesgbtNKcCn8KK5Y6PrKIK52U7RQ==}
+
+ '@walletconnect/events@1.0.1':
+ resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==}
+
+ '@walletconnect/heartbeat@1.2.2':
+ resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==}
+
+ '@walletconnect/jsonrpc-http-connection@1.0.8':
+ resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==}
+
+ '@walletconnect/jsonrpc-provider@1.0.14':
+ resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==}
+
+ '@walletconnect/jsonrpc-types@1.0.4':
+ resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==}
+
+ '@walletconnect/jsonrpc-utils@1.0.8':
+ resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==}
+
+ '@walletconnect/jsonrpc-ws-connection@1.0.16':
+ resolution: {integrity: sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==}
+
+ '@walletconnect/keyvaluestorage@1.1.1':
+ resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==}
+ peerDependencies:
+ '@react-native-async-storage/async-storage': 1.x
+ peerDependenciesMeta:
+ '@react-native-async-storage/async-storage':
+ optional: true
+
+ '@walletconnect/logger@3.0.2':
+ resolution: {integrity: sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA==}
+
+ '@walletconnect/relay-api@1.0.11':
+ resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==}
+
+ '@walletconnect/relay-auth@1.1.0':
+ resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==}
+
+ '@walletconnect/safe-json@1.0.2':
+ resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==}
+
+ '@walletconnect/sign-client@2.23.10':
+ resolution: {integrity: sha512-vO7DGRRmKo+rykmjVyQR1aM4I2nbk9kJ6olbxgjFRR6Jdhy+Kz+zgN7Ce5xVhPfWYVu4bV/XhOQxhvnQw7S5ng==}
+
+ '@walletconnect/sign-client@2.23.7':
+ resolution: {integrity: sha512-SX61lzb1bTl/LijlcHQttnoHPBzzoY5mW9ArR6qhFtDNDTS7yr2rcH7rCngxHlYeb4rAYcWLHgbiGSrdKxl/mg==}
+
+ '@walletconnect/time@1.0.2':
+ resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==}
+
+ '@walletconnect/types@2.23.10':
+ resolution: {integrity: sha512-XP8d41979anTrc1OJF3ISF+g81cvp1wim+ObdNnbcaT/jhwLwv+0T7rRe9VwRv+h8EaRgLyeb5YGy7oJ49vxVg==}
+
+ '@walletconnect/types@2.23.7':
+ resolution: {integrity: sha512-6PAKK+iR2IntmlkCFLMAHjYeIaerCJJYRDmdRimhon0u+aNmQT+HyGM6zxDAth0rdpBD7qEvKP5IXZTE7KFUhw==}
+
+ '@walletconnect/universal-provider@2.23.10':
+ resolution: {integrity: sha512-wkLcoaPA8R1Cfx5dcYmS7oMalYd0aEO6+8PNs9gZ5Zwe+zwU+6HOImL8HcCHngeMcdjLqW5aKN3Dy6NbueA3fg==}
+
+ '@walletconnect/universal-provider@2.23.7':
+ resolution: {integrity: sha512-6UicU/Mhr/1bh7MNoajypz7BhigORbHpP1LFTf8FYLQGDqzmqHMqmMH2GDAImtaY2sFTi2jBvc22tLl8VMze/A==}
+
+ '@walletconnect/utils@2.23.10':
+ resolution: {integrity: sha512-b1c9FRF2g7vNnz66oLW5WZD2VCMrbu9xhpmwJJwqGarBiGW7cY8NbUtS9/w2/qc0vsBVKJ/bzDn4TGjpELU6aQ==}
+
+ '@walletconnect/utils@2.23.7':
+ resolution: {integrity: sha512-3p38gNrkVcIiQixVrlsWSa66Gjs5PqHOug2TxDgYUVBW5NcKjwQA08GkC6CKBQUfr5iaCtbfy6uZJW1LKSIvWQ==}
+
+ '@walletconnect/window-getters@1.0.1':
+ resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==}
+
+ '@walletconnect/window-metadata@1.0.1':
+ resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==}
+
+ abi-wan-kanabi@2.2.4:
+ resolution: {integrity: sha512-0aA81FScmJCPX+8UvkXLki3X1+yPQuWxEkqXBVKltgPAK79J+NB+Lp5DouMXa7L6f+zcRlIA/6XO7BN/q9fnvg==}
+ hasBin: true
+
+ abitype@1.0.6:
+ resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==}
+ peerDependencies:
+ typescript: '>=5.0.4'
+ zod: ^3 >=3.22.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+
+ abitype@1.2.3:
+ resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==}
+ peerDependencies:
+ typescript: '>=5.0.4'
+ zod: ^3.22.0 || ^4.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+
+ abitype@1.3.0:
+ resolution: {integrity: sha512-fk6Te+bojIFrMvMZrnOO+SxCB+RUksTGOzq/60ZRvs1L+BVzvi2bqt9L3W/17ZLdZsyM1FuYf65P5nlmoiH1Bg==}
+ peerDependencies:
+ typescript: '>=5.0.4'
+ zod: ^3.22.0 || ^4.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+
+ aes-js@4.0.0-beta.5:
+ resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ ansicolors@0.3.2:
+ resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ asn1js@3.0.10:
+ resolution: {integrity: sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==}
+ engines: {node: '>=12.0.0'}
+
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
+ async-mutex@0.5.0:
+ resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ atomic-sleep@1.0.0:
+ resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
+ engines: {node: '>=8.0.0'}
+
+ axios-retry@4.5.0:
+ resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==}
+ peerDependencies:
+ axios: 0.x || 1.x
+
+ axios@1.16.0:
+ resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==}
+
+ base-x@5.0.1:
+ resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==}
+
+ base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+ baseline-browser-mapping@2.11.9:
+ resolution: {integrity: sha512-cp447VUsGS07+n1Dqf7YSQ8maeJrjEhaDxTm1ZefbqDtypHBC5GzGMQbklR6IPR13Y8OAJRHZWEMtZipJLCttg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ big.js@6.2.2:
+ resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==}
+
+ blakejs@1.2.1:
+ resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==}
+
+ borsh@2.0.0:
+ resolution: {integrity: sha512-kc9+BgR3zz9+cjbwM8ODoUB4fs3X3I5A/HtX7LZKxCLaMrEeDFoBpnhZY//DTS1VZBSs6S5v46RZRbZjRFspEg==}
+
+ browserslist@4.28.7:
+ resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ bs58@6.0.0:
+ resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==}
+
+ bs58check@4.0.0:
+ resolution: {integrity: sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==}
+
+ buffer@6.0.3:
+ resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+
+ bundle-name@4.1.0:
+ resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
+ engines: {node: '>=18'}
+
+ cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ camelcase@5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001806:
+ resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==}
+
+ cardinal@2.1.1:
+ resolution: {integrity: sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==}
+ hasBin: true
+
+ cbor-extract@2.2.2:
+ resolution: {integrity: sha512-hlSxxI9XO2yQfe9g6msd3g4xCfDqK5T5P0fRMLuaLHhxn4ViPrm+a+MUfhrvH2W962RGxcBwEGzLQyjbDG1gng==}
+ hasBin: true
+
+ cbor-js@0.1.0:
+ resolution: {integrity: sha512-7sQ/TvDZPl7csT1Sif9G0+MA0I0JOVah8+wWlJVQdVEgIbCzlN/ab3x+uvMNsc34TUvO6osQTAmB2ls80JX6tw==}
+
+ cbor-x@1.6.5:
+ resolution: {integrity: sha512-yO64CxnSh6kp+pHNRK9IfwnMvCB+c8HvmUjQY/9l9YRF0/cAPka/tUHLwS64QqUpFCq3/OtbKziVJYXH2EaRig==}
+
+ chai@5.3.3:
+ resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
+ engines: {node: '>=18'}
+
+ chalk@5.6.2:
+ resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
+ charenc@0.0.2:
+ resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
+
+ check-error@2.1.3:
+ resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
+ engines: {node: '>= 16'}
+
+ chokidar@5.0.0:
+ resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
+ engines: {node: '>= 20.19.0'}
+
+ cliui@6.0.0:
+ resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+
+ cliui@8.0.1:
+ resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
+
+ clsx@1.2.1:
+ resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
+ engines: {node: '>=6'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ commander@14.0.2:
+ resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==}
+ engines: {node: '>=20'}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cookie-es@1.2.3:
+ resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==}
+
+ cross-fetch@3.2.0:
+ resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==}
+
+ crossws@0.3.5:
+ resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
+
+ crypt@0.0.2:
+ resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
+
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ dayjs@1.11.13:
+ resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decamelize@1.2.0:
+ resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
+ engines: {node: '>=0.10.0'}
+
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
+ default-browser-id@5.0.1:
+ resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==}
+ engines: {node: '>=18'}
+
+ default-browser@5.5.0:
+ resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==}
+ engines: {node: '>=18'}
+
+ define-lazy-prop@3.0.0:
+ resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
+ engines: {node: '>=12'}
+
+ defu@6.1.7:
+ resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ destr@2.0.5:
+ resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
+
+ detect-browser@5.3.0:
+ resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==}
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ dijkstrajs@1.0.3:
+ resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ electron-to-chromium@1.5.399:
+ resolution: {integrity: sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ encode-utf8@1.0.3:
+ resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+
+ es-object-atoms@1.1.2:
+ resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ es-toolkit@1.44.0:
+ resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
+
+ es-toolkit@1.45.1:
+ resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==}
+
+ esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+ ethers@6.17.0:
+ resolution: {integrity: sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==}
+ engines: {node: '>=14.0.0'}
+
+ eventemitter3@5.0.1:
+ resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+
+ eventemitter3@5.0.4:
+ resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
+
+ events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+
+ expect-type@1.4.0:
+ resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==}
+ engines: {node: '>=12.0.0'}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ find-up@4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+
+ follow-redirects@1.16.0:
+ resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ form-data@4.0.6:
+ resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==}
+ engines: {node: '>= 6'}
+
+ fs-extra@10.1.0:
+ resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
+ engines: {node: '>=12'}
+
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ get-starknet-core@4.0.0:
+ resolution: {integrity: sha512-6pLmidQZkC3wZsrHY99grQHoGpuuXqkbSP65F8ov1/JsEI8DDLkhsAuLCKFzNOK56cJp+f1bWWfTJ57e9r5eqQ==}
+ deprecated: Package no longer supported. Please use @starknet-io/get-starknet-core
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ h3@1.15.11:
+ resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.4:
+ resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
+ engines: {node: '>= 0.4'}
+
+ hpke-js@1.8.0:
+ resolution: {integrity: sha512-N0PFQlUQsIPS9++nUNn2ZsxTPSv8pONyyrXIGZl0iiherRfS0XW1SvTd+RmepD0TN1S9zzTJkEutMIWWYt0/4w==}
+ engines: {node: '>=16.0.0'}
+
+ idb-keyval@6.2.1:
+ resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==}
+
+ idb-keyval@6.3.0:
+ resolution: {integrity: sha512-um+2dgAWmYsu615EXpWVwSmapJhON0G43t3Ka/EVaohzPQXSMqKEqeDK/oIW3Ow+BXaF2PvSc+oBTFp793A5Ow==}
+
+ ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
+ iron-webcrypto@1.2.1:
+ resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
+
+ is-buffer@1.1.6:
+ resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+
+ is-docker@3.0.0:
+ resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ hasBin: true
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-inside-container@1.0.0:
+ resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
+ engines: {node: '>=14.16'}
+ hasBin: true
+
+ is-retry-allowed@2.2.0:
+ resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==}
+ engines: {node: '>=10'}
+
+ is-wsl@3.1.1:
+ resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
+ engines: {node: '>=16'}
+
+ isows@1.0.7:
+ resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==}
+ peerDependencies:
+ ws: '*'
+
+ jose@6.2.6:
+ resolution: {integrity: sha512-HwMtbJjMw8rC8dUTwCNilHJD+fxTeKM3JV1eprSmTjS41qwXSSt6exJXgyPK1QOu0jB9eDYLESRDkB3qaT3jnw==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-tokens@9.0.1:
+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ jsonfile@6.2.1:
+ resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==}
+
+ keyvaluestorage-interface@1.0.0:
+ resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==}
+
+ lit-element@4.2.2:
+ resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==}
+
+ lit-html@3.3.3:
+ resolution: {integrity: sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==}
+
+ lit@3.3.0:
+ resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==}
+
+ locate-path@5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
+ lossless-json@4.3.1:
+ resolution: {integrity: sha512-SqD/Bg3ZfltBJ2Z14hJ/BihnvtV553WO4g9/ePtlp4lrnl9jF3AdIJt53A/Wkg/0Li+LMfxaBqgx1MiFZdQlpQ==}
+
+ loupe@3.2.1:
+ resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
+
+ lru-cache@11.5.2:
+ resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==}
+ engines: {node: 20 || >=22}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ md5@2.3.0:
+ resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
+
+ micro-packed@0.7.3:
+ resolution: {integrity: sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==}
+
+ micro-sol-signer@0.5.0:
+ resolution: {integrity: sha512-4D5mGHuWuAC1w7HXXs+mlugw9n0hk3Gk0pFjQYkzE6zbvwEEioyb6l8375hivcqD6830/tCDCyQv+i3jfVFC+w==}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mipd@0.0.7:
+ resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==}
+ peerDependencies:
+ typescript: '>=5.0.4'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ multiformats@9.9.0:
+ resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==}
+
+ nanoid@3.3.16:
+ resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-fetch-native@1.6.7:
+ resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
+
+ node-fetch@2.7.0:
+ resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+
+ node-gyp-build-optional-packages@5.1.1:
+ resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==}
+ hasBin: true
+
+ node-mock-http@1.0.5:
+ resolution: {integrity: sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==}
+
+ node-releases@2.0.51:
+ resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==}
+ engines: {node: '>=18'}
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ ofetch@1.5.1:
+ resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
+
+ on-exit-leak-free@2.1.2:
+ resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
+ engines: {node: '>=14.0.0'}
+
+ open@10.2.0:
+ resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==}
+ engines: {node: '>=18'}
+
+ ox@0.14.33:
+ resolution: {integrity: sha512-rooA/4o7bBof4Ge2VH/eovfNPb/AEEYyrNj03wggc55g5HZD8Pjs/OeWhttgjic3dDcqn0r29bDuvQEdTiUemQ==}
+ peerDependencies:
+ typescript: '>=5.4.0'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ ox@0.4.4:
+ resolution: {integrity: sha512-oJPEeCDs9iNiPs6J0rTx+Y0KGeCGyCAA3zo94yZhm8G5WpOxrwUtn2Ie/Y8IyARSqqY/j9JTKA3Fc1xs1DvFnw==}
+ peerDependencies:
+ typescript: '>=5.4.0'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ ox@0.6.9:
+ resolution: {integrity: sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==}
+ peerDependencies:
+ typescript: '>=5.4.0'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ ox@0.9.3:
+ resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==}
+ peerDependencies:
+ typescript: '>=5.4.0'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ p-limit@2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+
+ p-locate@4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+
+ p-try@2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+
+ pako@2.2.0:
+ resolution: {integrity: sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ pathval@2.0.1:
+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ engines: {node: '>= 14.16'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.2:
+ resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.5:
+ resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
+ engines: {node: '>=12'}
+
+ pino-abstract-transport@2.0.0:
+ resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==}
+
+ pino-std-serializers@7.1.0:
+ resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==}
+
+ pino@10.0.0:
+ resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==}
+ hasBin: true
+
+ playwright-core@1.62.1:
+ resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==}
+ engines: {node: '>=20'}
+ hasBin: true
+
+ playwright@1.62.1:
+ resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==}
+ engines: {node: '>=20'}
+ hasBin: true
+
+ pngjs@5.0.0:
+ resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
+ engines: {node: '>=10.13.0'}
+
+ postcss@8.5.25:
+ resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ preact@10.24.2:
+ resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==}
+
+ process-warning@5.1.0:
+ resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==}
+
+ proxy-compare@3.0.1:
+ resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==}
+
+ proxy-from-env@2.1.0:
+ resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
+ engines: {node: '>=10'}
+
+ pvtsutils@1.3.6:
+ resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==}
+
+ pvutils@1.1.5:
+ resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==}
+ engines: {node: '>=16.0.0'}
+
+ qrcode@1.5.3:
+ resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+
+ quick-format-unescaped@4.0.4:
+ resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
+
+ radix3@1.1.2:
+ resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
+
+ react-dom@18.3.1:
+ resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
+ peerDependencies:
+ react: ^18.3.1
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@18.3.1:
+ resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
+ engines: {node: '>=0.10.0'}
+
+ readdirp@5.0.0:
+ resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
+ engines: {node: '>= 20.19.0'}
+
+ real-require@0.2.0:
+ resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
+ engines: {node: '>= 12.13.0'}
+
+ redeyed@2.1.1:
+ resolution: {integrity: sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==}
+
+ reflect-metadata@0.2.2:
+ resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
+
+ require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ require-main-filename@2.0.0:
+ resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+
+ rollup@4.62.3:
+ resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ run-applescript@7.1.0:
+ resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==}
+ engines: {node: '>=18'}
+
+ safe-stable-stringify@2.5.0:
+ resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
+ engines: {node: '>=10'}
+
+ scheduler@0.23.2:
+ resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.2:
+ resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ set-blocking@2.0.0:
+ resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
+
+ sha256-uint8array@0.10.7:
+ resolution: {integrity: sha512-1Q6JQU4tX9NqsDGodej6pkrUVQVNapLZnvkwIhddH/JqzBZF1fSaxSWNY6sziXBE8aEa2twtGkXUrwzGeZCMpQ==}
+
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
+ slow-redact@0.3.2:
+ resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==}
+
+ sonic-boom@4.2.1:
+ resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ split2@4.2.0:
+ resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
+ engines: {node: '>= 10.x'}
+
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+ starknet@8.9.2:
+ resolution: {integrity: sha512-+dp+o2w67fV6JyVOVkYeM1Ec71aORHc/JrF4VHLlfeGee0nLilooCQLE2u6hUcSGQG2x2/fvzkxYpIN+k1JBvA==}
+ engines: {node: '>=22'}
+
+ starknet@9.4.2:
+ resolution: {integrity: sha512-NFtg077DjddHUSh8sLZ5uB149LEF4NR90FuJ0oF7+zhce7l0oG9Ubqr3H4+jHm/ghHtV+yjlv1UhEoo4SBfILA==}
+ engines: {node: '>=22'}
+
+ std-env@3.10.0:
+ resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-literal@3.1.0:
+ resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
+
+ thread-stream@3.2.0:
+ resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==}
+
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@0.3.2:
+ resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
+ tinyglobby@0.2.17:
+ resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
+ engines: {node: '>=12.0.0'}
+
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@2.0.0:
+ resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@4.0.4:
+ resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==}
+ engines: {node: '>=14.0.0'}
+
+ tr46@0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
+ ts-mixer@6.0.4:
+ resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==}
+
+ tslib@1.14.1:
+ resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+
+ tslib@2.7.0:
+ resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ tsyringe@4.10.0:
+ resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==}
+ engines: {node: '>= 6.0.0'}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ ufo@1.6.4:
+ resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}
+
+ uint8arrays@3.1.1:
+ resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==}
+
+ uncrypto@0.1.3:
+ resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
+
+ undici-types@6.19.8:
+ resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
+
+ undici-types@7.29.0:
+ resolution: {integrity: sha512-vamA8dGlzMwhpyYpQp9d8vka3o4D/yn5I7ez7Or+msDA4bZ8Uh+Zy91WvWf3I73gDAkFha9JcYRqm2li0Npfgg==}
+
+ universalify@2.0.1:
+ resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
+ engines: {node: '>= 10.0.0'}
+
+ unstorage@1.17.5:
+ resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==}
+ peerDependencies:
+ '@azure/app-configuration': ^1.8.0
+ '@azure/cosmos': ^4.2.0
+ '@azure/data-tables': ^13.3.0
+ '@azure/identity': ^4.6.0
+ '@azure/keyvault-secrets': ^4.9.0
+ '@azure/storage-blob': ^12.26.0
+ '@capacitor/preferences': ^6 || ^7 || ^8
+ '@deno/kv': '>=0.9.0'
+ '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
+ '@planetscale/database': ^1.19.0
+ '@upstash/redis': ^1.34.3
+ '@vercel/blob': '>=0.27.1'
+ '@vercel/functions': ^2.2.12 || ^3.0.0
+ '@vercel/kv': ^1 || ^2 || ^3
+ aws4fetch: ^1.0.20
+ db0: '>=0.2.1'
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
+ uploadthing: ^7.4.4
+ peerDependenciesMeta:
+ '@azure/app-configuration':
+ optional: true
+ '@azure/cosmos':
+ optional: true
+ '@azure/data-tables':
+ optional: true
+ '@azure/identity':
+ optional: true
+ '@azure/keyvault-secrets':
+ optional: true
+ '@azure/storage-blob':
+ optional: true
+ '@capacitor/preferences':
+ optional: true
+ '@deno/kv':
+ optional: true
+ '@netlify/blobs':
+ optional: true
+ '@planetscale/database':
+ optional: true
+ '@upstash/redis':
+ optional: true
+ '@vercel/blob':
+ optional: true
+ '@vercel/functions':
+ optional: true
+ '@vercel/kv':
+ optional: true
+ aws4fetch:
+ optional: true
+ db0:
+ optional: true
+ idb-keyval:
+ optional: true
+ ioredis:
+ optional: true
+ uploadthing:
+ optional: true
+
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ valtio@2.1.7:
+ resolution: {integrity: sha512-DwJhCDpujuQuKdJ2H84VbTjEJJteaSmqsuUltsfbfdbotVfNeTE4K/qc/Wi57I9x8/2ed4JNdjEna7O6PfavRg==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=18.0.0'
+ react: '>=18.0.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react:
+ optional: true
+
+ viem@2.55.10:
+ resolution: {integrity: sha512-Q9Ba+/ma81U2M5o5P2AQ7Ux8rTIwmCZvUcr8rKdQ22bV0IBFHllM2m5gWDP8hFaUN2nH2oW3QG44amRazflYNQ==}
+ peerDependencies:
+ typescript: '>=5.0.4'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ vite-node@3.2.4:
+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+
+ vite@5.4.21:
+ resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+
+ vitest@3.2.7:
+ resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/debug': ^4.1.12
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ '@vitest/browser': 3.2.7
+ '@vitest/ui': 3.2.7
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/debug':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ webidl-conversions@3.0.1:
+ resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+
+ whatwg-url@5.0.0:
+ resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+
+ which-module@2.0.1:
+ resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
+
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
+ wrap-ansi@6.2.0:
+ resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+ engines: {node: '>=8'}
+
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ ws@7.5.13:
+ resolution: {integrity: sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==}
+ engines: {node: '>=8.3.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ ws@8.21.0:
+ resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ ws@8.21.1:
+ resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ wsl-utils@0.1.0:
+ resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==}
+ engines: {node: '>=18'}
+
+ y18n@4.0.3:
+ resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
+
+ y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yargs-parser@18.1.3:
+ resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
+ engines: {node: '>=6'}
+
+ yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ yargs@15.4.1:
+ resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
+ engines: {node: '>=8'}
+
+ yargs@17.7.3:
+ resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==}
+ engines: {node: '>=12'}
+
+ zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
+
+ zod@3.25.76:
+ resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
+
+ zustand@5.0.3:
+ resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=18.0.0'
+ immer: '>=9.0.6'
+ react: '>=18.0.0'
+ use-sync-external-store: '>=1.2.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+
+snapshots:
+
+ '@adraffy/ens-normalize@1.11.1': {}
+
+ '@babel/code-frame@7.29.7':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.29.7
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.7': {}
+
+ '@babel/core@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/generator': 7.29.8
+ '@babel/helper-compilation-targets': 7.29.7
+ '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7)
+ '@babel/helpers': 7.29.7
+ '@babel/parser': 7.29.8
+ '@babel/template': 7.29.7
+ '@babel/traverse': 7.29.8
+ '@babel/types': 7.29.8
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.8':
+ dependencies:
+ '@babel/parser': 7.29.8
+ '@babel/types': 7.29.8
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.29.7':
+ dependencies:
+ '@babel/compat-data': 7.29.7
+ '@babel/helper-validator-option': 7.29.7
+ browserslist: 4.28.7
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.29.7': {}
+
+ '@babel/helper-module-imports@7.29.7':
+ dependencies:
+ '@babel/traverse': 7.29.8
+ '@babel/types': 7.29.8
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-module-imports': 7.29.7
+ '@babel/helper-validator-identifier': 7.29.7
+ '@babel/traverse': 7.29.8
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.29.7': {}
+
+ '@babel/helper-string-parser@7.29.7': {}
+
+ '@babel/helper-validator-identifier@7.29.7': {}
+
+ '@babel/helper-validator-option@7.29.7': {}
+
+ '@babel/helpers@7.29.7':
+ dependencies:
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.8
+
+ '@babel/parser@7.29.8':
+ dependencies:
+ '@babel/types': 7.29.8
+
+ '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-plugin-utils': 7.29.7
+
+ '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-plugin-utils': 7.29.7
+
+ '@babel/template@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/parser': 7.29.8
+ '@babel/types': 7.29.8
+
+ '@babel/traverse@7.29.8':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/generator': 7.29.8
+ '@babel/helper-globals': 7.29.7
+ '@babel/parser': 7.29.8
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.8
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.8':
+ dependencies:
+ '@babel/helper-string-parser': 7.29.7
+ '@babel/helper-validator-identifier': 7.29.7
+
+ '@base-org/account@2.4.0(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@coinbase/cdp-sdk': 1.54.0(typescript@5.9.3)
+ '@noble/hashes': 1.4.0
+ clsx: 1.2.1
+ eventemitter3: 5.0.1
+ idb-keyval: 6.2.1
+ ox: 0.6.9(typescript@5.9.3)(zod@3.25.76)
+ preact: 10.24.2
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ zustand: 5.0.3(@types/react@18.3.31)(react@18.3.1)
+ transitivePeerDependencies:
+ - '@types/react'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - bufferutil
+ - debug
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - react
+ - typescript
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+ optional: true
+
+ '@cartridge/connector@0.13.16(@starknet-react/core@5.0.3(get-starknet-core@4.0.0)(react@18.3.1)(starknet@9.4.2(typescript@5.9.3)(zod@3.25.76))(typescript@5.9.3))(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@cartridge/controller': 0.13.16(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-react/core': 5.0.3(get-starknet-core@4.0.0)(react@18.3.1)(starknet@9.4.2(typescript@5.9.3)(zod@3.25.76))(typescript@5.9.3)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - react
+ - react-dom
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+
+ '@cartridge/controller-wasm@0.10.1': {}
+
+ '@cartridge/controller@0.13.16(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@cartridge/controller-wasm': 0.10.1
+ '@cartridge/penpal': 6.2.4
+ '@starknet-io/get-starknet-core': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/types-js': 0.9.1
+ '@turnkey/sdk-browser': 5.16.1(typescript@5.9.3)(zod@3.25.76)
+ '@wallet-standard/wallet': 1.1.1
+ '@walletconnect/ethereum-provider': 2.23.10(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ bs58: 6.0.0
+ cbor-x: 1.6.5
+ ethers: 6.17.0
+ micro-sol-signer: 0.5.0
+ mipd: 0.0.7(typescript@5.9.3)
+ open: 10.2.0
+ starknet: 8.9.2
+ optionalDependencies:
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+
+ '@cartridge/penpal@6.2.4': {}
+
+ '@cbor-extract/cbor-extract-darwin-arm64@2.2.2':
+ optional: true
+
+ '@cbor-extract/cbor-extract-darwin-x64@2.2.2':
+ optional: true
+
+ '@cbor-extract/cbor-extract-linux-arm64@2.2.2':
+ optional: true
+
+ '@cbor-extract/cbor-extract-linux-arm@2.2.2':
+ optional: true
+
+ '@cbor-extract/cbor-extract-linux-x64@2.2.2':
+ optional: true
+
+ '@cbor-extract/cbor-extract-win32-x64@2.2.2':
+ optional: true
+
+ '@coinbase/cdp-sdk@1.54.0(typescript@5.9.3)':
+ dependencies:
+ '@solana-program/system': 0.10.0(@solana/kit@5.5.1(typescript@5.9.3))
+ '@solana-program/token': 0.9.0(@solana/kit@5.5.1(typescript@5.9.3))
+ '@solana/kit': 5.5.1(typescript@5.9.3)
+ abitype: 1.0.6(typescript@5.9.3)(zod@3.25.76)
+ axios: 1.16.0
+ axios-retry: 4.5.0(axios@1.16.0)
+ bs58: 6.0.0
+ jose: 6.2.6
+ md5: 2.3.0
+ uncrypto: 0.1.3
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ zod: 3.25.76
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - fastestsmallesttextencoderdecoder
+ - typescript
+ - utf-8-validate
+ optional: true
+
+ '@esbuild/aix-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm@0.21.5':
+ optional: true
+
+ '@esbuild/android-x64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.21.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.21.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/win32-x64@0.21.5':
+ optional: true
+
+ '@hpke/chacha20poly1305@1.8.0':
+ dependencies:
+ '@hpke/common': 1.10.1
+
+ '@hpke/common@1.10.1': {}
+
+ '@hpke/core@1.9.0':
+ dependencies:
+ '@hpke/common': 1.10.1
+
+ '@hpke/dhkem-x25519@1.8.0':
+ dependencies:
+ '@hpke/common': 1.10.1
+
+ '@hpke/dhkem-x448@1.8.0':
+ dependencies:
+ '@hpke/common': 1.10.1
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@lit-labs/ssr-dom-shim@1.6.0': {}
+
+ '@lit/react@1.0.8(@types/react@18.3.31)':
+ dependencies:
+ '@types/react': 18.3.31
+ optional: true
+
+ '@lit/reactive-element@2.1.2':
+ dependencies:
+ '@lit-labs/ssr-dom-shim': 1.6.0
+
+ '@module-federation/error-codes@0.12.0': {}
+
+ '@module-federation/runtime-core@0.12.0':
+ dependencies:
+ '@module-federation/error-codes': 0.12.0
+ '@module-federation/sdk': 0.12.0
+
+ '@module-federation/runtime@0.12.0':
+ dependencies:
+ '@module-federation/error-codes': 0.12.0
+ '@module-federation/runtime-core': 0.12.0
+ '@module-federation/sdk': 0.12.0
+
+ '@module-federation/sdk@0.12.0': {}
+
+ '@msgpack/msgpack@3.1.3': {}
+
+ '@noble/ciphers@1.3.0': {}
+
+ '@noble/curves@1.2.0':
+ dependencies:
+ '@noble/hashes': 1.3.2
+
+ '@noble/curves@1.7.0':
+ dependencies:
+ '@noble/hashes': 1.6.0
+
+ '@noble/curves@1.8.0':
+ dependencies:
+ '@noble/hashes': 1.7.0
+
+ '@noble/curves@1.9.0':
+ dependencies:
+ '@noble/hashes': 1.8.0
+
+ '@noble/curves@1.9.1':
+ dependencies:
+ '@noble/hashes': 1.8.0
+
+ '@noble/curves@1.9.7':
+ dependencies:
+ '@noble/hashes': 1.8.0
+
+ '@noble/hashes@1.3.2': {}
+
+ '@noble/hashes@1.4.0':
+ optional: true
+
+ '@noble/hashes@1.6.0': {}
+
+ '@noble/hashes@1.6.1': {}
+
+ '@noble/hashes@1.7.0': {}
+
+ '@noble/hashes@1.8.0': {}
+
+ '@peculiar/asn1-cms@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ '@peculiar/asn1-x509-attr': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-csr@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-ecc@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-pfx@2.8.0':
+ dependencies:
+ '@peculiar/asn1-cms': 2.8.0
+ '@peculiar/asn1-pkcs8': 2.8.0
+ '@peculiar/asn1-rsa': 2.8.0
+ '@peculiar/asn1-schema': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-pkcs8@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-pkcs9@2.8.0':
+ dependencies:
+ '@peculiar/asn1-cms': 2.8.0
+ '@peculiar/asn1-pfx': 2.8.0
+ '@peculiar/asn1-pkcs8': 2.8.0
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ '@peculiar/asn1-x509-attr': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-rsa@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-schema@2.8.0':
+ dependencies:
+ '@peculiar/utils': 2.0.3
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-x509-attr@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/asn1-x509@2.8.0':
+ dependencies:
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/utils': 2.0.3
+ asn1js: 3.0.10
+ tslib: 2.8.1
+
+ '@peculiar/utils@2.0.3':
+ dependencies:
+ tslib: 2.8.1
+
+ '@peculiar/x509@1.12.3':
+ dependencies:
+ '@peculiar/asn1-cms': 2.8.0
+ '@peculiar/asn1-csr': 2.8.0
+ '@peculiar/asn1-ecc': 2.8.0
+ '@peculiar/asn1-pkcs9': 2.8.0
+ '@peculiar/asn1-rsa': 2.8.0
+ '@peculiar/asn1-schema': 2.8.0
+ '@peculiar/asn1-x509': 2.8.0
+ pvtsutils: 1.3.6
+ reflect-metadata: 0.2.2
+ tslib: 2.8.1
+ tsyringe: 4.10.0
+
+ '@phosphor-icons/webcomponents@2.1.5':
+ dependencies:
+ lit: 3.3.0
+
+ '@reown/appkit-common@1.8.19(typescript@5.9.3)(zod@3.22.4)':
+ dependencies:
+ big.js: 6.2.2
+ dayjs: 1.11.13
+ viem: 2.55.10(typescript@5.9.3)(zod@3.22.4)
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@reown/appkit-common@1.8.19(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ big.js: 6.2.2
+ dayjs: 1.11.13
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@reown/appkit-controllers@1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-wallet': 1.8.19(typescript@5.9.3)
+ '@walletconnect/universal-provider': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ valtio: 2.1.7(@types/react@18.3.31)(react@18.3.1)
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - encoding
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@reown/appkit-pay@1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-ui': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-utils': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(valtio@2.1.7(@types/react@18.3.31)(react@18.3.1))(zod@3.25.76)
+ lit: 3.3.0
+ valtio: 2.1.7(@types/react@18.3.31)(react@18.3.1)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+
+ '@reown/appkit-polyfills@1.8.19':
+ dependencies:
+ buffer: 6.0.3
+
+ '@reown/appkit-scaffold-ui@1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(valtio@2.1.7(@types/react@18.3.31)(react@18.3.1))(zod@3.25.76)':
+ dependencies:
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-pay': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-ui': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-utils': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(valtio@2.1.7(@types/react@18.3.31)(react@18.3.1))(zod@3.25.76)
+ '@reown/appkit-wallet': 1.8.19(typescript@5.9.3)
+ lit: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - valtio
+ - zod
+
+ '@reown/appkit-ui@1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@phosphor-icons/webcomponents': 2.1.5
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-wallet': 1.8.19(typescript@5.9.3)
+ lit: 3.3.0
+ qrcode: 1.5.3
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - encoding
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@reown/appkit-utils@1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(valtio@2.1.7(@types/react@18.3.31)(react@18.3.1))(zod@3.25.76)':
+ dependencies:
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-polyfills': 1.8.19
+ '@reown/appkit-wallet': 1.8.19(typescript@5.9.3)
+ '@wallet-standard/wallet': 1.1.0
+ '@walletconnect/logger': 3.0.2
+ '@walletconnect/universal-provider': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ valtio: 2.1.7(@types/react@18.3.31)(react@18.3.1)
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ optionalDependencies:
+ '@base-org/account': 2.4.0(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@safe-global/safe-apps-provider': 0.18.6(typescript@5.9.3)(zod@3.25.76)
+ '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+
+ '@reown/appkit-wallet@1.8.19(typescript@5.9.3)':
+ dependencies:
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.22.4)
+ '@reown/appkit-polyfills': 1.8.19
+ '@walletconnect/logger': 3.0.2
+ zod: 3.22.4
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+
+ '@reown/appkit@1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@reown/appkit-common': 1.8.19(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-pay': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-polyfills': 1.8.19
+ '@reown/appkit-scaffold-ui': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(valtio@2.1.7(@types/react@18.3.31)(react@18.3.1))(zod@3.25.76)
+ '@reown/appkit-ui': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@reown/appkit-utils': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(valtio@2.1.7(@types/react@18.3.31)(react@18.3.1))(zod@3.25.76)
+ '@reown/appkit-wallet': 1.8.19(typescript@5.9.3)
+ '@walletconnect/universal-provider': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ bs58: 6.0.0
+ semver: 7.7.2
+ valtio: 2.1.7(@types/react@18.3.31)(react@18.3.1)
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ optionalDependencies:
+ '@lit/react': 1.0.8(@types/react@18.3.31)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+
+ '@rolldown/pluginutils@1.0.0-beta.27': {}
+
+ '@rollup/rollup-android-arm-eabi@4.62.3':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-musl@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-musl@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.62.3':
+ optional: true
+
+ '@rollup/rollup-openbsd-x64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.62.3':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.62.3':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.62.3':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.62.3':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.62.3':
+ optional: true
+
+ '@safe-global/safe-apps-provider@0.18.6(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@safe-global/safe-apps-sdk': 9.1.0(typescript@5.9.3)(zod@3.25.76)
+ events: 3.3.0
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+ optional: true
+
+ '@safe-global/safe-apps-sdk@9.1.0(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@safe-global/safe-gateway-typescript-sdk': 3.23.1
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+ optional: true
+
+ '@safe-global/safe-gateway-typescript-sdk@3.23.1':
+ optional: true
+
+ '@scure/base@1.2.6': {}
+
+ '@scure/bip32@1.7.0':
+ dependencies:
+ '@noble/curves': 1.9.1
+ '@noble/hashes': 1.8.0
+ '@scure/base': 1.2.6
+
+ '@scure/bip39@1.6.0':
+ dependencies:
+ '@noble/hashes': 1.8.0
+ '@scure/base': 1.2.6
+
+ '@scure/starknet@1.1.0':
+ dependencies:
+ '@noble/curves': 1.7.0
+ '@noble/hashes': 1.6.1
+
+ '@solana-program/system@0.10.0(@solana/kit@5.5.1(typescript@5.9.3))':
+ dependencies:
+ '@solana/kit': 5.5.1(typescript@5.9.3)
+ optional: true
+
+ '@solana-program/token@0.9.0(@solana/kit@5.5.1(typescript@5.9.3))':
+ dependencies:
+ '@solana/kit': 5.5.1(typescript@5.9.3)
+ optional: true
+
+ '@solana/accounts@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/addresses@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/assertions': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/assertions@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/codecs-core@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/codecs-data-structures@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/codecs-numbers@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/codecs-strings@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/codecs@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/options': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/errors@5.5.1(typescript@5.9.3)':
+ dependencies:
+ chalk: 5.6.2
+ commander: 14.0.2
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/fast-stable-stringify@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/functional@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/instruction-plans@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/instructions': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/promises': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transactions': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/instructions@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/keys@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/assertions': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/kit@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/accounts': 5.5.1(typescript@5.9.3)
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/instruction-plans': 5.5.1(typescript@5.9.3)
+ '@solana/instructions': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/offchain-messages': 5.5.1(typescript@5.9.3)
+ '@solana/plugin-core': 5.5.1(typescript@5.9.3)
+ '@solana/programs': 5.5.1(typescript@5.9.3)
+ '@solana/rpc': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-api': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-parsed-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ '@solana/signers': 5.5.1(typescript@5.9.3)
+ '@solana/sysvars': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-confirmation': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transactions': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - fastestsmallesttextencoderdecoder
+ - utf-8-validate
+ optional: true
+
+ '@solana/nominal-types@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/offchain-messages@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/options@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/plugin-core@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/programs@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/promises@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/rpc-api@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-parsed-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-transformers': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transactions': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/rpc-parsed-types@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/rpc-spec-types@5.5.1(typescript@5.9.3)':
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/rpc-spec@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/rpc-subscriptions-api@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions-spec': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-transformers': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transactions': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/rpc-subscriptions-channel-websocket@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions-spec': 5.5.1(typescript@5.9.3)
+ '@solana/subscribable': 5.5.1(typescript@5.9.3)
+ ws: 8.21.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+ optional: true
+
+ '@solana/rpc-subscriptions-spec@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/promises': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ '@solana/subscribable': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/rpc-subscriptions@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/fast-stable-stringify': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/promises': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions-api': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions-channel-websocket': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions-spec': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-transformers': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ '@solana/subscribable': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - fastestsmallesttextencoderdecoder
+ - utf-8-validate
+ optional: true
+
+ '@solana/rpc-transformers@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/rpc-transport-http@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ undici-types: 7.29.0
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/rpc-types@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/rpc@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/fast-stable-stringify': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-api': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-transformers': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-transport-http': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/signers@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/instructions': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ '@solana/offchain-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transactions': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/subscribable@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ optional: true
+
+ '@solana/sysvars@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/accounts': 5.5.1(typescript@5.9.3)
+ '@solana/codecs': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/transaction-confirmation@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/promises': 5.5.1(typescript@5.9.3)
+ '@solana/rpc': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-subscriptions': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ '@solana/transactions': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - fastestsmallesttextencoderdecoder
+ - utf-8-validate
+ optional: true
+
+ '@solana/transaction-messages@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/instructions': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@solana/transactions@5.5.1(typescript@5.9.3)':
+ dependencies:
+ '@solana/addresses': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-core': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-numbers': 5.5.1(typescript@5.9.3)
+ '@solana/codecs-strings': 5.5.1(typescript@5.9.3)
+ '@solana/errors': 5.5.1(typescript@5.9.3)
+ '@solana/functional': 5.5.1(typescript@5.9.3)
+ '@solana/instructions': 5.5.1(typescript@5.9.3)
+ '@solana/keys': 5.5.1(typescript@5.9.3)
+ '@solana/nominal-types': 5.5.1(typescript@5.9.3)
+ '@solana/rpc-types': 5.5.1(typescript@5.9.3)
+ '@solana/transaction-messages': 5.5.1(typescript@5.9.3)
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - fastestsmallesttextencoderdecoder
+ optional: true
+
+ '@starknet-io/get-starknet-core@5.0.0(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@starknet-io/get-starknet-discovery': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/get-starknet-virtual-wallet': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/get-starknet-wallet-standard': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/get-starknet-wallets': 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@starknet-io/get-starknet-discovery@5.0.0(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@starknet-io/get-starknet-virtual-wallet': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/get-starknet-wallet-standard': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/types-js': 0.7.10
+ '@wallet-standard/base': 1.1.1
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@starknet-io/get-starknet-virtual-wallet@5.0.0(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@module-federation/runtime': 0.12.0
+ '@starknet-io/get-starknet-wallet-standard': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/types-js': 0.7.10
+ '@wallet-standard/base': 1.1.1
+ '@wallet-standard/features': 1.1.1
+ async-mutex: 0.5.0
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@starknet-io/get-starknet-wallet-standard@5.0.0(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@starknet-io/types-js': 0.7.10
+ '@wallet-standard/base': 1.1.1
+ '@wallet-standard/features': 1.1.1
+ ox: 0.4.4(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - typescript
+ - zod
+
+ '@starknet-io/get-starknet-wallets@5.0.0': {}
+
+ '@starknet-io/types-js@0.10.0': {}
+
+ '@starknet-io/types-js@0.7.10': {}
+
+ '@starknet-io/types-js@0.8.4': {}
+
+ '@starknet-io/types-js@0.9.1': {}
+
+ '@starknet-io/types-js@0.9.2': {}
+
+ '@starknet-react/chains@5.0.3': {}
+
+ '@starknet-react/core@5.0.3(get-starknet-core@4.0.0)(react@18.3.1)(starknet@9.4.2(typescript@5.9.3)(zod@3.25.76))(typescript@5.9.3)':
+ dependencies:
+ '@starknet-io/types-js': 0.7.10
+ '@starknet-react/chains': 5.0.3
+ '@tanstack/react-query': 5.101.4(react@18.3.1)
+ abi-wan-kanabi: 2.2.4
+ eventemitter3: 5.0.4
+ get-starknet-core: 4.0.0
+ react: 18.3.1
+ starknet: 9.4.2(typescript@5.9.3)(zod@3.25.76)
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ zod: 3.25.76
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+
+ '@tanstack/query-core@5.101.4': {}
+
+ '@tanstack/react-query@5.101.4(react@18.3.1)':
+ dependencies:
+ '@tanstack/query-core': 5.101.4
+ react: 18.3.1
+
+ '@turnkey/api-key-stamper@0.6.5':
+ dependencies:
+ '@noble/curves': 1.9.7
+ '@turnkey/crypto': 2.8.14
+ '@turnkey/encoding': 0.6.0
+ sha256-uint8array: 0.10.7
+
+ '@turnkey/crypto@2.8.14':
+ dependencies:
+ '@noble/ciphers': 1.3.0
+ '@noble/curves': 1.9.0
+ '@noble/hashes': 1.8.0
+ '@peculiar/x509': 1.12.3
+ '@turnkey/encoding': 0.6.0
+ '@turnkey/sdk-types': 0.14.0
+ borsh: 2.0.0
+ cbor-js: 0.1.0
+
+ '@turnkey/encoding@0.6.0':
+ dependencies:
+ bs58: 6.0.0
+ bs58check: 4.0.0
+
+ '@turnkey/http@3.18.1':
+ dependencies:
+ '@turnkey/api-key-stamper': 0.6.5
+ '@turnkey/encoding': 0.6.0
+ '@turnkey/webauthn-stamper': 0.6.0
+ cross-fetch: 3.2.0
+ transitivePeerDependencies:
+ - encoding
+
+ '@turnkey/iframe-stamper@2.11.0': {}
+
+ '@turnkey/indexed-db-stamper@1.2.6':
+ dependencies:
+ '@turnkey/api-key-stamper': 0.6.5
+ '@turnkey/encoding': 0.6.0
+
+ '@turnkey/sdk-browser@5.16.1(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@turnkey/api-key-stamper': 0.6.5
+ '@turnkey/crypto': 2.8.14
+ '@turnkey/encoding': 0.6.0
+ '@turnkey/http': 3.18.1
+ '@turnkey/iframe-stamper': 2.11.0
+ '@turnkey/indexed-db-stamper': 1.2.6
+ '@turnkey/sdk-types': 0.14.0
+ '@turnkey/wallet-stamper': 1.1.16(typescript@5.9.3)(zod@3.25.76)
+ '@turnkey/webauthn-stamper': 0.6.0
+ buffer: 6.0.3
+ cross-fetch: 3.2.0
+ hpke-js: 1.8.0
+ transitivePeerDependencies:
+ - bufferutil
+ - encoding
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@turnkey/sdk-types@0.14.0': {}
+
+ '@turnkey/wallet-stamper@1.1.16(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@turnkey/crypto': 2.8.14
+ '@turnkey/encoding': 0.6.0
+ optionalDependencies:
+ viem: 2.55.10(typescript@5.9.3)(zod@3.25.76)
+ transitivePeerDependencies:
+ - bufferutil
+ - typescript
+ - utf-8-validate
+ - zod
+
+ '@turnkey/webauthn-stamper@0.6.0':
+ dependencies:
+ sha256-uint8array: 0.10.7
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.29.8
+ '@babel/types': 7.29.8
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.29.8
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.29.8
+ '@babel/types': 7.29.8
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.29.8
+
+ '@types/chai@5.2.3':
+ dependencies:
+ '@types/deep-eql': 4.0.2
+ assertion-error: 2.0.1
+
+ '@types/deep-eql@4.0.2': {}
+
+ '@types/estree@1.0.9': {}
+
+ '@types/node@22.7.5':
+ dependencies:
+ undici-types: 6.19.8
+
+ '@types/prop-types@15.7.15': {}
+
+ '@types/react-dom@18.3.7(@types/react@18.3.31)':
+ dependencies:
+ '@types/react': 18.3.31
+
+ '@types/react@18.3.31':
+ dependencies:
+ '@types/prop-types': 15.7.15
+ csstype: 3.2.3
+
+ '@types/trusted-types@2.0.7': {}
+
+ '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@22.7.5))':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7)
+ '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7)
+ '@rolldown/pluginutils': 1.0.0-beta.27
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 5.4.21(@types/node@22.7.5)
+ transitivePeerDependencies:
+ - supports-color
+
+ '@vitest/expect@3.2.7':
+ dependencies:
+ '@types/chai': 5.2.3
+ '@vitest/spy': 3.2.7
+ '@vitest/utils': 3.2.7
+ chai: 5.3.3
+ tinyrainbow: 2.0.0
+
+ '@vitest/mocker@3.2.7(vite@5.4.21(@types/node@22.7.5))':
+ dependencies:
+ '@vitest/spy': 3.2.7
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ optionalDependencies:
+ vite: 5.4.21(@types/node@22.7.5)
+
+ '@vitest/pretty-format@3.2.7':
+ dependencies:
+ tinyrainbow: 2.0.0
+
+ '@vitest/runner@3.2.7':
+ dependencies:
+ '@vitest/utils': 3.2.7
+ pathe: 2.0.3
+ strip-literal: 3.1.0
+
+ '@vitest/snapshot@3.2.7':
+ dependencies:
+ '@vitest/pretty-format': 3.2.7
+ magic-string: 0.30.21
+ pathe: 2.0.3
+
+ '@vitest/spy@3.2.7':
+ dependencies:
+ tinyspy: 4.0.4
+
+ '@vitest/utils@3.2.7':
+ dependencies:
+ '@vitest/pretty-format': 3.2.7
+ loupe: 3.2.1
+ tinyrainbow: 2.0.0
+
+ '@wallet-standard/base@1.1.1': {}
+
+ '@wallet-standard/features@1.1.1':
+ dependencies:
+ '@wallet-standard/base': 1.1.1
+
+ '@wallet-standard/wallet@1.1.0':
+ dependencies:
+ '@wallet-standard/base': 1.1.1
+
+ '@wallet-standard/wallet@1.1.1':
+ dependencies:
+ '@wallet-standard/base': 1.1.1
+
+ '@walletconnect/core@2.23.10(typescript@5.9.3)(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
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.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.23.10
+ '@walletconnect/utils': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/window-getters': 1.0.1
+ es-toolkit: 1.45.1
+ events: 3.3.0
+ uint8arrays: 3.1.1
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - ioredis
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/core@2.23.7(typescript@5.9.3)(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
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.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.23.7
+ '@walletconnect/utils': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/window-getters': 1.0.1
+ es-toolkit: 1.44.0
+ events: 3.3.0
+ uint8arrays: 3.1.1
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - ioredis
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/environment@1.0.1':
+ dependencies:
+ tslib: 1.14.1
+
+ '@walletconnect/ethereum-provider@2.23.10(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@reown/appkit': 1.8.19(@types/react@18.3.31)(react@18.3.1)(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/jsonrpc-provider': 1.0.14
+ '@walletconnect/jsonrpc-types': 1.0.4
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/sign-client': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/types': 2.23.10
+ '@walletconnect/universal-provider': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/utils': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@types/react'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - '@x402/core'
+ - '@x402/evm'
+ - '@x402/extensions'
+ - '@x402/svm'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - debug
+ - encoding
+ - fastestsmallesttextencoderdecoder
+ - immer
+ - ioredis
+ - react
+ - typescript
+ - uploadthing
+ - use-sync-external-store
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/events@1.0.1':
+ dependencies:
+ keyvaluestorage-interface: 1.0.0
+ tslib: 1.14.1
+
+ '@walletconnect/heartbeat@1.2.2':
+ dependencies:
+ '@walletconnect/events': 1.0.1
+ '@walletconnect/time': 1.0.2
+ events: 3.3.0
+
+ '@walletconnect/jsonrpc-http-connection@1.0.8':
+ dependencies:
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/safe-json': 1.0.2
+ cross-fetch: 3.2.0
+ events: 3.3.0
+ transitivePeerDependencies:
+ - encoding
+
+ '@walletconnect/jsonrpc-provider@1.0.14':
+ dependencies:
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/safe-json': 1.0.2
+ events: 3.3.0
+
+ '@walletconnect/jsonrpc-types@1.0.4':
+ dependencies:
+ events: 3.3.0
+ keyvaluestorage-interface: 1.0.0
+
+ '@walletconnect/jsonrpc-utils@1.0.8':
+ dependencies:
+ '@walletconnect/environment': 1.0.1
+ '@walletconnect/jsonrpc-types': 1.0.4
+ tslib: 1.14.1
+
+ '@walletconnect/jsonrpc-ws-connection@1.0.16':
+ dependencies:
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/safe-json': 1.0.2
+ events: 3.3.0
+ ws: 7.5.13
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
+ '@walletconnect/keyvaluestorage@1.1.1':
+ dependencies:
+ '@walletconnect/safe-json': 1.0.2
+ idb-keyval: 6.3.0
+ unstorage: 1.17.5(idb-keyval@6.3.0)
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - ioredis
+ - uploadthing
+
+ '@walletconnect/logger@3.0.2':
+ dependencies:
+ '@walletconnect/safe-json': 1.0.2
+ pino: 10.0.0
+
+ '@walletconnect/relay-api@1.0.11':
+ dependencies:
+ '@walletconnect/jsonrpc-types': 1.0.4
+
+ '@walletconnect/relay-auth@1.1.0':
+ dependencies:
+ '@noble/curves': 1.8.0
+ '@noble/hashes': 1.7.0
+ '@walletconnect/safe-json': 1.0.2
+ '@walletconnect/time': 1.0.2
+ uint8arrays: 3.1.1
+
+ '@walletconnect/safe-json@1.0.2':
+ dependencies:
+ tslib: 1.14.1
+
+ '@walletconnect/sign-client@2.23.10(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@walletconnect/core': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/logger': 3.0.2
+ '@walletconnect/time': 1.0.2
+ '@walletconnect/types': 2.23.10
+ '@walletconnect/utils': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - ioredis
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/sign-client@2.23.7(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@walletconnect/core': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/events': 1.0.1
+ '@walletconnect/heartbeat': 1.2.2
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/logger': 3.0.2
+ '@walletconnect/time': 1.0.2
+ '@walletconnect/types': 2.23.7
+ '@walletconnect/utils': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - ioredis
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/time@1.0.2':
+ dependencies:
+ tslib: 1.14.1
+
+ '@walletconnect/types@2.23.10':
+ dependencies:
+ '@walletconnect/events': 1.0.1
+ '@walletconnect/heartbeat': 1.2.2
+ '@walletconnect/jsonrpc-types': 1.0.4
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.2
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - ioredis
+ - uploadthing
+
+ '@walletconnect/types@2.23.7':
+ dependencies:
+ '@walletconnect/events': 1.0.1
+ '@walletconnect/heartbeat': 1.2.2
+ '@walletconnect/jsonrpc-types': 1.0.4
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.2
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - ioredis
+ - uploadthing
+
+ '@walletconnect/universal-provider@2.23.10(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@walletconnect/events': 1.0.1
+ '@walletconnect/jsonrpc-http-connection': 1.0.8
+ '@walletconnect/jsonrpc-provider': 1.0.14
+ '@walletconnect/jsonrpc-types': 1.0.4
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.2
+ '@walletconnect/sign-client': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/types': 2.23.10
+ '@walletconnect/utils': 2.23.10(typescript@5.9.3)(zod@3.25.76)
+ es-toolkit: 1.45.1
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - encoding
+ - ioredis
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/universal-provider@2.23.7(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@walletconnect/events': 1.0.1
+ '@walletconnect/jsonrpc-http-connection': 1.0.8
+ '@walletconnect/jsonrpc-provider': 1.0.14
+ '@walletconnect/jsonrpc-types': 1.0.4
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.2
+ '@walletconnect/sign-client': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ '@walletconnect/types': 2.23.7
+ '@walletconnect/utils': 2.23.7(typescript@5.9.3)(zod@3.25.76)
+ es-toolkit: 1.44.0
+ events: 3.3.0
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - bufferutil
+ - db0
+ - encoding
+ - ioredis
+ - typescript
+ - uploadthing
+ - utf-8-validate
+ - zod
+
+ '@walletconnect/utils@2.23.10(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@msgpack/msgpack': 3.1.3
+ '@noble/ciphers': 1.3.0
+ '@noble/curves': 1.9.7
+ '@noble/hashes': 1.8.0
+ '@scure/base': 1.2.6
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.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.23.10
+ '@walletconnect/window-getters': 1.0.1
+ '@walletconnect/window-metadata': 1.0.1
+ blakejs: 1.2.1
+ detect-browser: 5.3.0
+ ox: 0.9.3(typescript@5.9.3)(zod@3.25.76)
+ uint8arrays: 3.1.1
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - ioredis
+ - typescript
+ - uploadthing
+ - zod
+
+ '@walletconnect/utils@2.23.7(typescript@5.9.3)(zod@3.25.76)':
+ dependencies:
+ '@msgpack/msgpack': 3.1.3
+ '@noble/ciphers': 1.3.0
+ '@noble/curves': 1.9.7
+ '@noble/hashes': 1.8.0
+ '@scure/base': 1.2.6
+ '@walletconnect/jsonrpc-utils': 1.0.8
+ '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/logger': 3.0.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.23.7
+ '@walletconnect/window-getters': 1.0.1
+ '@walletconnect/window-metadata': 1.0.1
+ blakejs: 1.2.1
+ detect-browser: 5.3.0
+ ox: 0.9.3(typescript@5.9.3)(zod@3.25.76)
+ uint8arrays: 3.1.1
+ transitivePeerDependencies:
+ - '@azure/app-configuration'
+ - '@azure/cosmos'
+ - '@azure/data-tables'
+ - '@azure/identity'
+ - '@azure/keyvault-secrets'
+ - '@azure/storage-blob'
+ - '@capacitor/preferences'
+ - '@deno/kv'
+ - '@netlify/blobs'
+ - '@planetscale/database'
+ - '@react-native-async-storage/async-storage'
+ - '@upstash/redis'
+ - '@vercel/blob'
+ - '@vercel/functions'
+ - '@vercel/kv'
+ - aws4fetch
+ - db0
+ - ioredis
+ - typescript
+ - uploadthing
+ - zod
+
+ '@walletconnect/window-getters@1.0.1':
+ dependencies:
+ tslib: 1.14.1
+
+ '@walletconnect/window-metadata@1.0.1':
+ dependencies:
+ '@walletconnect/window-getters': 1.0.1
+ tslib: 1.14.1
+
+ abi-wan-kanabi@2.2.4:
+ dependencies:
+ ansicolors: 0.3.2
+ cardinal: 2.1.1
+ fs-extra: 10.1.0
+ yargs: 17.7.3
+
+ abitype@1.0.6(typescript@5.9.3)(zod@3.25.76):
+ optionalDependencies:
+ typescript: 5.9.3
+ zod: 3.25.76
+ optional: true
+
+ abitype@1.2.3(typescript@5.9.3)(zod@3.22.4):
+ optionalDependencies:
+ typescript: 5.9.3
+ zod: 3.22.4
+
+ abitype@1.2.3(typescript@5.9.3)(zod@3.25.76):
+ optionalDependencies:
+ typescript: 5.9.3
+ zod: 3.25.76
+
+ abitype@1.3.0(typescript@5.9.3)(zod@3.25.76):
+ optionalDependencies:
+ typescript: 5.9.3
+ zod: 3.25.76
+
+ aes-js@4.0.0-beta.5: {}
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ ansicolors@0.3.2: {}
+
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.2
+
+ asn1js@3.0.10:
+ dependencies:
+ pvtsutils: 1.3.6
+ pvutils: 1.1.5
+ tslib: 2.8.1
+
+ assertion-error@2.0.1: {}
+
+ async-mutex@0.5.0:
+ dependencies:
+ tslib: 2.8.1
+
+ asynckit@0.4.0:
+ optional: true
+
+ atomic-sleep@1.0.0: {}
+
+ axios-retry@4.5.0(axios@1.16.0):
+ dependencies:
+ axios: 1.16.0
+ is-retry-allowed: 2.2.0
+ optional: true
+
+ axios@1.16.0:
+ dependencies:
+ follow-redirects: 1.16.0
+ form-data: 4.0.6
+ proxy-from-env: 2.1.0
+ transitivePeerDependencies:
+ - debug
+ optional: true
+
+ base-x@5.0.1: {}
+
+ base64-js@1.5.1: {}
+
+ baseline-browser-mapping@2.11.9: {}
+
+ big.js@6.2.2: {}
+
+ blakejs@1.2.1: {}
+
+ borsh@2.0.0: {}
+
+ browserslist@4.28.7:
+ dependencies:
+ baseline-browser-mapping: 2.11.9
+ caniuse-lite: 1.0.30001806
+ electron-to-chromium: 1.5.399
+ node-releases: 2.0.51
+ update-browserslist-db: 1.2.3(browserslist@4.28.7)
+
+ bs58@6.0.0:
+ dependencies:
+ base-x: 5.0.1
+
+ bs58check@4.0.0:
+ dependencies:
+ '@noble/hashes': 1.8.0
+ bs58: 6.0.0
+
+ buffer@6.0.3:
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+
+ bundle-name@4.1.0:
+ dependencies:
+ run-applescript: 7.1.0
+
+ cac@6.7.14: {}
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ optional: true
+
+ camelcase@5.3.1: {}
+
+ caniuse-lite@1.0.30001806: {}
+
+ cardinal@2.1.1:
+ dependencies:
+ ansicolors: 0.3.2
+ redeyed: 2.1.1
+
+ cbor-extract@2.2.2:
+ dependencies:
+ node-gyp-build-optional-packages: 5.1.1
+ optionalDependencies:
+ '@cbor-extract/cbor-extract-darwin-arm64': 2.2.2
+ '@cbor-extract/cbor-extract-darwin-x64': 2.2.2
+ '@cbor-extract/cbor-extract-linux-arm': 2.2.2
+ '@cbor-extract/cbor-extract-linux-arm64': 2.2.2
+ '@cbor-extract/cbor-extract-linux-x64': 2.2.2
+ '@cbor-extract/cbor-extract-win32-x64': 2.2.2
+ optional: true
+
+ cbor-js@0.1.0: {}
+
+ cbor-x@1.6.5:
+ optionalDependencies:
+ cbor-extract: 2.2.2
+
+ chai@5.3.3:
+ dependencies:
+ assertion-error: 2.0.1
+ check-error: 2.1.3
+ deep-eql: 5.0.2
+ loupe: 3.2.1
+ pathval: 2.0.1
+
+ chalk@5.6.2:
+ optional: true
+
+ charenc@0.0.2:
+ optional: true
+
+ check-error@2.1.3: {}
+
+ chokidar@5.0.0:
+ dependencies:
+ readdirp: 5.0.0
+
+ cliui@6.0.0:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 6.2.0
+
+ cliui@8.0.1:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
+ clsx@1.2.1:
+ optional: true
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+ optional: true
+
+ commander@14.0.2:
+ optional: true
+
+ convert-source-map@2.0.0: {}
+
+ cookie-es@1.2.3: {}
+
+ cross-fetch@3.2.0:
+ dependencies:
+ node-fetch: 2.7.0
+ transitivePeerDependencies:
+ - encoding
+
+ crossws@0.3.5:
+ dependencies:
+ uncrypto: 0.1.3
+
+ crypt@0.0.2:
+ optional: true
+
+ csstype@3.2.3: {}
+
+ dayjs@1.11.13: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ decamelize@1.2.0: {}
+
+ deep-eql@5.0.2: {}
+
+ default-browser-id@5.0.1: {}
+
+ default-browser@5.5.0:
+ dependencies:
+ bundle-name: 4.1.0
+ default-browser-id: 5.0.1
+
+ define-lazy-prop@3.0.0: {}
+
+ defu@6.1.7: {}
+
+ delayed-stream@1.0.0:
+ optional: true
+
+ destr@2.0.5: {}
+
+ detect-browser@5.3.0: {}
+
+ detect-libc@2.1.2:
+ optional: true
+
+ dijkstrajs@1.0.3: {}
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+ optional: true
+
+ electron-to-chromium@1.5.399: {}
+
+ emoji-regex@8.0.0: {}
+
+ encode-utf8@1.0.3: {}
+
+ es-define-property@1.0.1:
+ optional: true
+
+ es-errors@1.3.0:
+ optional: true
+
+ es-module-lexer@1.7.0: {}
+
+ es-object-atoms@1.1.2:
+ dependencies:
+ es-errors: 1.3.0
+ optional: true
+
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.4
+ optional: true
+
+ es-toolkit@1.44.0: {}
+
+ es-toolkit@1.45.1: {}
+
+ esbuild@0.21.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+
+ escalade@3.2.0: {}
+
+ esprima@4.0.1: {}
+
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.9
+
+ ethers@6.17.0:
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.1
+ '@noble/curves': 1.2.0
+ '@noble/hashes': 1.3.2
+ '@types/node': 22.7.5
+ aes-js: 4.0.0-beta.5
+ tslib: 2.7.0
+ ws: 8.21.0
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
+ eventemitter3@5.0.1: {}
+
+ eventemitter3@5.0.4: {}
+
+ events@3.3.0: {}
+
+ expect-type@1.4.0: {}
+
+ fdir@6.5.0(picomatch@4.0.5):
+ optionalDependencies:
+ picomatch: 4.0.5
+
+ find-up@4.1.0:
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+
+ follow-redirects@1.16.0:
+ optional: true
+
+ form-data@4.0.6:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.4
+ mime-types: 2.1.35
+ optional: true
+
+ fs-extra@10.1.0:
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 6.2.1
+ universalify: 2.0.1
+
+ fsevents@2.3.2:
+ optional: true
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ get-caller-file@2.0.5: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.2
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.4
+ math-intrinsics: 1.1.0
+ optional: true
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.2
+ optional: true
+
+ get-starknet-core@4.0.0:
+ dependencies:
+ '@starknet-io/types-js': 0.7.10
+
+ gopd@1.2.0:
+ optional: true
+
+ graceful-fs@4.2.11: {}
+
+ h3@1.15.11:
+ dependencies:
+ cookie-es: 1.2.3
+ crossws: 0.3.5
+ defu: 6.1.7
+ destr: 2.0.5
+ iron-webcrypto: 1.2.1
+ node-mock-http: 1.0.5
+ radix3: 1.1.2
+ ufo: 1.6.4
+ uncrypto: 0.1.3
+
+ has-symbols@1.1.0:
+ optional: true
+
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+ optional: true
+
+ hasown@2.0.4:
+ dependencies:
+ function-bind: 1.1.2
+ optional: true
+
+ hpke-js@1.8.0:
+ dependencies:
+ '@hpke/chacha20poly1305': 1.8.0
+ '@hpke/common': 1.10.1
+ '@hpke/core': 1.9.0
+ '@hpke/dhkem-x25519': 1.8.0
+ '@hpke/dhkem-x448': 1.8.0
+
+ idb-keyval@6.2.1:
+ optional: true
+
+ idb-keyval@6.3.0: {}
+
+ ieee754@1.2.1: {}
+
+ iron-webcrypto@1.2.1: {}
+
+ is-buffer@1.1.6:
+ optional: true
+
+ is-docker@3.0.0: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-inside-container@1.0.0:
+ dependencies:
+ is-docker: 3.0.0
+
+ is-retry-allowed@2.2.0:
+ optional: true
+
+ is-wsl@3.1.1:
+ dependencies:
+ is-inside-container: 1.0.0
+
+ isows@1.0.7(ws@8.21.0):
+ dependencies:
+ ws: 8.21.0
+
+ jose@6.2.6:
+ optional: true
+
+ js-tokens@4.0.0: {}
+
+ js-tokens@9.0.1: {}
+
+ jsesc@3.1.0: {}
+
+ json5@2.2.3: {}
+
+ jsonfile@6.2.1:
+ dependencies:
+ universalify: 2.0.1
+ optionalDependencies:
+ graceful-fs: 4.2.11
+
+ keyvaluestorage-interface@1.0.0: {}
+
+ lit-element@4.2.2:
+ dependencies:
+ '@lit-labs/ssr-dom-shim': 1.6.0
+ '@lit/reactive-element': 2.1.2
+ lit-html: 3.3.3
+
+ lit-html@3.3.3:
+ dependencies:
+ '@types/trusted-types': 2.0.7
+
+ lit@3.3.0:
+ dependencies:
+ '@lit/reactive-element': 2.1.2
+ lit-element: 4.2.2
+ lit-html: 3.3.3
+
+ locate-path@5.0.0:
+ dependencies:
+ p-locate: 4.1.0
+
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
+ lossless-json@4.3.1: {}
+
+ loupe@3.2.1: {}
+
+ lru-cache@11.5.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ math-intrinsics@1.1.0:
+ optional: true
+
+ md5@2.3.0:
+ dependencies:
+ charenc: 0.0.2
+ crypt: 0.0.2
+ is-buffer: 1.1.6
+ optional: true
+
+ micro-packed@0.7.3:
+ dependencies:
+ '@scure/base': 1.2.6
+
+ micro-sol-signer@0.5.0:
+ dependencies:
+ '@noble/curves': 1.9.7
+ '@noble/hashes': 1.8.0
+ '@scure/base': 1.2.6
+ micro-packed: 0.7.3
+
+ mime-db@1.52.0:
+ optional: true
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+ optional: true
+
+ mipd@0.0.7(typescript@5.9.3):
+ optionalDependencies:
+ typescript: 5.9.3
+
+ ms@2.1.3: {}
+
+ multiformats@9.9.0: {}
+
+ nanoid@3.3.16: {}
+
+ node-fetch-native@1.6.7: {}
+
+ node-fetch@2.7.0:
+ dependencies:
+ whatwg-url: 5.0.0
+
+ node-gyp-build-optional-packages@5.1.1:
+ dependencies:
+ detect-libc: 2.1.2
+ optional: true
+
+ node-mock-http@1.0.5: {}
+
+ node-releases@2.0.51: {}
+
+ normalize-path@3.0.0: {}
+
+ ofetch@1.5.1:
+ dependencies:
+ destr: 2.0.5
+ node-fetch-native: 1.6.7
+ ufo: 1.6.4
+
+ on-exit-leak-free@2.1.2: {}
+
+ open@10.2.0:
+ dependencies:
+ default-browser: 5.5.0
+ define-lazy-prop: 3.0.0
+ is-inside-container: 1.0.0
+ wsl-utils: 0.1.0
+
+ ox@0.14.33(typescript@5.9.3)(zod@3.22.4):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.1
+ '@noble/ciphers': 1.3.0
+ '@noble/curves': 1.9.1
+ '@noble/hashes': 1.8.0
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.2.3(typescript@5.9.3)(zod@3.22.4)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - zod
+
+ ox@0.14.33(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.1
+ '@noble/ciphers': 1.3.0
+ '@noble/curves': 1.9.1
+ '@noble/hashes': 1.8.0
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - zod
+
+ ox@0.4.4(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.1
+ '@noble/curves': 1.7.0
+ '@noble/hashes': 1.6.1
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.3.0(typescript@5.9.3)(zod@3.25.76)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - zod
+
+ ox@0.6.9(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.1
+ '@noble/curves': 1.9.7
+ '@noble/hashes': 1.8.0
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.3.0(typescript@5.9.3)(zod@3.25.76)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - zod
+ optional: true
+
+ ox@0.9.3(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ '@adraffy/ens-normalize': 1.11.1
+ '@noble/ciphers': 1.3.0
+ '@noble/curves': 1.9.1
+ '@noble/hashes': 1.8.0
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.3.0(typescript@5.9.3)(zod@3.25.76)
+ eventemitter3: 5.0.1
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - zod
+
+ p-limit@2.3.0:
+ dependencies:
+ p-try: 2.2.0
+
+ p-locate@4.1.0:
+ dependencies:
+ p-limit: 2.3.0
+
+ p-try@2.2.0: {}
+
+ pako@2.2.0: {}
+
+ path-exists@4.0.0: {}
+
+ pathe@2.0.3: {}
+
+ pathval@2.0.1: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.2: {}
+
+ picomatch@4.0.5: {}
+
+ pino-abstract-transport@2.0.0:
+ dependencies:
+ split2: 4.2.0
+
+ pino-std-serializers@7.1.0: {}
+
+ pino@10.0.0:
+ dependencies:
+ atomic-sleep: 1.0.0
+ on-exit-leak-free: 2.1.2
+ pino-abstract-transport: 2.0.0
+ pino-std-serializers: 7.1.0
+ process-warning: 5.1.0
+ quick-format-unescaped: 4.0.4
+ real-require: 0.2.0
+ safe-stable-stringify: 2.5.0
+ slow-redact: 0.3.2
+ sonic-boom: 4.2.1
+ thread-stream: 3.2.0
+
+ playwright-core@1.62.1: {}
+
+ playwright@1.62.1:
+ dependencies:
+ playwright-core: 1.62.1
+ optionalDependencies:
+ fsevents: 2.3.2
+
+ pngjs@5.0.0: {}
+
+ postcss@8.5.25:
+ dependencies:
+ nanoid: 3.3.16
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ preact@10.24.2:
+ optional: true
+
+ process-warning@5.1.0: {}
+
+ proxy-compare@3.0.1: {}
+
+ proxy-from-env@2.1.0:
+ optional: true
+
+ pvtsutils@1.3.6:
+ dependencies:
+ tslib: 2.8.1
+
+ pvutils@1.1.5: {}
+
+ qrcode@1.5.3:
+ dependencies:
+ dijkstrajs: 1.0.3
+ encode-utf8: 1.0.3
+ pngjs: 5.0.0
+ yargs: 15.4.1
+
+ quick-format-unescaped@4.0.4: {}
+
+ radix3@1.1.2: {}
+
+ react-dom@18.3.1(react@18.3.1):
+ dependencies:
+ loose-envify: 1.4.0
+ react: 18.3.1
+ scheduler: 0.23.2
+
+ react-refresh@0.17.0: {}
+
+ react@18.3.1:
+ dependencies:
+ loose-envify: 1.4.0
+
+ readdirp@5.0.0: {}
+
+ real-require@0.2.0: {}
+
+ redeyed@2.1.1:
+ dependencies:
+ esprima: 4.0.1
+
+ reflect-metadata@0.2.2: {}
+
+ require-directory@2.1.1: {}
+
+ require-main-filename@2.0.0: {}
+
+ rollup@4.62.3:
+ dependencies:
+ '@types/estree': 1.0.9
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.62.3
+ '@rollup/rollup-android-arm64': 4.62.3
+ '@rollup/rollup-darwin-arm64': 4.62.3
+ '@rollup/rollup-darwin-x64': 4.62.3
+ '@rollup/rollup-freebsd-arm64': 4.62.3
+ '@rollup/rollup-freebsd-x64': 4.62.3
+ '@rollup/rollup-linux-arm-gnueabihf': 4.62.3
+ '@rollup/rollup-linux-arm-musleabihf': 4.62.3
+ '@rollup/rollup-linux-arm64-gnu': 4.62.3
+ '@rollup/rollup-linux-arm64-musl': 4.62.3
+ '@rollup/rollup-linux-loong64-gnu': 4.62.3
+ '@rollup/rollup-linux-loong64-musl': 4.62.3
+ '@rollup/rollup-linux-ppc64-gnu': 4.62.3
+ '@rollup/rollup-linux-ppc64-musl': 4.62.3
+ '@rollup/rollup-linux-riscv64-gnu': 4.62.3
+ '@rollup/rollup-linux-riscv64-musl': 4.62.3
+ '@rollup/rollup-linux-s390x-gnu': 4.62.3
+ '@rollup/rollup-linux-x64-gnu': 4.62.3
+ '@rollup/rollup-linux-x64-musl': 4.62.3
+ '@rollup/rollup-openbsd-x64': 4.62.3
+ '@rollup/rollup-openharmony-arm64': 4.62.3
+ '@rollup/rollup-win32-arm64-msvc': 4.62.3
+ '@rollup/rollup-win32-ia32-msvc': 4.62.3
+ '@rollup/rollup-win32-x64-gnu': 4.62.3
+ '@rollup/rollup-win32-x64-msvc': 4.62.3
+ fsevents: 2.3.3
+
+ run-applescript@7.1.0: {}
+
+ safe-stable-stringify@2.5.0: {}
+
+ scheduler@0.23.2:
+ dependencies:
+ loose-envify: 1.4.0
+
+ semver@6.3.1: {}
+
+ semver@7.7.2: {}
+
+ set-blocking@2.0.0: {}
+
+ sha256-uint8array@0.10.7: {}
+
+ siginfo@2.0.0: {}
+
+ slow-redact@0.3.2: {}
+
+ sonic-boom@4.2.1:
+ dependencies:
+ atomic-sleep: 1.0.0
+
+ source-map-js@1.2.1: {}
+
+ split2@4.2.0: {}
+
+ stackback@0.0.2: {}
+
+ starknet@8.9.2:
+ dependencies:
+ '@noble/curves': 1.7.0
+ '@noble/hashes': 1.6.1
+ '@scure/base': 1.2.6
+ '@scure/starknet': 1.1.0
+ '@starknet-io/starknet-types-08': '@starknet-io/types-js@0.8.4'
+ '@starknet-io/starknet-types-09': '@starknet-io/types-js@0.9.2'
+ abi-wan-kanabi: 2.2.4
+ lossless-json: 4.3.1
+ pako: 2.2.0
+ ts-mixer: 6.0.4
+
+ starknet@9.4.2(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ '@noble/curves': 1.7.0
+ '@noble/hashes': 1.6.1
+ '@scure/base': 1.2.6
+ '@scure/starknet': 1.1.0
+ '@starknet-io/get-starknet-wallet-standard': 5.0.0(typescript@5.9.3)(zod@3.25.76)
+ '@starknet-io/starknet-types-010': '@starknet-io/types-js@0.10.0'
+ '@starknet-io/starknet-types-09': '@starknet-io/types-js@0.9.2'
+ abi-wan-kanabi: 2.2.4
+ lossless-json: 4.3.1
+ pako: 2.2.0
+ ts-mixer: 6.0.4
+ transitivePeerDependencies:
+ - typescript
+ - zod
+
+ std-env@3.10.0: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-literal@3.1.0:
+ dependencies:
+ js-tokens: 9.0.1
+
+ thread-stream@3.2.0:
+ dependencies:
+ real-require: 0.2.0
+
+ tinybench@2.9.0: {}
+
+ tinyexec@0.3.2: {}
+
+ tinyglobby@0.2.17:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.5)
+ picomatch: 4.0.5
+
+ tinypool@1.1.1: {}
+
+ tinyrainbow@2.0.0: {}
+
+ tinyspy@4.0.4: {}
+
+ tr46@0.0.3: {}
+
+ ts-mixer@6.0.4: {}
+
+ tslib@1.14.1: {}
+
+ tslib@2.7.0: {}
+
+ tslib@2.8.1: {}
+
+ tsyringe@4.10.0:
+ dependencies:
+ tslib: 1.14.1
+
+ typescript@5.9.3: {}
+
+ ufo@1.6.4: {}
+
+ uint8arrays@3.1.1:
+ dependencies:
+ multiformats: 9.9.0
+
+ uncrypto@0.1.3: {}
+
+ undici-types@6.19.8: {}
+
+ undici-types@7.29.0:
+ optional: true
+
+ universalify@2.0.1: {}
+
+ unstorage@1.17.5(idb-keyval@6.3.0):
+ dependencies:
+ anymatch: 3.1.3
+ chokidar: 5.0.0
+ destr: 2.0.5
+ h3: 1.15.11
+ lru-cache: 11.5.2
+ node-fetch-native: 1.6.7
+ ofetch: 1.5.1
+ ufo: 1.6.4
+ optionalDependencies:
+ idb-keyval: 6.3.0
+
+ update-browserslist-db@1.2.3(browserslist@4.28.7):
+ dependencies:
+ browserslist: 4.28.7
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ valtio@2.1.7(@types/react@18.3.31)(react@18.3.1):
+ dependencies:
+ proxy-compare: 3.0.1
+ optionalDependencies:
+ '@types/react': 18.3.31
+ react: 18.3.1
+
+ viem@2.55.10(typescript@5.9.3)(zod@3.22.4):
+ dependencies:
+ '@noble/curves': 1.9.1
+ '@noble/hashes': 1.8.0
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.2.3(typescript@5.9.3)(zod@3.22.4)
+ isows: 1.0.7(ws@8.21.0)
+ ox: 0.14.33(typescript@5.9.3)(zod@3.22.4)
+ ws: 8.21.0
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+ - zod
+
+ viem@2.55.10(typescript@5.9.3)(zod@3.25.76):
+ dependencies:
+ '@noble/curves': 1.9.1
+ '@noble/hashes': 1.8.0
+ '@scure/bip32': 1.7.0
+ '@scure/bip39': 1.6.0
+ abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76)
+ isows: 1.0.7(ws@8.21.0)
+ ox: 0.14.33(typescript@5.9.3)(zod@3.25.76)
+ ws: 8.21.0
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+ - zod
+
+ vite-node@3.2.4(@types/node@22.7.5):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.4.3
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 5.4.21(@types/node@22.7.5)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
+ vite@5.4.21(@types/node@22.7.5):
+ dependencies:
+ esbuild: 0.21.5
+ postcss: 8.5.25
+ rollup: 4.62.3
+ optionalDependencies:
+ '@types/node': 22.7.5
+ fsevents: 2.3.3
+
+ vitest@3.2.7(@types/node@22.7.5):
+ dependencies:
+ '@types/chai': 5.2.3
+ '@vitest/expect': 3.2.7
+ '@vitest/mocker': 3.2.7(vite@5.4.21(@types/node@22.7.5))
+ '@vitest/pretty-format': 3.2.7
+ '@vitest/runner': 3.2.7
+ '@vitest/snapshot': 3.2.7
+ '@vitest/spy': 3.2.7
+ '@vitest/utils': 3.2.7
+ chai: 5.3.3
+ debug: 4.4.3
+ expect-type: 1.4.0
+ magic-string: 0.30.21
+ pathe: 2.0.3
+ picomatch: 4.0.5
+ std-env: 3.10.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.17
+ tinypool: 1.1.1
+ tinyrainbow: 2.0.0
+ vite: 5.4.21(@types/node@22.7.5)
+ vite-node: 3.2.4(@types/node@22.7.5)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 22.7.5
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
+ webidl-conversions@3.0.1: {}
+
+ whatwg-url@5.0.0:
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+
+ which-module@2.0.1: {}
+
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
+ wrap-ansi@6.2.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ ws@7.5.13: {}
+
+ ws@8.21.0: {}
+
+ ws@8.21.1:
+ optional: true
+
+ wsl-utils@0.1.0:
+ dependencies:
+ is-wsl: 3.1.1
+
+ y18n@4.0.3: {}
+
+ y18n@5.0.8: {}
+
+ yallist@3.1.1: {}
+
+ yargs-parser@18.1.3:
+ dependencies:
+ camelcase: 5.3.1
+ decamelize: 1.2.0
+
+ yargs-parser@21.1.1: {}
+
+ yargs@15.4.1:
+ dependencies:
+ cliui: 6.0.0
+ decamelize: 1.2.0
+ find-up: 4.1.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ require-main-filename: 2.0.0
+ set-blocking: 2.0.0
+ string-width: 4.2.3
+ which-module: 2.0.1
+ y18n: 4.0.3
+ yargs-parser: 18.1.3
+
+ yargs@17.7.3:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
+ zod@3.22.4: {}
+
+ zod@3.25.76: {}
+
+ zustand@5.0.3(@types/react@18.3.31)(react@18.3.1):
+ optionalDependencies:
+ '@types/react': 18.3.31
+ react: 18.3.1
+ optional: true
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..a40b32c
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,3 @@
+packages:
+ - sdk
+ - app
diff --git a/scripts/gen-tables.mjs b/scripts/gen-tables.mjs
new file mode 100644
index 0000000..cb66163
--- /dev/null
+++ b/scripts/gen-tables.mjs
@@ -0,0 +1,79 @@
+#!/usr/bin/env node
+// Regenerates sdk/src/tables.ts from src/beast_definitions.cairo.
+//
+// The name tables are the one part of the SDK that genuinely duplicates
+// contract data, so they are generated rather than transcribed: a hand-copied
+// list of 75 species drifts silently, and a wrong species name is a wrong NFT.
+//
+// Tiers and types are NOT generated — they are formulas (see sdk/src/species.ts),
+// and the SDK's tests pin them against the contract's own test anchors.
+
+import { readFileSync, writeFileSync } from 'node:fs';
+import { dirname, join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const root = join(dirname(fileURLToPath(import.meta.url)), '..');
+const source = readFileSync(join(root, 'src/beast_definitions.cairo'), 'utf8');
+
+/**
+ * Each table is an if/else chain of short-string literals in contract order,
+ * with a fallback literal at the end that is not a real entry.
+ */
+function extractTable(fnName, expected) {
+ const start = source.indexOf(`pub fn ${fnName}(`);
+ if (start === -1) throw new Error(`could not find ${fnName}`);
+
+ // Run to the next top-level `pub fn`, or the end of the file.
+ const next = source.indexOf('\npub fn ', start + 1);
+ const body = source.slice(start, next === -1 ? undefined : next);
+
+ const names = [...body.matchAll(/^\s*'([^']*)'/gm)].map((m) => m[1]);
+ const entries = names.slice(0, expected);
+
+ if (entries.length !== expected) {
+ throw new Error(`${fnName}: expected ${expected} entries, found ${entries.length}`);
+ }
+ if (entries.some((n) => n.length === 0)) {
+ throw new Error(`${fnName}: found an empty entry — the parse is misaligned`);
+ }
+ return entries;
+}
+
+const names = extractTable('get_beast_name', 75);
+const prefixes = extractTable('get_prefix', 69);
+const suffixes = extractTable('get_suffix', 18);
+
+const block = (arr, perLine = 5) => {
+ const lines = [];
+ for (let i = 0; i < arr.length; i += perLine) {
+ lines.push(' ' + arr.slice(i, i + perLine).map((x) => `'${x}',`).join(' '));
+ }
+ return lines.join('\n');
+};
+
+const output = `// GENERATED from src/beast_definitions.cairo — do not edit by hand.
+// Regenerate with \`node scripts/gen-tables.mjs\` from the repo root.
+//
+// Index 0 of each array is species/affix 1: the contract numbers these from
+// 1, and 0 means "absent" for affixes.
+
+/** The 75 genesis species, in contract order (index 0 === species 1). */
+export const GENESIS_SPECIES_NAMES: readonly string[] = [
+${block(names)}
+] as const;
+
+/** Name prefixes 1-69. Shared by every species, genesis and community. */
+export const PREFIX_NAMES: readonly string[] = [
+${block(prefixes)}
+] as const;
+
+/** Name suffixes 1-18. Shared by every species, genesis and community. */
+export const SUFFIX_NAMES: readonly string[] = [
+${block(suffixes)}
+] as const;
+`;
+
+writeFileSync(join(root, 'sdk/src/tables.ts'), output);
+console.log(
+ `Wrote sdk/src/tables.ts: ${names.length} species, ${prefixes.length} prefixes, ${suffixes.length} suffixes`,
+);
diff --git a/sdk/.gitignore b/sdk/.gitignore
new file mode 100644
index 0000000..1eae0cf
--- /dev/null
+++ b/sdk/.gitignore
@@ -0,0 +1,2 @@
+dist/
+node_modules/
diff --git a/sdk/README.md b/sdk/README.md
new file mode 100644
index 0000000..3f9c4f3
--- /dev/null
+++ b/sdk/README.md
@@ -0,0 +1,108 @@
+# @provable-games/beasts-sdk
+
+TypeScript SDK for the Beasts onchain bestiary.
+
+```bash
+pnpm add @provable-games/beasts-sdk starknet
+```
+
+## Everything static is offline
+
+A Beast's token ID *is* the Beast. The 116-bit layout encodes species, affixes,
+level, health, tier, type, and the shiny/animated flags, so the full static
+profile is recoverable without touching a node:
+
+```ts
+import { decodeTokenId, beastPower, fullBeastName } from '@provable-games/beasts-sdk';
+
+const beast = decodeTokenId('0x2e0064000a081000000000000004c');
+// { id: 76n, prefix: 1, suffix: 1, level: 10, health: 100,
+// shiny: 0, animated: 1, tier: 3, beastType: 1 }
+
+beastPower(beast); // 30 — level * (6 - tier)
+```
+
+Only two things need a chain read, and both cache per species: the **name** and
+the **art** of community species. Genesis species (1–75) resolve entirely
+offline:
+
+```ts
+import { genesisSpecies, fullBeastName, decodeTokenId } from '@provable-games/beasts-sdk';
+
+genesisSpecies(1n); // { name: 'Warlock', tier: 1, beastType: 0 }
+fullBeastName(decodeTokenId(genesisWarlockTokenId)); // 'Warlock'
+fullBeastName(communityBeast, 'Gloomfang'); // '"Agony Bane" Gloomfang'
+```
+
+## Genesis Beasts are derived, not flagged
+
+There is no genesis bit. The `(id, 0, 0)` affix slot is reserved as each
+species' Genesis Beast — the artist's provenance token — so `isGenesis` is just
+`prefix === 0 && suffix === 0`. Every other mint requires both affixes, which is
+what caps a species at exactly 1,243.
+
+## Validation mirrors the contract
+
+`validateSpeciesName`, `validateRenderableArt`, `validateFactoryArt` and
+`validateArtSet` reproduce the contract's guards so a UI can fail fast instead
+of failing a transaction. They are a convenience, never the security boundary —
+the contract re-checks everything and is the only thing that decides what is
+valid.
+
+The name charset is an injection guard, not a style rule: the contract's JSON
+and SVG builders embed names unescaped. Names are deliberately **not** unique —
+requiring uniqueness would let anyone squat the good ones.
+
+## Finding what a wallet controls
+
+```ts
+await client.getSpeciesByArtist(address); // [77n, 78n]
+await client.getOwnedSpecies(address); // + definition and Genesis token ID
+```
+
+**The artist role is not stored anywhere — it *is* ownership of the species'
+Genesis Beast.** So this walks the wallet's tokens through the collection's
+`token_of_owner_by_index`, decodes each ID locally, and keeps the ones with no
+affixes. No registry reads, no event scanning: a token ID already carries its
+species.
+
+Transferring a species is therefore an ordinary ERC721 transfer
+(`transferGenesisBeastCall`), and a marketplace sale does the same thing.
+
+## Reads and calls
+
+`BeastsClient` returns `Call` objects rather than sending them, so the caller
+decides how to sign — a wallet popup, a session, or a multicall batching several
+changes into one transaction.
+
+```ts
+import { BeastsClient, BeastType, SEPOLIA_ADDRESSES } from '@provable-games/beasts-sdk';
+import { RpcProvider } from 'starknet';
+
+const client = new BeastsClient(new RpcProvider({ nodeUrl }), SEPOLIA_ADDRESSES, account);
+
+await client.execute(
+ client.registerWithArtCall({
+ name: 'Gloomfang',
+ beastType: BeastType.Hunter,
+ tier: 3,
+ minter: dungeonAddress, // '0x0' registers paused
+ art: { pngRegular, pngShiny, gifRegular, gifShiny },
+ }),
+);
+```
+
+## Tests
+
+```bash
+pnpm test # unit tests, no network
+pnpm test:live # additionally reads the Sepolia deployment
+```
+
+The unit tests are anchored on two token IDs produced by the deployed contract,
+not by this SDK, so a layout drift between Cairo and TypeScript fails the suite.
+The live tests prove the client's calldata and ABI decoding match the deployed
+contracts — something fixtures cannot.
+
+`src/tables.ts` is generated from `src/beast_definitions.cairo`; regenerate with
+`node scripts/gen-tables.mjs` from the repo root rather than editing it.
diff --git a/sdk/package.json b/sdk/package.json
new file mode 100644
index 0000000..a7121d1
--- /dev/null
+++ b/sdk/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@provable-games/beasts-sdk",
+ "version": "0.1.0",
+ "description": "TypeScript SDK for the Beasts onchain bestiary: token ID codec, species resolution, and the permissionless registry.",
+ "type": "module",
+ "main": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ }
+ },
+ "files": ["dist"],
+ "scripts": {
+ "build": "tsc -p tsconfig.build.json",
+ "typecheck": "tsc --noEmit",
+ "test": "vitest run",
+ "test:live": "RUN_LIVE_TESTS=1 vitest run"
+ },
+ "peerDependencies": {
+ "starknet": "^9.0.0"
+ },
+ "devDependencies": {
+ "starknet": "9.4.2",
+ "typescript": "^5.8.3",
+ "vitest": "^3.0.0"
+ },
+ "license": "MIT"
+}
diff --git a/sdk/src/index.ts b/sdk/src/index.ts
new file mode 100644
index 0000000..e36d2e6
--- /dev/null
+++ b/sdk/src/index.ts
@@ -0,0 +1,54 @@
+export {
+ FIRST_COMMUNITY_ID,
+ GENESIS_SPECIES_MAX,
+ MAX_SUPPLY_PER_SPECIES,
+ TOKEN_ID_BITS,
+ TokenIdError,
+ beastPower,
+ decodeTokenId,
+ encodeTokenId,
+ genesisBeast,
+ isGenesis,
+ isGenesisSpecies,
+} from './tokenId.js';
+
+export {
+ fullBeastName,
+ genesisSpecies,
+ genesisSpeciesName,
+ genesisTier,
+ genesisType,
+ prefixName,
+ suffixName,
+} from './species.js';
+
+export {
+ ALLOWED_ART_PREFIXES,
+ MAX_NAME_BYTES,
+ type ValidationResult,
+ validateArtSet,
+ validateFactoryArt,
+ validateRenderableArt,
+ validateSpeciesName,
+ validateTier,
+} from './validation.js';
+
+export {
+ BeastsClient,
+ SEPOLIA_ADDRESSES,
+ type BeastsAddresses,
+ type OwnedSpecies,
+ type RegisterParams,
+ type RegisterWithArtParams,
+ type SpeciesSummary,
+} from './registry.js';
+
+export { GENESIS_SPECIES_NAMES, PREFIX_NAMES, SUFFIX_NAMES } from './tables.js';
+
+export {
+ BEAST_TYPE_NAMES,
+ BeastType,
+ type ArtSet,
+ type Beast,
+ type BeastDefinition,
+} from './types.js';
diff --git a/sdk/src/registry.ts b/sdk/src/registry.ts
new file mode 100644
index 0000000..d7169db
--- /dev/null
+++ b/sdk/src/registry.ts
@@ -0,0 +1,666 @@
+import type { AccountInterface, Call, ProviderInterface } from 'starknet';
+import { CallData, byteArray, shortString } from 'starknet';
+import { genesisSpecies, genesisSpeciesName } from './species.js';
+import {
+ FIRST_COMMUNITY_ID,
+ decodeTokenId,
+ encodeTokenId,
+ genesisBeast,
+ isGenesis,
+ isGenesisSpecies,
+} from './tokenId.js';
+import { BeastType, type ArtSet, type Beast, type BeastDefinition } from './types.js';
+
+/** Name, traits and mint count for any species, genesis or community. */
+export interface SpeciesSummary {
+ beastId: bigint;
+ name: string;
+ tier: number;
+ beastType: BeastType;
+ /** Non-genesis mints. The Genesis Beast is not counted. */
+ minted: number;
+ /** False for the original 75, which have no registry entry. */
+ community: boolean;
+}
+
+/** A species the connected wallet controls, with its provenance token. */
+export interface OwnedSpecies {
+ beastId: bigint;
+ definition: BeastDefinition;
+ /** Token ID of the species' Genesis Beast — the artist's provenance token. */
+ genesisTokenId: bigint;
+}
+
+/** Addresses of a deployed Beasts stack. */
+export interface BeastsAddresses {
+ nft: string;
+ registry: string;
+}
+
+/** Deployed stacks, from `docs/sepolia-v3-deployment.md`. */
+export const SEPOLIA_ADDRESSES: BeastsAddresses = {
+ nft: '0x017e2cb5d7c4a86ff2bdee182ce53386a7cc57c63b943878de21b681e336a89a',
+ registry: '0x0797a19c0b267e91ea17f886f155310e38196261ec5683e3a12a35772718d723',
+};
+
+export interface RegisterWithArtParams {
+ name: string;
+ beastType: BeastType;
+ tier: number;
+ /** Dungeon allowed to mint. Pass `'0x0'` to register in a paused state. */
+ minter: string;
+ art: ArtSet;
+}
+
+export interface RegisterParams {
+ name: string;
+ beastType: BeastType;
+ tier: number;
+ minter: string;
+ /** An `IBeastArtProvider` the artist controls. */
+ artProvider: string;
+}
+
+/**
+ * Reads and call-builders for the Beasts stack.
+ *
+ * Write methods return `Call` objects rather than executing them, so the
+ * caller decides how to sign — a wallet popup, a Cartridge session, or a
+ * multicall batching several changes into one transaction. Only
+ * `execute` actually sends, and only if an account was supplied.
+ */
+export class BeastsClient {
+ private legacyProviders?: {
+ pngRegular: string;
+ pngShiny: string;
+ gifRegular: string;
+ gifShiny: string;
+ };
+
+ constructor(
+ private readonly provider: ProviderInterface,
+ private readonly addresses: BeastsAddresses = SEPOLIA_ADDRESSES,
+ private readonly account?: AccountInterface,
+ ) {}
+
+ get nftAddress(): string {
+ return this.addresses.nft;
+ }
+
+ get registryAddress(): string {
+ return this.addresses.registry;
+ }
+
+ // ------------------------------------------------------------- reads
+
+ /** Full definition of a registered community species. Reverts for 1-75. */
+ async getDefinition(beastId: bigint): Promise {
+ const raw = (await this.provider.callContract({
+ contractAddress: this.addresses.registry,
+ entrypoint: 'get_definition',
+ calldata: CallData.compile([beastId.toString()]),
+ })) as string[];
+
+ // BeastDefinition: name, type, tier, minter, artist, art_provider,
+ // stats_source, factory, art_locked, minter_locked
+ return {
+ name: shortString.decodeShortString(raw[0]),
+ beastType: Number(BigInt(raw[1])) as BeastType,
+ tier: Number(BigInt(raw[2])),
+ minter: toHex(raw[3]),
+ artist: toHex(raw[4]),
+ artProvider: toHex(raw[5]),
+ statsSource: toHex(raw[6]),
+ factoryProvider: BigInt(raw[7]) === 1n,
+ artLocked: BigInt(raw[8]) === 1n,
+ minterLocked: BigInt(raw[9]) === 1n,
+ };
+ }
+
+ /** Total species, genesis included. `next_id - 1`. */
+ async speciesCount(): Promise {
+ const [raw] = (await this.provider.callContract({
+ contractAddress: this.addresses.registry,
+ entrypoint: 'species_count',
+ calldata: [],
+ })) as string[];
+ return BigInt(raw);
+ }
+
+ async isRegistered(beastId: bigint): Promise {
+ const [raw] = (await this.provider.callContract({
+ contractAddress: this.addresses.registry,
+ entrypoint: 'is_registered',
+ calldata: CallData.compile([beastId.toString()]),
+ })) as string[];
+ return BigInt(raw) === 1n;
+ }
+
+ /** Minted NFT count. Not the highest token ID — IDs are not sequential. */
+ async totalSupply(): Promise {
+ const raw = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'total_supply',
+ calldata: [],
+ })) as string[];
+ return u256FromParts(raw[0], raw[1]);
+ }
+
+ /** Decodes a token's Beast. Local decode; no chain read is needed. */
+ decodeBeast(tokenId: bigint | string): Beast {
+ return decodeTokenId(tokenId);
+ }
+
+ async ownerOf(tokenId: bigint): Promise {
+ const [raw] = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'owner_of',
+ calldata: CallData.compile(u256ToParts(tokenId)),
+ })) as string[];
+ return toHex(raw);
+ }
+
+ /** Rank within the species, by power then health. Genesis Beasts are 0. */
+ async getBeastRank(tokenId: bigint): Promise {
+ const [raw] = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'get_beast_rank',
+ calldata: CallData.compile(u256ToParts(tokenId)),
+ })) as string[];
+ return Number(BigInt(raw));
+ }
+
+ /** The contract's own metadata for a token: a base64 JSON data URI. */
+ async tokenUri(tokenId: bigint): Promise {
+ const raw = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'token_uri',
+ calldata: CallData.compile(u256ToParts(tokenId)),
+ })) as string[];
+ return byteArray.stringFromByteArray(decodeByteArray(raw));
+ }
+
+ /** Art for a Beast, straight from its species' provider. */
+ async getArt(beast: Beast): Promise {
+ // Mirrors the contract's own routing in `resolve_art`: genesis species
+ // read from the four art data contracts wired at construction, community
+ // species from their registered provider.
+ if (isGenesisSpecies(beast.id)) {
+ const providers = await this.getLegacyArtProviders();
+ const address = beast.animated
+ ? beast.shiny
+ ? providers.gifShiny
+ : providers.gifRegular
+ : beast.shiny
+ ? providers.pngShiny
+ : providers.pngRegular;
+ // The legacy interface is keyed by the u8 species ID, not the beast.
+ return this.callForByteArray(address, 'get_data_uri', [beast.id.toString()]);
+ }
+
+ const definition = await this.getDefinition(beast.id);
+ return this.callForByteArray(definition.artProvider, 'get_data_uri', [
+ beast.id.toString(),
+ beast.prefix,
+ beast.suffix,
+ beast.level,
+ beast.health,
+ beast.shiny,
+ beast.animated,
+ beast.tier,
+ beast.beastType,
+ ]);
+ }
+
+ /**
+ * Addresses of the four genesis art data contracts, read once and cached.
+ * They are set at construction and immutable, so a single read is safe for
+ * the lifetime of the client.
+ */
+ async getLegacyArtProviders(): Promise<{
+ pngRegular: string;
+ pngShiny: string;
+ gifRegular: string;
+ gifShiny: string;
+ }> {
+ if (!this.legacyProviders) {
+ const [pngRegular, pngShiny, gifRegular, gifShiny] = await Promise.all([
+ this.callForAddress('get_regular_png_provider'),
+ this.callForAddress('get_shiny_png_provider'),
+ this.callForAddress('get_regular_gif_provider'),
+ this.callForAddress('get_shiny_gif_provider'),
+ ]);
+ this.legacyProviders = { pngRegular, pngShiny, gifRegular, gifShiny };
+ }
+ return this.legacyProviders;
+ }
+
+ /** Display name of any species: baked-in tables below 76, registry above. */
+ async getSpeciesName(beastId: bigint): Promise {
+ if (isGenesisSpecies(beastId)) return genesisSpeciesName(beastId);
+ return (await this.getDefinition(beastId)).name;
+ }
+
+ /**
+ * Name, traits and mint count for any species, genesis or community.
+ *
+ * Genesis species resolve entirely offline except the count, which is the
+ * one thing only the chain knows.
+ */
+ async getSpeciesSummary(beastId: bigint): Promise {
+ const minted = await this.getSpeciesMintCount(beastId);
+
+ if (isGenesisSpecies(beastId)) {
+ const { name, tier, beastType } = genesisSpecies(beastId);
+ return { beastId, name, tier, beastType, minted, community: false };
+ }
+
+ const definition = await this.getDefinition(beastId);
+ return {
+ beastId,
+ name: definition.name,
+ tier: definition.tier,
+ beastType: definition.beastType,
+ minted,
+ community: true,
+ };
+ }
+
+ /** Non-genesis mints of a species. Excludes the rank-0 Genesis Beast. */
+ async getSpeciesMintCount(beastId: bigint): Promise {
+ const [raw] = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'get_species_count',
+ calldata: CallData.compile([beastId.toString()]),
+ })) as string[];
+ return Number(BigInt(raw));
+ }
+
+ /**
+ * Every token of a species, best rank first, with the Genesis Beast last.
+ *
+ * Uses the contract's own per-species rank list rather than scanning: the
+ * NFT already keeps `rank -> token_id` for each species to drive metadata
+ * refreshes.
+ */
+ async getSpeciesTokens(beastId: bigint, concurrency = 4): Promise {
+ const count = await this.getSpeciesMintCount(beastId);
+ const tokens: bigint[] = [];
+
+ for (let start = 1; start <= count; start += concurrency) {
+ const batch = await Promise.all(
+ Array.from({ length: Math.min(concurrency, count - start + 1) }, (_, offset) =>
+ this.getTokenIdAtRank(beastId, start + offset),
+ ),
+ );
+ tokens.push(...batch.filter((id) => id !== 0n));
+ }
+
+ // The Genesis Beast holds rank 0 and lives outside that list.
+ const genesis = await this.getGenesisTokenIdIfMinted(beastId);
+ if (genesis !== null) tokens.push(genesis);
+
+ return tokens;
+ }
+
+ async getTokenIdAtRank(beastId: bigint, rank: number): Promise {
+ const raw = (await withRateLimitRetry(
+ () =>
+ this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'get_token_id_at_rank',
+ calldata: CallData.compile([beastId.toString(), rank]),
+ }) as Promise,
+ ));
+ return u256FromParts(raw[0], raw[1]);
+ }
+
+ /** Every token an address holds, decoded. */
+ async getTokensOfOwner(owner: string, concurrency = 4): Promise {
+ const balance = Number(await this.balanceOf(owner));
+ const beasts: Beast[] = [];
+
+ for (let start = 0; start < balance; start += concurrency) {
+ const batch = await Promise.all(
+ Array.from({ length: Math.min(concurrency, balance - start) }, (_, offset) =>
+ this.tokenOfOwnerByIndex(owner, BigInt(start + offset)),
+ ),
+ );
+ beasts.push(...batch.map((id) => decodeTokenId(id)));
+ }
+
+ return beasts;
+ }
+
+ private async getGenesisTokenIdIfMinted(beastId: bigint): Promise {
+ const tokenId = isGenesisSpecies(beastId)
+ ? encodeTokenId(
+ genesisBeast(beastId, genesisSpecies(beastId).tier, genesisSpecies(beastId).beastType),
+ )
+ : await this.getGenesisTokenId(beastId);
+ try {
+ await this.ownerOf(tokenId);
+ return tokenId;
+ } catch {
+ return null;
+ }
+ }
+
+ private async callForAddress(entrypoint: string): Promise {
+ const [raw] = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint,
+ calldata: [],
+ })) as string[];
+ return toHex(raw);
+ }
+
+ private async callForByteArray(
+ contractAddress: string,
+ entrypoint: string,
+ calldata: unknown[],
+ ): Promise {
+ const raw = (await withRateLimitRetry(
+ () =>
+ this.provider.callContract({
+ contractAddress,
+ entrypoint,
+ calldata: CallData.compile(calldata as never),
+ }) as Promise,
+ ));
+ return byteArray.stringFromByteArray(decodeByteArray(raw));
+ }
+
+ // ------------------------------------------------- artist enumeration
+
+ /**
+ * Species IDs an address controls.
+ *
+ * The artist role is not stored anywhere — it *is* ownership of the
+ * species' Genesis Beast. So this walks the wallet's tokens through
+ * `token_of_owner_by_index`, decodes each one locally, and keeps the ones
+ * with no affixes. A token ID carries its own species, so no registry read
+ * and no event scan is involved.
+ */
+ async getSpeciesByArtist(artist: string, concurrency = 4): Promise {
+ const balance = Number(await this.balanceOf(artist));
+ const ids: bigint[] = [];
+
+ // Enumeration is one call per token, and the collection owner alone holds
+ // all 75 genesis Beasts — issuing those serially takes tens of seconds and
+ // trips public-node rate limits. Fetch in bounded batches instead:
+ // fast enough for a real wallet, still polite to the node.
+ for (let start = 0; start < balance; start += concurrency) {
+ const batch = await Promise.all(
+ Array.from({ length: Math.min(concurrency, balance - start) }, (_, offset) =>
+ this.tokenOfOwnerByIndex(artist, BigInt(start + offset)),
+ ),
+ );
+ for (const tokenId of batch) {
+ const beast = decodeTokenId(tokenId);
+ // The (id, 0, 0) slot is the species' Genesis Beast, and holding it is
+ // what the registry checks. Every other token is an ordinary Beast.
+ if (isGenesis(beast)) ids.push(beast.id);
+ }
+ }
+
+ return ids.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
+ }
+
+ /**
+ * Full detail for everything an address controls, ready to render.
+ *
+ * Genesis species (1-75) are skipped: their Genesis Beasts belong to the
+ * collection owner and have no registry entry, so `get_definition` would
+ * revert on them.
+ */
+ async getOwnedSpecies(artist: string): Promise {
+ const ids = (await this.getSpeciesByArtist(artist)).filter(
+ (id) => id >= FIRST_COMMUNITY_ID,
+ );
+ return Promise.all(
+ ids.map(async (beastId) => {
+ const definition = await this.getDefinition(beastId);
+ return {
+ beastId,
+ definition,
+ genesisTokenId: encodeTokenId(
+ genesisBeast(beastId, definition.tier, definition.beastType),
+ ),
+ };
+ }),
+ );
+ }
+
+ /**
+ * Token ID of the species' Genesis Beast, read from the registry.
+ *
+ * Derivable offline via `encodeTokenId(genesisBeast(...))`, but reading it
+ * back is what proves the client and the contract agree on which token
+ * carries the artist role.
+ */
+ async getGenesisTokenId(beastId: bigint): Promise {
+ const raw = (await this.provider.callContract({
+ contractAddress: this.addresses.registry,
+ entrypoint: 'get_genesis_token_id',
+ calldata: CallData.compile([beastId.toString()]),
+ })) as string[];
+ return u256FromParts(raw[0], raw[1]);
+ }
+
+ async balanceOf(owner: string): Promise {
+ const raw = (await this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'balance_of',
+ calldata: CallData.compile([owner]),
+ })) as string[];
+ return u256FromParts(raw[0], raw[1]);
+ }
+
+ /** Owner enumeration. Order is not stable across transfers. */
+ async tokenOfOwnerByIndex(owner: string, index: bigint): Promise {
+ const raw = (await withRateLimitRetry(
+ () =>
+ this.provider.callContract({
+ contractAddress: this.addresses.nft,
+ entrypoint: 'token_of_owner_by_index',
+ calldata: CallData.compile([owner, ...u256ToParts(index)]),
+ }) as Promise,
+ ));
+ return u256FromParts(raw[0], raw[1]);
+ }
+
+ // ------------------------------------------------------ call builders
+
+ /**
+ * The simple path: the registry deploys a canonical `StoredArtProvider`
+ * holding the four variants. One transaction, no contract knowledge needed,
+ * and the artist's Genesis Beast lands in the same transaction.
+ */
+ registerWithArtCall(params: RegisterWithArtParams): Call {
+ return {
+ contractAddress: this.addresses.registry,
+ entrypoint: 'register_beast_with_art',
+ calldata: CallData.compile([
+ shortString.encodeShortString(params.name),
+ params.beastType,
+ params.tier,
+ params.minter,
+ byteArray.byteArrayFromString(params.art.pngRegular),
+ byteArray.byteArrayFromString(params.art.pngShiny),
+ byteArray.byteArrayFromString(params.art.gifRegular),
+ byteArray.byteArrayFromString(params.art.gifShiny),
+ ]),
+ };
+ }
+
+ /** The advanced path: the artist supplies their own `IBeastArtProvider`. */
+ registerCall(params: RegisterParams): Call {
+ return {
+ contractAddress: this.addresses.registry,
+ entrypoint: 'register_beast',
+ calldata: CallData.compile([
+ shortString.encodeShortString(params.name),
+ params.beastType,
+ params.tier,
+ params.minter,
+ params.artProvider,
+ ]),
+ };
+ }
+
+ updateArtCall(beastId: bigint, art: ArtSet): Call {
+ return {
+ contractAddress: this.addresses.registry,
+ entrypoint: 'update_art',
+ calldata: CallData.compile([
+ beastId.toString(),
+ byteArray.byteArrayFromString(art.pngRegular),
+ byteArray.byteArrayFromString(art.pngShiny),
+ byteArray.byteArrayFromString(art.gifRegular),
+ byteArray.byteArrayFromString(art.gifShiny),
+ ]),
+ };
+ }
+
+ /** Zero pauses the species — mints revert until a minter is set again. */
+ setMinterCall(beastId: bigint, minter: string): Call {
+ return this.registryCall('set_minter', [beastId.toString(), minter]);
+ }
+
+ /** One-way. After this the minter can never change. */
+ lockMinterCall(beastId: bigint): Call {
+ return this.registryCall('lock_minter', [beastId.toString()]);
+ }
+
+ /**
+ * One-way. Freezes the art *pointer*. For a factory provider that is a true
+ * freeze, since its only mutator is registry-gated. For a custom provider it
+ * freezes only the address — the provider may still change what it returns,
+ * which is why `notify_art_updated` stays open for those.
+ */
+ lockArtCall(beastId: bigint): Call {
+ return this.registryCall('lock_art', [beastId.toString()]);
+ }
+
+ setArtProviderCall(beastId: bigint, provider: string): Call {
+ return this.registryCall('set_art_provider', [beastId.toString(), provider]);
+ }
+
+ /** Re-announces art to marketplaces after a custom provider changed. */
+ notifyArtUpdatedCall(beastId: bigint): Call {
+ return this.registryCall('notify_art_updated', [beastId.toString()]);
+ }
+
+ /** Zero clears the source, turning kill stats off for the species. */
+ setStatsSourceCall(beastId: bigint, source: string): Call {
+ return this.registryCall('set_stats_source', [beastId.toString(), source]);
+ }
+
+ /**
+ * Transfers a species by transferring its Genesis Beast.
+ *
+ * There is no `transfer_artist_role`: the creator token *is* the role, so
+ * this is an ordinary ERC721 transfer and a marketplace sale does exactly
+ * the same thing.
+ */
+ transferGenesisBeastCall(from: string, to: string, genesisTokenId: bigint): Call {
+ return {
+ contractAddress: this.addresses.nft,
+ entrypoint: 'transfer_from',
+ calldata: CallData.compile([from, to, ...u256ToParts(genesisTokenId)]),
+ };
+ }
+
+ /** Permissionless: pulls a community token's stats into the render cache. */
+ refreshStatsCall(tokenId: bigint): Call {
+ return {
+ contractAddress: this.addresses.nft,
+ entrypoint: 'refresh_stats',
+ calldata: CallData.compile(u256ToParts(tokenId)),
+ };
+ }
+
+ // ----------------------------------------------------------- execute
+
+ /** Sends one or more calls. Requires an account. */
+ async execute(calls: Call | Call[]): Promise {
+ if (!this.account) {
+ throw new Error('BeastsClient was constructed without an account; cannot execute');
+ }
+ const { transaction_hash } = await this.account.execute(calls);
+ return transaction_hash;
+ }
+
+ private registryCall(entrypoint: string, args: unknown[]): Call {
+ return {
+ contractAddress: this.addresses.registry,
+ entrypoint,
+ calldata: CallData.compile(args as never),
+ };
+ }
+}
+
+// ------------------------------------------------------------- helpers
+
+/**
+ * Retries a call that a public node refused for rate limiting.
+ *
+ * Enumeration is one request per token, so any wallet with a real collection
+ * will out-run a free endpoint's per-second budget. That is a transient
+ * refusal, not an answer — retrying with backoff is the difference between
+ * "this wallet holds nothing" and the truth.
+ */
+async function withRateLimitRetry(fn: () => Promise, attempts = 7): Promise {
+ let delayMs = 250;
+ for (let attempt = 0; ; attempt++) {
+ try {
+ return await fn();
+ } catch (error) {
+ if (attempt >= attempts - 1 || !isRateLimited(error)) throw error;
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
+ delayMs *= 2;
+ }
+ }
+}
+
+function isRateLimited(error: unknown): boolean {
+ const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
+ return (
+ message.includes('-32011') ||
+ message.includes('cu limit') ||
+ message.includes('too many requests') ||
+ message.includes('rate limit') ||
+ message.includes('429')
+ );
+}
+
+function toHex(value: string): string {
+ return `0x${BigInt(value).toString(16).padStart(64, '0')}`;
+}
+
+function u256ToParts(value: bigint): [string, string] {
+ const MASK = (1n << 128n) - 1n;
+ return [(value & MASK).toString(), (value >> 128n).toString()];
+}
+
+function u256FromParts(low: string, high: string): bigint {
+ return BigInt(low) + (BigInt(high) << 128n);
+}
+
+/**
+ * A ByteArray on the wire is `[num_full_words, ...words, pending_word,
+ * pending_len]`. starknet.js wants that shape as an object.
+ */
+function decodeByteArray(raw: string[]): {
+ data: string[];
+ pending_word: string;
+ pending_word_len: number;
+} {
+ const wordCount = Number(BigInt(raw[0]));
+ return {
+ data: raw.slice(1, 1 + wordCount),
+ pending_word: raw[1 + wordCount],
+ pending_word_len: Number(BigInt(raw[2 + wordCount])),
+ };
+}
diff --git a/sdk/src/species.ts b/sdk/src/species.ts
new file mode 100644
index 0000000..416624a
--- /dev/null
+++ b/sdk/src/species.ts
@@ -0,0 +1,75 @@
+import { GENESIS_SPECIES_NAMES, PREFIX_NAMES, SUFFIX_NAMES } from './tables.js';
+import { GENESIS_SPECIES_MAX, isGenesisSpecies } from './tokenId.js';
+import { BeastType, type Beast } from './types.js';
+
+/**
+ * Tier of a genesis species.
+ *
+ * The contract expresses this as ranges, but they are a formula: species are
+ * laid out in three blocks of 25 (one per type), and each block runs T1..T5 in
+ * groups of five.
+ */
+export function genesisTier(id: bigint): number {
+ assertGenesisSpecies(id);
+ return Math.floor((Number(id - 1n) % 25) / 5) + 1;
+}
+
+/** Type of a genesis species: 1-25 Magic, 26-50 Hunter, 51-75 Brute. */
+export function genesisType(id: bigint): BeastType {
+ assertGenesisSpecies(id);
+ return Math.floor(Number(id - 1n) / 25) as BeastType;
+}
+
+/** Display name of a genesis species. */
+export function genesisSpeciesName(id: bigint): string {
+ assertGenesisSpecies(id);
+ return GENESIS_SPECIES_NAMES[Number(id) - 1];
+}
+
+/** Prefix display name, or `null` for the Genesis Beast's absent affix. */
+export function prefixName(prefix: number): string | null {
+ if (prefix === 0) return null;
+ if (prefix < 0 || prefix > PREFIX_NAMES.length) {
+ throw new RangeError(`prefix out of range: ${prefix}`);
+ }
+ return PREFIX_NAMES[prefix - 1];
+}
+
+/** Suffix display name, or `null` for the Genesis Beast's absent affix. */
+export function suffixName(suffix: number): string | null {
+ if (suffix === 0) return null;
+ if (suffix < 0 || suffix > SUFFIX_NAMES.length) {
+ throw new RangeError(`suffix out of range: ${suffix}`);
+ }
+ return SUFFIX_NAMES[suffix - 1];
+}
+
+/**
+ * Full display name, matching the contract's metadata exactly.
+ *
+ * A Genesis Beast is just the species name; every other Beast is
+ * `"Prefix Suffix" Species`. Community species must supply `speciesName` —
+ * only the registry knows it.
+ */
+export function fullBeastName(beast: Beast, speciesName?: string): string {
+ const base = speciesName ?? genesisSpeciesName(beast.id);
+ if (beast.prefix === 0) return base;
+ return `"${prefixName(beast.prefix)} ${suffixName(beast.suffix)}" ${base}`;
+}
+
+/**
+ * Static traits of a genesis species, resolved offline. Community species get
+ * theirs from the registry — see `BeastRegistryClient.getDefinition`.
+ */
+export function genesisSpecies(id: bigint): { name: string; tier: number; beastType: BeastType } {
+ return { name: genesisSpeciesName(id), tier: genesisTier(id), beastType: genesisType(id) };
+}
+
+function assertGenesisSpecies(id: bigint): void {
+ if (!isGenesisSpecies(id)) {
+ throw new RangeError(
+ `species ${id} is not a genesis species (1-${GENESIS_SPECIES_MAX}); ` +
+ 'community species resolve through the registry',
+ );
+ }
+}
diff --git a/sdk/src/tables.ts b/sdk/src/tables.ts
new file mode 100644
index 0000000..2487985
--- /dev/null
+++ b/sdk/src/tables.ts
@@ -0,0 +1,50 @@
+// GENERATED from src/beast_definitions.cairo — do not edit by hand.
+// Regenerate with `node scripts/gen-tables.mjs` from the repo root.
+//
+// Index 0 of each array is species/affix 1: the contract numbers these from
+// 1, and 0 means "absent" for affixes.
+
+/** The 75 genesis species, in contract order (index 0 === species 1). */
+export const GENESIS_SPECIES_NAMES: readonly string[] = [
+ 'Warlock', 'Typhon', 'Jiangshi', 'Anansi', 'Basilisk',
+ 'Gorgon', 'Kitsune', 'Lich', 'Chimera', 'Wendigo',
+ 'Rakshasa', 'Werewolf', 'Banshee', 'Draugr', 'Vampire',
+ 'Goblin', 'Ghoul', 'Wraith', 'Sprite', 'Kappa',
+ 'Fairy', 'Leprechaun', 'Kelpie', 'Pixie', 'Gnome',
+ 'Griffin', 'Manticore', 'Phoenix', 'Dragon', 'Minotaur',
+ 'Qilin', 'Ammit', 'Nue', 'Skinwalker', 'Chupacabra',
+ 'Weretiger', 'Wyvern', 'Roc', 'Harpy', 'Pegasus',
+ 'Hippogriff', 'Fenrir', 'Jaguar', 'Satori', 'Direwolf',
+ 'Bear', 'Wolf', 'Mantis', 'Spider', 'Rat',
+ 'Kraken', 'Colossus', 'Balrog', 'Leviathan', 'Tarrasque',
+ 'Titan', 'Nephilim', 'Behemoth', 'Hydra', 'Juggernaut',
+ 'Oni', 'Jotunn', 'Ettin', 'Cyclops', 'Giant',
+ 'Nemean Lion', 'Berserker', 'Yeti', 'Golem', 'Ent',
+ 'Troll', 'Bigfoot', 'Ogre', 'Orc', 'Skeleton',
+] as const;
+
+/** Name prefixes 1-69. Shared by every species, genesis and community. */
+export const PREFIX_NAMES: readonly string[] = [
+ 'Agony', 'Apocalypse', 'Armageddon', 'Beast', 'Behemoth',
+ 'Blight', 'Blood', 'Bramble', 'Brimstone', 'Brood',
+ 'Carrion', 'Cataclysm', 'Chimeric', 'Corpse', 'Corruption',
+ 'Damnation', 'Death', 'Demon', 'Dire', 'Dragon',
+ 'Dread', 'Doom', 'Dusk', 'Eagle', 'Empyrean',
+ 'Fate', 'Foe', 'Gale', 'Ghoul', 'Gloom',
+ 'Glyph', 'Golem', 'Grim', 'Hate', 'Havoc',
+ 'Honour', 'Horror', 'Hypnotic', 'Kraken', 'Loath',
+ 'Maelstrom', 'Mind', 'Miracle', 'Morbid', 'Oblivion',
+ 'Onslaught', 'Pain', 'Pandemonium', 'Phoenix', 'Plague',
+ 'Rage', 'Rapture', 'Rune', 'Skull', 'Sol',
+ 'Soul', 'Sorrow', 'Spirit', 'Storm', 'Tempest',
+ 'Torment', 'Vengeance', 'Victory', 'Viper', 'Vortex',
+ 'Woe', 'Wrath', 'Lights', 'Shimmering',
+] as const;
+
+/** Name suffixes 1-18. Shared by every species, genesis and community. */
+export const SUFFIX_NAMES: readonly string[] = [
+ 'Bane', 'Root', 'Bite', 'Song', 'Roar',
+ 'Grasp', 'Instrument', 'Glow', 'Bender', 'Shadow',
+ 'Whisper', 'Shout', 'Growl', 'Tear', 'Peak',
+ 'Form', 'Sun', 'Moon',
+] as const;
diff --git a/sdk/src/tokenId.ts b/sdk/src/tokenId.ts
new file mode 100644
index 0000000..1dc8d0e
--- /dev/null
+++ b/sdk/src/tokenId.ts
@@ -0,0 +1,185 @@
+import { BeastType, type Beast } from './types.js';
+
+/**
+ * The 116-bit token ID layout, mirroring `pack_to_u256` in `src/pack.cairo`.
+ *
+ * ```
+ * bits 0- 63 id (u64)
+ * bits 64- 70 prefix (7)
+ * bits 71- 75 suffix (5)
+ * bits 76- 91 level (16)
+ * bits 92-107 health (16)
+ * bit 108 shiny (1)
+ * bit 109 animated (1)
+ * bits 110-112 tier (3)
+ * bits 113-115 type (3)
+ * ```
+ *
+ * Token IDs are deterministic, not sequential: the ID *is* the Beast. Every
+ * static trait is recoverable offline, so a client needs chain reads only for
+ * the species name and art of community species.
+ */
+const SHIFT = {
+ id: 0n,
+ prefix: 64n,
+ suffix: 71n,
+ level: 76n,
+ health: 92n,
+ shiny: 108n,
+ animated: 109n,
+ tier: 110n,
+ beastType: 113n,
+} as const;
+
+const WIDTH = {
+ id: 64n,
+ prefix: 7n,
+ suffix: 5n,
+ level: 16n,
+ health: 16n,
+ shiny: 1n,
+ animated: 1n,
+ tier: 3n,
+ beastType: 3n,
+} as const;
+
+const mask = (bits: bigint) => (1n << bits) - 1n;
+
+/** Total width of the layout. Anything above this bit must be zero. */
+export const TOKEN_ID_BITS = 116n;
+
+/** Highest species ID backed by the baked-in genesis tables. */
+export const GENESIS_SPECIES_MAX = 75n;
+
+/** First species ID the registry will assign. */
+export const FIRST_COMMUNITY_ID = 76n;
+
+/** Max mintable Beasts per species: 69 x 18 named variants + 1 Genesis. */
+export const MAX_SUPPLY_PER_SPECIES = 69 * 18 + 1;
+
+export class TokenIdError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'TokenIdError';
+ }
+}
+
+/**
+ * Encodes a Beast into its canonical token ID.
+ *
+ * Validates the same ranges the contract does, so an ID produced here can
+ * never decode into a different Beast than the one passed in.
+ */
+export function encodeTokenId(beast: Beast): bigint {
+ assertEncodable(beast);
+
+ return (
+ (beast.id << SHIFT.id) |
+ (BigInt(beast.prefix) << SHIFT.prefix) |
+ (BigInt(beast.suffix) << SHIFT.suffix) |
+ (BigInt(beast.level) << SHIFT.level) |
+ (BigInt(beast.health) << SHIFT.health) |
+ (BigInt(beast.shiny) << SHIFT.shiny) |
+ (BigInt(beast.animated) << SHIFT.animated) |
+ (BigInt(beast.tier) << SHIFT.tier) |
+ (BigInt(beast.beastType) << SHIFT.beastType)
+ );
+}
+
+/**
+ * Decodes a token ID into its Beast.
+ *
+ * Applies the contract's `decode_token_id` checks: no residual high bits, a
+ * non-zero species, in-range tier/type/affixes, and the affix-pair rule that
+ * `(prefix === 0) === (suffix === 0)` — the `(id, 0, 0)` slot is reserved for
+ * the species' Genesis Beast and no other combination may be half-set.
+ */
+export function decodeTokenId(tokenId: bigint | string | number): Beast {
+ const packed = BigInt(tokenId);
+
+ if (packed < 0n) throw new TokenIdError('token ID must be non-negative');
+ if (packed >> TOKEN_ID_BITS) throw new TokenIdError('token ID has residual high bits');
+
+ const field = (key: keyof typeof SHIFT) => (packed >> SHIFT[key]) & mask(WIDTH[key]);
+
+ const id = field('id');
+ if (id === 0n) throw new TokenIdError('species ID must not be zero');
+
+ const prefix = Number(field('prefix'));
+ const suffix = Number(field('suffix'));
+ const tier = Number(field('tier'));
+ const beastType = Number(field('beastType'));
+
+ if (tier < 1 || tier > 5) throw new TokenIdError(`tier out of range: ${tier}`);
+ if (beastType > 2) throw new TokenIdError(`beast type out of range: ${beastType}`);
+ if (prefix > 69) throw new TokenIdError(`prefix out of range: ${prefix}`);
+ if (suffix > 18) throw new TokenIdError(`suffix out of range: ${suffix}`);
+ if ((prefix === 0) !== (suffix === 0)) {
+ throw new TokenIdError('invalid affix combo: prefix and suffix must both be zero, or neither');
+ }
+
+ return {
+ id,
+ prefix,
+ suffix,
+ level: Number(field('level')),
+ health: Number(field('health')),
+ shiny: Number(field('shiny')) as 0 | 1,
+ animated: Number(field('animated')) as 0 | 1,
+ tier,
+ beastType: beastType as BeastType,
+ };
+}
+
+/**
+ * A Genesis Beast is derived, never stored: it is the one Beast per species
+ * holding the reserved `(id, 0, 0)` affix slot. It is the artist's provenance
+ * token for community species, and belongs to the collection owner for the
+ * original 75.
+ */
+export function isGenesis(beast: Beast): boolean {
+ return beast.prefix === 0 && beast.suffix === 0;
+}
+
+/** True for the 75 species baked into the contract's tables. */
+export function isGenesisSpecies(id: bigint): boolean {
+ return id >= 1n && id <= GENESIS_SPECIES_MAX;
+}
+
+/** Combat power, exactly as the contract computes it: `level * (6 - tier)`. */
+export function beastPower(beast: Beast): number {
+ const power = beast.level * (6 - beast.tier);
+ return power > 65535 ? 65535 : power;
+}
+
+/** Builds the Genesis Beast of a species from its static traits. */
+export function genesisBeast(id: bigint, tier: number, beastType: BeastType): Beast {
+ return { id, prefix: 0, suffix: 0, level: 1, health: 100, shiny: 1, animated: 1, tier, beastType };
+}
+
+function assertEncodable(beast: Beast): void {
+ const inRange = (name: string, value: number | bigint, max: bigint) => {
+ const v = BigInt(value);
+ if (v < 0n || v > max) throw new TokenIdError(`${name} out of range: ${value}`);
+ };
+
+ if (beast.id <= 0n) throw new TokenIdError('species ID must be positive');
+ inRange('id', beast.id, mask(WIDTH.id));
+ inRange('level', beast.level, mask(WIDTH.level));
+ inRange('health', beast.health, mask(WIDTH.health));
+
+ if (beast.prefix > 69) throw new TokenIdError(`prefix out of range: ${beast.prefix}`);
+ if (beast.suffix > 18) throw new TokenIdError(`suffix out of range: ${beast.suffix}`);
+ if (beast.prefix < 0 || beast.suffix < 0) throw new TokenIdError('affixes must be non-negative');
+ if ((beast.prefix === 0) !== (beast.suffix === 0)) {
+ throw new TokenIdError('invalid affix combo: prefix and suffix must both be zero, or neither');
+ }
+ if (beast.tier < 1 || beast.tier > 5) throw new TokenIdError(`tier out of range: ${beast.tier}`);
+ if (beast.beastType < 0 || beast.beastType > 2) {
+ throw new TokenIdError(`beast type out of range: ${beast.beastType}`);
+ }
+ if (beast.shiny !== 0 && beast.shiny !== 1) throw new TokenIdError('shiny must be 0 or 1');
+ if (beast.animated !== 0 && beast.animated !== 1) {
+ throw new TokenIdError('animated must be 0 or 1');
+ }
+}
diff --git a/sdk/src/types.ts b/sdk/src/types.ts
new file mode 100644
index 0000000..38385da
--- /dev/null
+++ b/sdk/src/types.ts
@@ -0,0 +1,59 @@
+/** Beast type codes exactly as encoded in the token ID. */
+export enum BeastType {
+ Magic = 0,
+ Hunter = 1,
+ Brute = 2,
+}
+
+export const BEAST_TYPE_NAMES: Record = {
+ [BeastType.Magic]: 'Magic',
+ [BeastType.Hunter]: 'Hunter',
+ [BeastType.Brute]: 'Brute',
+};
+
+/**
+ * Everything a token ID encodes. This is the whole static profile of a Beast —
+ * no chain read is needed to produce it, which is the point of the 116-bit
+ * layout.
+ */
+export interface Beast {
+ /** Species ID. 1-75 are genesis species; 76+ are community species. */
+ id: bigint;
+ /** 0-69. Zero only on a Genesis Beast. */
+ prefix: number;
+ /** 0-18. Zero only on a Genesis Beast. */
+ suffix: number;
+ level: number;
+ health: number;
+ shiny: 0 | 1;
+ animated: 0 | 1;
+ /** 1-5. */
+ tier: number;
+ beastType: BeastType;
+}
+
+/** A registered community species, as returned by `get_definition`. */
+export interface BeastDefinition {
+ name: string;
+ beastType: BeastType;
+ tier: number;
+ /** Dungeon allowed to mint this species. Zero means paused. */
+ minter: string;
+ /** Registrant; holds the per-species admin role. */
+ artist: string;
+ artProvider: string;
+ /** Zero means kill stats are off for this species. */
+ statsSource: string;
+ /** True when `artProvider` is the registry's canonical factory deploy. */
+ factoryProvider: boolean;
+ artLocked: boolean;
+ minterLocked: boolean;
+}
+
+/** The four art variants a factory-provider species stores. */
+export interface ArtSet {
+ pngRegular: string;
+ pngShiny: string;
+ gifRegular: string;
+ gifShiny: string;
+}
diff --git a/sdk/src/validation.ts b/sdk/src/validation.ts
new file mode 100644
index 0000000..650d014
--- /dev/null
+++ b/sdk/src/validation.ts
@@ -0,0 +1,151 @@
+/**
+ * Client-side mirrors of the contract's guards.
+ *
+ * These exist so the web app can reject bad input before it costs a
+ * transaction — they are a convenience, never the security boundary. The
+ * contract re-checks everything, and it is the only thing that decides what
+ * is valid.
+ */
+
+// ---------------------------------------------------------------- names
+
+/**
+ * Species name charset, mirroring `assert_valid_name` in
+ * `src/beast_registry.cairo`.
+ *
+ * This is an injection guard, not a style rule: the contract's JSON and SVG
+ * builders embed names unescaped, so the charset is what keeps every token's
+ * metadata well-formed. Uniqueness is deliberately NOT enforced — requiring
+ * it would let anyone squat the good names. Species ID is the identity.
+ */
+const NAME_CHARSET = /^[A-Za-z0-9 '-]+$/;
+
+/** Names are stored in a single felt252, which holds at most 31 bytes. */
+export const MAX_NAME_BYTES = 31;
+
+export interface ValidationResult {
+ valid: boolean;
+ error?: string;
+}
+
+export function validateSpeciesName(name: string): ValidationResult {
+ if (name.length === 0) return { valid: false, error: 'Name cannot be empty' };
+ if (new TextEncoder().encode(name).length > MAX_NAME_BYTES) {
+ return { valid: false, error: `Name cannot exceed ${MAX_NAME_BYTES} bytes` };
+ }
+ if (!NAME_CHARSET.test(name)) {
+ return {
+ valid: false,
+ error: "Name may only contain letters, numbers, spaces, apostrophes, and hyphens",
+ };
+ }
+ if (name.startsWith(' ')) return { valid: false, error: 'Name cannot start with a space' };
+ if (name.endsWith(' ')) return { valid: false, error: 'Name cannot end with a space' };
+ return { valid: true };
+}
+
+// ------------------------------------------------------------------ art
+
+/**
+ * Media types the contract accepts from a community art provider at render
+ * time (`src/art_validation.cairo`).
+ */
+export const ALLOWED_ART_PREFIXES = [
+ 'data:image/png;base64,',
+ 'data:image/gif;base64,',
+ 'data:image/webp;base64,',
+ 'data:image/svg+xml;base64,',
+] as const;
+
+/**
+ * Base64-encoded magic bytes the *factory* provider additionally requires at
+ * write time (`src/stored_art_provider.cairo`). A fixed leading signature
+ * always encodes to a fixed character prefix, so this needs no decoding:
+ * PNG 89 50 4E 47 0D 0A 1A 0A + IHDR length -> "iVBORw0KGgo"
+ * GIF "GIF87a" -> "R0lGODdh", "GIF89a" -> "R0lGODlh"
+ */
+const PNG_MAGIC = 'iVBORw0KGgo';
+const GIF_MAGICS = ['R0lGODdh', 'R0lGODlh'] as const;
+
+const BASE64_BODY = /^[A-Za-z0-9+/]*={0,2}$/;
+
+/**
+ * Validates a data URI the way `token_uri` will when it renders: allowlisted
+ * media type plus a structurally sound standard-base64 payload.
+ *
+ * Deliberately imposes no size cap. If an artist is willing to pay for the
+ * storage and the network accepts the transaction, the art is valid.
+ */
+export function validateRenderableArt(uri: string): ValidationResult {
+ const prefix = ALLOWED_ART_PREFIXES.find((p) => uri.startsWith(p));
+ if (!prefix) {
+ return {
+ valid: false,
+ error: 'Art must be a base64 data URI of type png, gif, webp, or svg+xml',
+ };
+ }
+
+ const payload = uri.slice(prefix.length);
+ if (payload.length === 0) return { valid: false, error: 'Art payload is empty' };
+ if (payload.length % 4 !== 0) {
+ return { valid: false, error: 'Art payload is not valid base64 (length must be a multiple of 4)' };
+ }
+ if (!BASE64_BODY.test(payload)) {
+ return { valid: false, error: 'Art payload contains characters outside the base64 alphabet' };
+ }
+ return { valid: true };
+}
+
+/**
+ * Validates art destined for the *factory* provider, which is stricter than
+ * render-time: it must additionally carry real PNG or GIF magic bytes. This
+ * is what earns factory art its "verified" designation — a locked factory
+ * species is provably frozen and provably an inert image.
+ */
+export function validateFactoryArt(uri: string, kind: 'png' | 'gif'): ValidationResult {
+ const expectedPrefix = kind === 'png' ? 'data:image/png;base64,' : 'data:image/gif;base64,';
+ if (!uri.startsWith(expectedPrefix)) {
+ return { valid: false, error: `Expected a ${kind.toUpperCase()} data URI` };
+ }
+
+ const structural = validateRenderableArt(uri);
+ if (!structural.valid) return structural;
+
+ const payload = uri.slice(expectedPrefix.length);
+ if (kind === 'png') {
+ if (!payload.startsWith(PNG_MAGIC)) {
+ return { valid: false, error: 'File is not a valid PNG' };
+ }
+ } else if (!GIF_MAGICS.some((m) => payload.startsWith(m))) {
+ return { valid: false, error: 'File is not a valid GIF (must be GIF87a or GIF89a)' };
+ }
+ return { valid: true };
+}
+
+/** Validates the complete four-variant set the factory path requires. */
+export function validateArtSet(art: {
+ pngRegular: string;
+ pngShiny: string;
+ gifRegular: string;
+ gifShiny: string;
+}): ValidationResult {
+ const checks: Array<[string, ValidationResult]> = [
+ ['Regular PNG', validateFactoryArt(art.pngRegular, 'png')],
+ ['Shiny PNG', validateFactoryArt(art.pngShiny, 'png')],
+ ['Regular GIF', validateFactoryArt(art.gifRegular, 'gif')],
+ ['Shiny GIF', validateFactoryArt(art.gifShiny, 'gif')],
+ ];
+ for (const [label, result] of checks) {
+ if (!result.valid) return { valid: false, error: `${label}: ${result.error}` };
+ }
+ return { valid: true };
+}
+
+// ----------------------------------------------------------------- tier
+
+export function validateTier(tier: number): ValidationResult {
+ if (!Number.isInteger(tier) || tier < 1 || tier > 5) {
+ return { valid: false, error: 'Tier must be a whole number from 1 to 5' };
+ }
+ return { valid: true };
+}
diff --git a/sdk/test/live.test.ts b/sdk/test/live.test.ts
new file mode 100644
index 0000000..07f2ca6
--- /dev/null
+++ b/sdk/test/live.test.ts
@@ -0,0 +1,124 @@
+import { RpcProvider } from 'starknet';
+import { describe, expect, it } from 'vitest';
+import { BeastType, BeastsClient, SEPOLIA_ADDRESSES, decodeTokenId } from '../src/index.js';
+
+/**
+ * Live reads against the Sepolia deployment in
+ * `docs/sepolia-v3-deployment.md`.
+ *
+ * Skipped by default — they need network and will drift if that deployment is
+ * replaced. Run with `pnpm test:live`. Their job is to prove the client's
+ * calldata and return-value decoding actually match the deployed ABI, which
+ * unit tests with hand-written fixtures cannot.
+ */
+const RPC_URL = process.env.STARKNET_RPC_URL ?? 'https://api.zan.top/public/starknet-sepolia/rpc/v0_10';
+const live = process.env.RUN_LIVE_TESTS ? describe : describe.skip;
+
+const GENESIS_WARLOCK = 0x7006400010000000000000000001n;
+const GLOOMFANG = 0x2e0064000a081000000000000004cn; // minted below if absent
+
+live('Sepolia deployment', () => {
+ const client = new BeastsClient(new RpcProvider({ nodeUrl: RPC_URL }), SEPOLIA_ADDRESSES);
+
+ it('reads the registered community species', async () => {
+ const definition = await client.getDefinition(76n);
+ expect(definition.name).toBe('Gloomfang');
+ expect(definition.beastType).toBe(BeastType.Hunter);
+ expect(definition.tier).toBe(3);
+ expect(definition.factoryProvider).toBe(true);
+ expect(definition.artLocked).toBe(false);
+ expect(definition.minterLocked).toBe(false);
+ // No stats source was set, so kill stats are off for this species.
+ expect(BigInt(definition.statsSource)).toBe(0n);
+ }, 30_000);
+
+ it('counts species and supply', async () => {
+ expect(await client.speciesCount()).toBeGreaterThanOrEqual(76n);
+ expect(await client.totalSupply()).toBeGreaterThanOrEqual(76n);
+ }, 30_000);
+
+ it('reports registration only above the genesis range', async () => {
+ expect(await client.isRegistered(76n)).toBe(true);
+ expect(await client.isRegistered(1n)).toBe(false);
+ expect(await client.isRegistered(9_999n)).toBe(false);
+ }, 30_000);
+
+ it('ranks the community mint first in its species', async () => {
+ expect(await client.getBeastRank(GLOOMFANG)).toBe(1);
+ // Genesis Beasts sit outside the ranked list.
+ expect(await client.getBeastRank(GENESIS_WARLOCK)).toBe(0);
+ }, 30_000);
+
+ it('renders token_uri as base64 JSON with the expected identity', async () => {
+ const uri = await client.tokenUri(GLOOMFANG);
+ expect(uri.startsWith('data:application/json;base64,')).toBe(true);
+
+ const json = JSON.parse(
+ Buffer.from(uri.slice('data:application/json;base64,'.length), 'base64').toString('utf8'),
+ );
+ expect(json.name).toBe('"Agony Bane" Gloomfang');
+
+ const attribute = (t: string) =>
+ json.attributes.find((a: { trait_type: string }) => a.trait_type === t)?.value;
+ expect(attribute('Beast')).toBe('Gloomfang');
+ expect(attribute('Type')).toBe('Hunter');
+ expect(attribute('Tier')).toBe('3');
+ expect(attribute('Power')).toBe('30');
+ expect(attribute('Genesis')).toBe('0');
+ }, 60_000);
+
+ it('fetches art from the species art provider', async () => {
+ const art = await client.getArt(decodeTokenId(GLOOMFANG));
+ // animated = 1, shiny = 0, so the provider must return the regular GIF.
+ expect(art.startsWith('data:image/gif;base64,R0lGOD')).toBe(true);
+ }, 30_000);
+
+ it('agrees with the chain on who owns the genesis token', async () => {
+ const owner = await client.ownerOf(GENESIS_WARLOCK);
+ expect(BigInt(owner)).not.toBe(0n);
+ }, 30_000);
+
+ // ---------------------------------------------------- artist lookup
+
+ const DEPLOYER = '0x736faa0dca6a4569bf22471b574ddf42107f5af81d67e2cb9e1aa9bba7de76b';
+
+ it('finds the species an artist controls', async () => {
+ // Walks the wallet's tokens through enumeration and keeps the Genesis
+ // Beasts. Non-empty is the assertion, not a detail: an enumeration
+ // entrypoint the contract lacks would look identical to "owns nothing".
+ const owned = await client.getSpeciesByArtist(DEPLOYER);
+ expect(owned.length).toBeGreaterThan(0);
+ expect(owned).toContain(76n);
+ }, 60_000);
+
+ it('agrees with the registry on who the artist is', async () => {
+ const definition = await client.getDefinition(76n);
+ const genesis = await client.getGenesisTokenId(76n);
+ // The role is ownership of this token — the two must be the same address.
+ expect(BigInt(await client.ownerOf(genesis))).toBe(BigInt(definition.artist));
+ }, 30_000);
+
+ it('returns nothing for an address that never registered', async () => {
+ expect(await client.getSpeciesByArtist('0xdead')).toEqual([]);
+ }, 60_000);
+
+ it('derives a real Genesis Beast token for each owned species', async () => {
+ const owned = await client.getOwnedSpecies(DEPLOYER);
+ expect(owned.length).toBeGreaterThan(0);
+
+ for (const species of owned) {
+ // The derived ID must decode back to the same species with the traits
+ // the registry reports — that is what makes deriving it safe instead of
+ // reading it from the chain.
+ const beast = decodeTokenId(species.genesisTokenId);
+ expect(beast.id).toBe(species.beastId);
+ expect(beast.tier).toBe(species.definition.tier);
+ expect(beast.beastType).toBe(species.definition.beastType);
+ expect(beast.prefix).toBe(0);
+ expect(beast.suffix).toBe(0);
+
+ // And it must actually exist: ownerOf reverts for an unminted token.
+ expect(BigInt(await client.ownerOf(species.genesisTokenId))).not.toBe(0n);
+ }
+ }, 60_000);
+});
diff --git a/sdk/test/species.test.ts b/sdk/test/species.test.ts
new file mode 100644
index 0000000..5115a25
--- /dev/null
+++ b/sdk/test/species.test.ts
@@ -0,0 +1,104 @@
+import { describe, expect, it } from 'vitest';
+import {
+ BeastType,
+ GENESIS_SPECIES_NAMES,
+ PREFIX_NAMES,
+ SUFFIX_NAMES,
+ decodeTokenId,
+ fullBeastName,
+ genesisSpeciesName,
+ genesisTier,
+ genesisType,
+ prefixName,
+ suffixName,
+} from '../src/index.js';
+
+describe('generated tables', () => {
+ it('has the exact table sizes the contract does', () => {
+ expect(GENESIS_SPECIES_NAMES).toHaveLength(75);
+ expect(PREFIX_NAMES).toHaveLength(69);
+ expect(SUFFIX_NAMES).toHaveLength(18);
+ });
+
+ it('contains no empty entries', () => {
+ for (const table of [GENESIS_SPECIES_NAMES, PREFIX_NAMES, SUFFIX_NAMES]) {
+ expect(table.every((n) => n.length > 0)).toBe(true);
+ }
+ });
+
+ it('keeps every name inside a felt252', () => {
+ const encoder = new TextEncoder();
+ for (const table of [GENESIS_SPECIES_NAMES, PREFIX_NAMES, SUFFIX_NAMES]) {
+ for (const name of table) expect(encoder.encode(name).length).toBeLessThanOrEqual(31);
+ }
+ });
+});
+
+describe('genesis species traits', () => {
+ // Anchors taken from the contract's own unit tests in beast_manager.cairo.
+ it.each([
+ [1n, 'Warlock', 1, BeastType.Magic],
+ [3n, 'Jiangshi', 1, BeastType.Magic],
+ [25n, 'Gnome', 5, BeastType.Magic],
+ [42n, 'Fenrir', 4, BeastType.Hunter],
+ [75n, undefined, 5, BeastType.Brute],
+ ])('resolves species %s', (id, name, tier, type) => {
+ if (name) expect(genesisSpeciesName(id as bigint)).toBe(name);
+ expect(genesisTier(id as bigint)).toBe(tier);
+ expect(genesisType(id as bigint)).toBe(type);
+ });
+
+ it('lays tiers out in five-wide groups within each type block', () => {
+ for (let id = 1; id <= 75; id++) {
+ const expected = Math.floor(((id - 1) % 25) / 5) + 1;
+ expect(genesisTier(BigInt(id))).toBe(expected);
+ }
+ });
+
+ it('splits types into three blocks of 25', () => {
+ expect(genesisType(25n)).toBe(BeastType.Magic);
+ expect(genesisType(26n)).toBe(BeastType.Hunter);
+ expect(genesisType(50n)).toBe(BeastType.Hunter);
+ expect(genesisType(51n)).toBe(BeastType.Brute);
+ });
+
+ it('refuses community species, which resolve through the registry', () => {
+ expect(() => genesisSpeciesName(76n)).toThrow(/not a genesis species/);
+ expect(() => genesisTier(76n)).toThrow(/not a genesis species/);
+ });
+});
+
+describe('affixes', () => {
+ it('matches the contract anchors', () => {
+ expect(prefixName(1)).toBe('Agony');
+ expect(suffixName(1)).toBe('Bane');
+ expect(suffixName(2)).toBe('Root');
+ });
+
+ it('returns null for the Genesis Beast’s absent affixes', () => {
+ expect(prefixName(0)).toBeNull();
+ expect(suffixName(0)).toBeNull();
+ });
+
+ it('rejects out-of-range affixes', () => {
+ expect(() => prefixName(70)).toThrow(RangeError);
+ expect(() => suffixName(19)).toThrow(RangeError);
+ });
+});
+
+describe('full names', () => {
+ it('renders a genesis beast as the bare species name', () => {
+ expect(fullBeastName(decodeTokenId(0x7006400010000000000000000001n))).toBe('Warlock');
+ });
+
+ it('reproduces the name the Sepolia contract rendered', () => {
+ // The deployed contract returned: "Agony Bane" Gloomfang
+ const beast = decodeTokenId(0x2e0064000a081000000000000004cn);
+ expect(fullBeastName(beast, 'Gloomfang')).toBe('"Agony Bane" Gloomfang');
+ });
+
+ it('requires a species name for community species', () => {
+ const beast = decodeTokenId(0x2e0064000a081000000000000004cn);
+ expect(() => fullBeastName(beast)).toThrow(/not a genesis species/);
+ });
+});
diff --git a/sdk/test/tokenId.test.ts b/sdk/test/tokenId.test.ts
new file mode 100644
index 0000000..804b482
--- /dev/null
+++ b/sdk/test/tokenId.test.ts
@@ -0,0 +1,172 @@
+import { describe, expect, it } from 'vitest';
+import {
+ BeastType,
+ TokenIdError,
+ beastPower,
+ decodeTokenId,
+ encodeTokenId,
+ genesisBeast,
+ isGenesis,
+ isGenesisSpecies,
+ type Beast,
+} from '../src/index.js';
+
+/**
+ * These two IDs were produced by the deployed contract on Sepolia, not by
+ * this SDK — see `docs/sepolia-v3-deployment.md`. They are the anchor that
+ * proves the TS layout matches `pack_to_u256`; everything else here is
+ * self-consistency.
+ */
+const ONCHAIN_GENESIS_WARLOCK = 0x7006400010000000000000000001n;
+const ONCHAIN_GLOOMFANG = 0x2e0064000a081000000000000004cn;
+
+describe('on-chain parity', () => {
+ it('decodes the Sepolia genesis Warlock token', () => {
+ const beast = decodeTokenId(ONCHAIN_GENESIS_WARLOCK);
+ expect(beast).toEqual({
+ id: 1n,
+ prefix: 0,
+ suffix: 0,
+ level: 1,
+ health: 100,
+ shiny: 1,
+ animated: 1,
+ tier: 1,
+ beastType: BeastType.Magic,
+ });
+ expect(isGenesis(beast)).toBe(true);
+ });
+
+ it('decodes the Sepolia "Agony Bane" Gloomfang token', () => {
+ const beast = decodeTokenId(ONCHAIN_GLOOMFANG);
+ expect(beast).toEqual({
+ id: 76n,
+ prefix: 1,
+ suffix: 1,
+ level: 10,
+ health: 100,
+ shiny: 0,
+ animated: 1,
+ tier: 3,
+ beastType: BeastType.Hunter,
+ });
+ expect(isGenesis(beast)).toBe(false);
+ // The contract reported Power 30 for this token.
+ expect(beastPower(beast)).toBe(30);
+ });
+
+ it('re-encodes both on-chain tokens byte for byte', () => {
+ for (const tokenId of [ONCHAIN_GENESIS_WARLOCK, ONCHAIN_GLOOMFANG]) {
+ expect(encodeTokenId(decodeTokenId(tokenId))).toBe(tokenId);
+ }
+ });
+});
+
+describe('round trips', () => {
+ it('survives the maximum value in every field', () => {
+ const beast: Beast = {
+ id: (1n << 64n) - 1n,
+ prefix: 69,
+ suffix: 18,
+ level: 65535,
+ health: 65535,
+ shiny: 1,
+ animated: 1,
+ tier: 5,
+ beastType: BeastType.Brute,
+ };
+ expect(decodeTokenId(encodeTokenId(beast))).toEqual(beast);
+ });
+
+ it('stays inside 116 bits at maximum', () => {
+ const maxId = encodeTokenId({
+ id: (1n << 64n) - 1n,
+ prefix: 69,
+ suffix: 18,
+ level: 65535,
+ health: 65535,
+ shiny: 1,
+ animated: 1,
+ tier: 5,
+ beastType: BeastType.Brute,
+ });
+ expect(maxId >> 116n).toBe(0n);
+ // Fits a u128, which is what makes these IDs cheap for clients.
+ expect(maxId < 1n << 128n).toBe(true);
+ });
+
+ it('accepts hex strings and numbers', () => {
+ expect(decodeTokenId('0x7006400010000000000000000001').id).toBe(1n);
+ expect(decodeTokenId(ONCHAIN_GENESIS_WARLOCK.toString()).id).toBe(1n);
+ });
+});
+
+describe('validation', () => {
+ const valid: Beast = {
+ id: 3n,
+ prefix: 1,
+ suffix: 2,
+ level: 10,
+ health: 100,
+ shiny: 0,
+ animated: 0,
+ tier: 1,
+ beastType: BeastType.Magic,
+ };
+
+ it('rejects a zero species ID', () => {
+ expect(() => encodeTokenId({ ...valid, id: 0n })).toThrow(TokenIdError);
+ expect(() => decodeTokenId(0n)).toThrow(/species ID must not be zero/);
+ });
+
+ it('rejects residual high bits', () => {
+ expect(() => decodeTokenId(1n << 116n)).toThrow(/residual high bits/);
+ });
+
+ it('rejects half-set affixes in both directions', () => {
+ // The (id, 0, 0) slot is reserved for the Genesis Beast, so a Beast may
+ // have both affixes or neither — never one.
+ expect(() => encodeTokenId({ ...valid, prefix: 0 })).toThrow(/invalid affix combo/);
+ expect(() => encodeTokenId({ ...valid, suffix: 0 })).toThrow(/invalid affix combo/);
+ });
+
+ it('accepts a genesis beast with neither affix', () => {
+ expect(() => encodeTokenId({ ...valid, prefix: 0, suffix: 0 })).not.toThrow();
+ });
+
+ it('rejects out-of-range traits', () => {
+ expect(() => encodeTokenId({ ...valid, tier: 0 })).toThrow(/tier out of range/);
+ expect(() => encodeTokenId({ ...valid, tier: 6 })).toThrow(/tier out of range/);
+ expect(() => encodeTokenId({ ...valid, prefix: 70 })).toThrow(/prefix out of range/);
+ expect(() => encodeTokenId({ ...valid, suffix: 19 })).toThrow(/suffix out of range/);
+ expect(() => encodeTokenId({ ...valid, beastType: 3 as BeastType })).toThrow(
+ /beast type out of range/,
+ );
+ });
+
+ it('rejects a decoded tier of zero', () => {
+ // Tier 0 is unreachable through encode, so build the ID by hand.
+ const raw = 1n | (1n << 64n) | (1n << 71n);
+ expect(() => decodeTokenId(raw)).toThrow(/tier out of range/);
+ });
+});
+
+describe('derived helpers', () => {
+ it('caps power at u16', () => {
+ expect(beastPower({ ...genesisBeast(1n, 1, BeastType.Magic), level: 65535 })).toBe(65535);
+ });
+
+ it('computes power as level * (6 - tier)', () => {
+ for (let tier = 1; tier <= 5; tier++) {
+ const beast = { ...genesisBeast(1n, tier, BeastType.Magic), level: 10 };
+ expect(beastPower(beast)).toBe(10 * (6 - tier));
+ }
+ });
+
+ it('classifies genesis vs community species', () => {
+ expect(isGenesisSpecies(1n)).toBe(true);
+ expect(isGenesisSpecies(75n)).toBe(true);
+ expect(isGenesisSpecies(76n)).toBe(false);
+ expect(isGenesisSpecies(0n)).toBe(false);
+ });
+});
diff --git a/sdk/test/validation.test.ts b/sdk/test/validation.test.ts
new file mode 100644
index 0000000..9d30959
--- /dev/null
+++ b/sdk/test/validation.test.ts
@@ -0,0 +1,122 @@
+import { describe, expect, it } from 'vitest';
+import {
+ validateArtSet,
+ validateFactoryArt,
+ validateRenderableArt,
+ validateSpeciesName,
+ validateTier,
+} from '../src/index.js';
+
+describe('species names', () => {
+ it('accepts the charset the contract allows', () => {
+ for (const name of ["Warlock", "Fire Drake", "K9", "Ol' One-Eye", 'x', 'A name that is 31 bytes long ok']) {
+ expect(validateSpeciesName(name).valid).toBe(true);
+ }
+ });
+
+ it('rejects the injection characters the contract guards against', () => {
+ // components_to_json and the SVG builder embed names unescaped, so these
+ // would break every token's metadata for that species.
+ for (const name of ['bad"name', 'bad\\name', '', 'a,b', 'ab']) {
+ expect(validateSpeciesName(name).valid).toBe(false);
+ }
+ });
+
+ it('rejects empty and edge-space names', () => {
+ expect(validateSpeciesName('').valid).toBe(false);
+ expect(validateSpeciesName(' Warlock').valid).toBe(false);
+ expect(validateSpeciesName('Warlock ').valid).toBe(false);
+ });
+
+ it('rejects names past the felt252 limit', () => {
+ expect(validateSpeciesName('a'.repeat(31)).valid).toBe(true);
+ expect(validateSpeciesName('a'.repeat(32)).valid).toBe(false);
+ });
+
+ it('counts bytes, not code points', () => {
+ // Multi-byte characters are outside the charset anyway, but the length
+ // check must not be fooled into thinking they fit.
+ expect(validateSpeciesName('é'.repeat(20)).valid).toBe(false);
+ });
+});
+
+describe('renderable art', () => {
+ it('accepts every allowed media type', () => {
+ for (const uri of [
+ 'data:image/png;base64,iVBORw0KGgo=',
+ 'data:image/gif;base64,R0lGODlhAQAB',
+ 'data:image/webp;base64,UklGRhIAAABX',
+ 'data:image/svg+xml;base64,PHN2Zy8+',
+ ]) {
+ expect(validateRenderableArt(uri).valid).toBe(true);
+ }
+ });
+
+ it('rejects non-image media types', () => {
+ expect(validateRenderableArt('data:text/html;base64,PHNjcmlwdD4=').valid).toBe(false);
+ });
+
+ it('rejects URL-encoded SVG, which carries raw markup', () => {
+ expect(validateRenderableArt('data:image/svg+xml, ').valid).toBe(false);
+ });
+
+ it('rejects an attribute escape', () => {
+ // The art is embedded inside a single-quoted src='...' attribute.
+ expect(validateRenderableArt("data:image/png;base64,AAAA'AAA").valid).toBe(false);
+ });
+
+ it('rejects payloads that are not 4-aligned', () => {
+ expect(validateRenderableArt('data:image/png;base64,AAAAA').valid).toBe(false);
+ });
+
+ it('rejects an empty payload', () => {
+ expect(validateRenderableArt('data:image/png;base64,').valid).toBe(false);
+ });
+
+ it('rejects interior padding', () => {
+ expect(validateRenderableArt('data:image/png;base64,AA=ABBBB').valid).toBe(false);
+ });
+});
+
+describe('factory art', () => {
+ it('accepts real PNG and both GIF versions', () => {
+ expect(validateFactoryArt('data:image/png;base64,iVBORw0KGgoAAAA1', 'png').valid).toBe(true);
+ expect(validateFactoryArt('data:image/gif;base64,R0lGODdhAAA1', 'gif').valid).toBe(true);
+ expect(validateFactoryArt('data:image/gif;base64,R0lGODlhAAA1', 'gif').valid).toBe(true);
+ });
+
+ it('rejects a payload without PNG magic bytes', () => {
+ expect(validateFactoryArt('data:image/png;base64,AAAAAAAAAAAA', 'png').valid).toBe(false);
+ });
+
+ it('rejects a truncated GIF signature', () => {
+ // "R0lGODAAAAAA" decodes to the invalid header GIF80; the version
+ // characters have to be checked, not just the "R0lGOD" stem.
+ expect(validateFactoryArt('data:image/gif;base64,R0lGODAAAAAA', 'gif').valid).toBe(false);
+ });
+
+ it('rejects a GIF submitted as a PNG', () => {
+ expect(validateFactoryArt('data:image/gif;base64,R0lGODdhAAA1', 'png').valid).toBe(false);
+ });
+
+ it('validates a whole set and names the offending variant', () => {
+ const good = {
+ pngRegular: 'data:image/png;base64,iVBORw0KGgoAAAA1',
+ pngShiny: 'data:image/png;base64,iVBORw0KGgoAAAA2',
+ gifRegular: 'data:image/gif;base64,R0lGODdhAAA1',
+ gifShiny: 'data:image/gif;base64,R0lGODdhAAA2',
+ };
+ expect(validateArtSet(good).valid).toBe(true);
+
+ const bad = validateArtSet({ ...good, gifShiny: 'data:image/gif;base64,AAAAAAAA' });
+ expect(bad.valid).toBe(false);
+ expect(bad.error).toMatch(/^Shiny GIF:/);
+ });
+});
+
+describe('tier', () => {
+ it('accepts 1 through 5 only', () => {
+ for (const tier of [1, 2, 3, 4, 5]) expect(validateTier(tier).valid).toBe(true);
+ for (const tier of [0, 6, -1, 1.5]) expect(validateTier(tier).valid).toBe(false);
+ });
+});
diff --git a/sdk/tsconfig.build.json b/sdk/tsconfig.build.json
new file mode 100644
index 0000000..1c207e7
--- /dev/null
+++ b/sdk/tsconfig.build.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src"
+ },
+ "include": ["src/**/*"]
+}
diff --git a/sdk/tsconfig.json b/sdk/tsconfig.json
new file mode 100644
index 0000000..25b8ca1
--- /dev/null
+++ b/sdk/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "lib": ["ES2022", "DOM"],
+ "strict": true,
+ "noUncheckedIndexedAccess": false,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "declaration": true,
+ "outDir": "dist"
+ },
+ "include": ["src/**/*", "test/**/*"]
+}
diff --git a/sdk/vitest.config.ts b/sdk/vitest.config.ts
new file mode 100644
index 0000000..43e56f4
--- /dev/null
+++ b/sdk/vitest.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ include: ['test/**/*.test.ts'],
+ },
+});