diff --git a/.claude/agents/ux-review.md b/.claude/agents/ux-review.md index 12cc672..a16054a 100644 --- a/.claude/agents/ux-review.md +++ b/.claude/agents/ux-review.md @@ -4,33 +4,23 @@ Purpose: - review the store surfaces for discoverability, audience fit, docs parity, and developer evaluation quality Required read order: -1. `.codex/STATE.md` -2. `README.md` -3. `docs/api.md` -4. `docs/architecture.md` -5. `internal/httpapi/server.go` -6. `internal/httpapi/openapi.go` -7. `internal/webui/handler.go` -8. `web/index.html` -9. `web/reference.html` -10. `web/advanced.html` -11. `web/store.js` -12. `web/console.js` -13. `web/style.css` +1. `README.md` +2. `docs/api.md` +3. `docs/architecture.md` +4. `internal/httpapi/server.go` +5. `internal/httpapi/store_public.go` +6. `internal/service/storefront_wallet.go` +7. `frontend/src/App.tsx` +8. `internal/webui/handler.go` Required output: - findings ordered by severity -- surface classification: - - store app - - API reference - - advanced/developer tool - friction points by audience: - - first-time store visitor - - returning store visitor + - first-time shopper + - returning shopper - first-time developer - - protocol/debug operator - docs mismatches -- recommendations limited to product structure, discoverability, next-step guidance, and trust-building +- recommendations limited to signed wallet flows, store usability, docs parity, and trust-building Non-goals: - no implementation diff --git a/.claude/rules/api-contract.md b/.claude/rules/api-contract.md index f16c789..3175640 100644 --- a/.claude/rules/api-contract.md +++ b/.claude/rules/api-contract.md @@ -1,24 +1,26 @@ # API Contract Rules -- prefix all API routes with `/api/v1` +- active API routes are only: + - `GET /api/store/bootstrap` + - `POST /api/store/init` + - `POST /api/store/update` + - `GET /api/store/content/{id}` - amounts are decimal strings, never floats - error envelope: ```json {"error":{"code":"snake_case","message":"lowercase message"}} ``` -- raw mutation routes in `/advanced` use `requireWriteAccess()` -- `requireWriteAccess()` accepts: - - bearer key - - unlocked write-session cookie -- store product routes are browser-cookie scoped and do not require write unlock for normal use -- `POST /api/v1/app-session/submit-state` is the single store mutation endpoint -- `POST /api/v1/app-session/submit-state` must dispatch from `session_data.action` +- store state-changing routes are wallet-signature scoped +- `POST /api/store/init` verifies `packCreateAppSessionRequestV1(definition, session_data)` +- `POST /api/store/update` verifies `packAppStateUpdateV1(app_state_update)` +- `POST /api/store/update` dispatches from `app_state_update.intent` +- deposit responses are app-signed checkpoints; bootstrap may return `pending_action` until the browser-side Clearnode submit is observed +- `GET /api/store/content/{id}` is a public demo read path and must still require a submitted wallet purchase +- do not present the content read gate as production-grade authorization - supported public actions are: - - `deposit` + - `user_deposit` - `purchase` - `user_withdraw` -- hidden developer-only action: - - `app_withdraw` - - only allowed when write access is present - server must never trust client purchase price or allocation math -- one browser-scoped store session per asset +- supported demo assets are `yusd` and `yellow` +- one wallet-scoped store session per supported asset diff --git a/.claude/skills/add-store-endpoint.md b/.claude/skills/add-store-endpoint.md index 9dc59b4..d2243b3 100644 --- a/.claude/skills/add-store-endpoint.md +++ b/.claude/skills/add-store-endpoint.md @@ -4,12 +4,12 @@ Create: - handler stub - service/store method stub - route registration -- OpenAPI entry - test stubs - store UI hook if user-facing Keep: - decode -> service -> encode shape -- `session_data` as the store mutation contract -- browser-cookie session semantics +- signed wallet request semantics +- `app_state_update.intent` as the store mutation dispatcher +- `session_data.intent` as the store action detail - decimal string amounts diff --git a/.claude/skills/run-store-demo-flow.md b/.claude/skills/run-store-demo-flow.md index f8fab3d..a043bba 100644 --- a/.claude/skills/run-store-demo-flow.md +++ b/.claude/skills/run-store-demo-flow.md @@ -2,16 +2,18 @@ Sequence: 1. open `/` -2. create or load a store session -3. deposit into the session -4. purchase an item -5. read purchased content -6. withdraw remaining user balance +2. Connect wallet +3. create or load the wallet store session +4. deposit into the app session +5. purchase item `1` for `0.9` YUSD +6. read purchased content +7. withdraw remaining user balance Require: - funded demo wallet - reachable clearnode - selected asset supported by the catalog +- direct `@yellow-org/sdk` wallet signing available Output: - step result diff --git a/.claude/skills/trace-store-session-flow.md b/.claude/skills/trace-store-session-flow.md index f1a36be..53a4921 100644 --- a/.claude/skills/trace-store-session-flow.md +++ b/.claude/skills/trace-store-session-flow.md @@ -2,7 +2,7 @@ Trace: - store handler -- storefront service +- wallet store service - store persistence - Nitrolite SDK call chain diff --git a/.claude/skills/update-store-ui.md b/.claude/skills/update-store-ui.md index 38ed607..eb0cf59 100644 --- a/.claude/skills/update-store-ui.md +++ b/.claude/skills/update-store-ui.md @@ -5,7 +5,7 @@ Check: - asset switching is clear - session status is understandable - purchase and content-access states are explicit -- hidden developer surfaces stay out of the main store nav +- action labels remain `Connect`, `Deposit`, `Withdraw`, and `Purchase` Output: - UI/API mismatches diff --git a/.env.example b/.env.example index 96f44d0..c82baed 100644 --- a/.env.example +++ b/.env.example @@ -1,26 +1,23 @@ -# Clearnode WebSocket URL - use sandbox for development -CLEARNODE_WS_URL=wss://clearnode-sandbox.yellow.org/v1/ws +# Nitronode endpoint URL +CLEARNODE_WS_URL=wss://nitronode-stress.yellow.org/v1/ws # Demo signer private key (generate a new key: openssl rand -hex 32) # This wallet must have sandbox funds. Never use a mainnet key here. DEMO_PRIVATE_KEY=0xyour_private_key_here -# Console API key - required for all mutation endpoints (min 32 chars) -# Generate: openssl rand -hex 32 -CONSOLE_API_KEY=your_random_32_char_key_here - # Blockchain RPC endpoints (JSON map of chainID -> RPC URL) BLOCKCHAIN_RPC_URLS={"11155111":"https://sepolia.example.rpc"} # Home blockchain per asset (JSON map of asset symbol -> chainID) HOME_BLOCKCHAINS={"yusd":11155111,"yellow":11155111} +# Default amount used when preparing a home channel from on-chain test tokens +STORE_CHANNEL_BOOTSTRAP_AMOUNTS={"yusd":"10","yellow":"10"} + # Optional PORT=8080 LOG_LEVEL=info -SQLITE_PATH=./data/nitrolite-go-example.db +SQLITE_PATH=./data/nitrolite-store-example.db STORE_NAME=Nitrolite App Session Store STORE_APP_ID=default STORE_APP_PRIVATE_KEY= -MERCHANT_NAME=Nitrolite Sandbox Merchant -MERCHANT_APP_ID=default diff --git a/AGENTS.md b/AGENTS.md index eb1586b..3f77570 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,7 @@ # AGENTS Read order: + 1. `README.md` 2. `CLAUDE.md` 3. `docs/api.md` @@ -10,25 +11,23 @@ Read order: 7. `internal/nitrolite/manager.go` 8. `internal/service/` 9. `internal/httpapi/` -10. `internal/webui/handler.go` -11. `web/` +10. `frontend/` +11. `internal/webui/handler.go` Ownership: - `internal/config`: env parsing and validation -- `internal/store`: SQLite schema, store sessions, purchases -- `internal/signing`: signer abstraction, demo signer, derived store-app signer +- `internal/store`: SQLite wallet sessions and purchases +- `internal/signing`: signer abstraction and store app signer - `internal/nitrolite`: SDK lifecycle and reconnect manager -- `internal/service`: store orchestration, catalog/content logic, raw SDK-backed business logic -- `internal/httpapi`: decode -> service -> encode, browser cookie flow, write auth, OpenAPI surface -- `internal/webui`: page routing for embedded assets -- `web/`: store UI, embedded reference shell, advanced developer console +- `internal/service`: wallet store orchestration, catalog, signed update verification, and content gating +- `internal/httpapi`: request decode, service calls, and response encoding +- `frontend`: React + direct Nitrolite v1 TypeScript SDK browser flow +- `internal/webui`: embedded asset serving Current scope: -- same-binary Go server + embedded web assets -- `/` App Session Micropayment Store -- `/reference` OpenAPI-backed embedded explorer -- `/advanced` raw protocol/developer console -- one browser-scoped store session per asset +- same-binary Go server plus embedded frontend assets +- `/` content store +- one wallet-owned store session per asset - seeded content catalog with purchased-content gating diff --git a/CLAUDE.md b/CLAUDE.md index 31d1c09..4ee120b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,15 +1,18 @@ # CLAUDE Module: -- `github.com/layer-3/nitrolite-go-example` + +- `github.com/layer-3/nitrolite-store-example` Commands: + ```bash go run ./cmd/server -env CGO_ENABLED=0 GOCACHE=/tmp/nitrolite-go-example-gocache go test ./... -docker build -t nitrolite-go-example . +env CGO_ENABLED=0 GOCACHE=/tmp/nitrolite-store-example-gocache go test $(go list ./... | grep -v '/frontend/node_modules/') +docker build -t nitrolite-store-example . go vet ./... gofmt -w . +cd frontend && npm run lint && npm run typecheck && npm run build ``` Key paths: @@ -18,11 +21,19 @@ Key paths: - persistence: `internal/store` - api: `internal/httpapi` - services: `internal/service` +- frontend source: `frontend` - web router: `internal/webui/handler.go` -- web assets: `web` +- embedded assets: `internal/webui/dist` Product surfaces: -- `/`: App Session Micropayment Store -- `/reference`: embedded API reference -- `/advanced`: raw developer/debug console +- `/`: content store +- `/healthz`: process health +- `/readyz`: Clearnode readiness + +Active API: + +- `GET /api/store/bootstrap` +- `POST /api/store/init` +- `POST /api/store/update` +- `GET /api/store/content/{id}` diff --git a/Dockerfile b/Dockerfile index 5a9f4c5..752b063 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,14 @@ +FROM node:24-bookworm-slim AS frontend-build + +WORKDIR /src/frontend + +COPY frontend/package.json frontend/package-lock.json ./ +COPY frontend/vendor ./vendor +RUN npm ci + +COPY frontend ./ +RUN npm run build + FROM golang:1.25-bookworm AS build WORKDIR /src @@ -6,6 +17,7 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . +COPY --from=frontend-build /src/internal/webui/dist ./internal/webui/dist ENV CGO_ENABLED=0 GOOS=linux GOARCH=amd64 RUN go build -o /out/app ./cmd/server @@ -22,7 +34,7 @@ RUN apt-get update \ COPY --from=build /out/app /app/app ENV PORT=8080 -ENV SQLITE_PATH=/app/data/nitrolite-go-example.db +ENV SQLITE_PATH=/app/data/nitrolite-store-example.db ENV STORE_NAME="Nitrolite App Session Store" ENV STORE_APP_ID=default ENV LOG_LEVEL=info diff --git a/README.md b/README.md index e0cc715..ed26fa8 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,101 @@ -# nitrolite-go-example +# nitrolite-store-example -Go backend reference app for a Nitrolite-backed **content store** with a **TypeScript + MetaMask** frontend. +Go backend and React frontend for a Nitrolite-backed content store using the Nitrolite v1 TypeScript SDK from the browser and the Go SDK from the server. -One Go service serves the built frontend and the store API from the same origin. The shopper experience is intentionally small: +The shopper flow is intentionally narrow: -- connect MetaMask -- add funds -- buy content -- read purchased content -- withdraw remaining balance +1. Connect MetaMask. +2. Prepare the selected asset home channel when the wallet is not ready yet. +3. Create a two-party app session between the shopper wallet and store app signer. +4. Deposit YUSD into the store session. +5. Purchase content. +6. Read purchased content. +7. Withdraw remaining store balance. -Protocol details stay behind the implementation boundary. The main UI does not expose raw Nitrolite or channel-management surfaces. +`YUSD` is the default walkthrough asset. `YELLOW` is also exposed as a second testnet asset so the same wallet/session flows can be exercised against another configured asset before mainnet asset names are finalized. ## Surfaces -- `/` shopper-facing store UI -- `/healthz` process health -- `/readyz` Clearnode readiness - -## What This Demonstrates - -- a Go backend that validates, app-signs, and submits frontend-constructed app-session updates -- a React + Vite frontend that uses MetaMask as the real shopper identity -- automatic app-session bootstrap after wallet connect -- exact-payload forwarding: the update the user signs is the update the backend submits -- instant content gating after successful purchase -- YUSD and YELLOW catalog pricing from one seeded catalog - -## Trust model - -This refresh is wallet-first. - -- MetaMask is the shopper identity -- the frontend constructs the full app-session update -- the shopper signs the update in MetaMask -- the backend validates the same payload, app-signs it, and submits it -- the backend does **not** sign as the user -- channel management is assumed to exist already and is out of scope for this app - -Session keys are intentionally deferred to a later phase. +- `/`: store UI +- `/healthz`: process health +- `/readyz`: Nitronode readiness +- `GET /api/store/bootstrap` +- `POST /api/store/init` +- `POST /api/store/update` +- `GET /api/store/content/{id}` + +## Trust Model + +- MetaMask is the shopper identity. +- The frontend constructs the app session definition and app state updates. +- The shopper signs with MetaMask using direct `@yellow-org/sdk` v1 packers. +- The backend verifies the exact signed payload before adding the store app signature. +- The backend never signs as the shopper. +- Store authorization is based on app-session signatures, not login cookies. +- Deposit checkpoints store the signed deposit payload long enough to resume a browser-side Nitronode submit after reload or timeout. +- This is not a production-ready authorization model: content reads use a public example-app gate keyed by wallet, item, and submitted purchase status, so production apps should add an authenticated read session, signed read proof, or equivalent boundary before serving confidential content. + +## Required Flows + +### App Session Creation + +1. User presses `Connect`. +2. Frontend requests MetaMask accounts. +3. Frontend calls `GET /api/store/bootstrap?wallet_address=...&asset=yusd`. +4. If `channel_readiness.status` is not `ready`, the frontend asks the user to prepare the channel first. +5. For `ack_required`, the browser SDK acknowledges the pending off-chain state and checkpoints when needed. +6. For `deposit_required`, the browser SDK deposits the configured bootstrap amount from on-chain test tokens and checkpoints. +7. Frontend constructs `AppDefinitionV1` with shopper and app signer participants, both weight `1`, quorum `2`, and `nonce: BigInt(Date.now() * 1000000)`. +8. Frontend encodes with `packCreateAppSessionRequestV1`. +9. MetaMask signs the encoded payload. +10. Frontend calls `POST /api/store/init`. +11. Backend verifies the definition and shopper signature. +12. Backend app-signs and calls `sdkClient.CreateAppSession`. +13. Frontend receives success and shows the session as ready. + +### Deposit + +1. User enters a YUSD amount and presses `Deposit`. +2. Frontend uses cached bootstrap data or refreshes `GET /api/store/bootstrap`. +3. Frontend constructs `AppStateUpdateV1` with `AppStateUpdateIntent.Deposit`. +4. `sessionData` is `{"intent":"user_deposit","amount":"..."}`. +5. Frontend encodes with `packAppStateUpdateV1`. +6. MetaMask signs the encoded payload. +7. Frontend calls `POST /api/store/update`. +8. Backend verifies the update, signature, version, participants, asset, and allocation delta. +9. Backend persists a signed deposit checkpoint and returns the store app signature. +10. Frontend submits to Nitronode with `submitAppSessionDeposit`. +11. Frontend refreshes bootstrap and shows the updated store balance. + +If the browser is closed or the Nitronode submit times out after step 9, bootstrap returns `pending_action` for the signed deposit. The frontend shows `Resume`, which reuses the stored signatures and does not ask MetaMask to sign again. + +### Withdraw + +1. User enters a YUSD amount and presses `Withdraw`. +2. Frontend constructs `AppStateUpdateV1` with `AppStateUpdateIntent.Withdraw`. +3. `sessionData` is `{"intent":"user_withdraw"}`. +4. Frontend signs with MetaMask and calls `POST /api/store/update`. +5. Backend verifies, app-signs, submits with `sdkClient.SubmitAppState`, and returns refreshed bootstrap data. + +`submitAppSessionDeposit` is deposit-specific. Withdraw follows the backend `SubmitAppState` path. + +### Purchase + +1. User chooses item `1` and presses `Purchase`. +2. Frontend constructs `AppStateUpdateV1` with `AppStateUpdateIntent.Operate`. +3. The YUSD example payload is `{"intent":"purchase","item_id":1,"item_price":"0.9"}`. +4. Frontend signs with MetaMask and calls `POST /api/store/update`. +5. Backend verifies item ownership, catalog price, allocation delta, signature, and session version. +6. Backend app-signs, submits with `sdkClient.SubmitAppState`, records ownership, and returns refreshed bootstrap data. + +Purchase uses backend `SubmitAppState` because it is not a deposit operation. + +### Open Purchased Content + +1. User chooses an owned library item and presses `Open`. +2. Frontend calls `GET /api/store/content/{id}?wallet_address=...&asset=...`. +3. Backend checks the wallet session, asset, item id, and submitted purchase before returning content. +4. This read path is intentionally public for demo ergonomics and should not be used as-is for confidential production content. ## Quickstart @@ -49,181 +106,59 @@ go run ./cmd/server Open [http://localhost:8080/](http://localhost:8080/). -If you were previously running an older build of this app, stop that server first. Web assets are embedded into the Go binary, so an older process will keep serving stale UI until restarted. - -## How To Use The Store - -The main product surface is `/`. - -Normal flow: - -1. Open `/` -2. Connect MetaMask on Sepolia -3. Wait for the store session to bootstrap automatically -4. Add funds to the store balance -5. Buy an item from the catalog -6. Open it from `Library` -7. Withdraw any remaining balance - -The main panels mean: - -- `Wallet` shows the connected shopper identity -- `Available balance` is what can still be committed into the store -- `Store balance` is the shopper allocation already inside the store session -- `Catalog` lists seeded content and prices for the selected asset -- `Library` shows wallet-owned content -- `Reader` displays purchased content after ownership is confirmed -- `Browser activity` is a client-side trace for debugging - -## Frontend development - -The product UI now lives in `frontend/` and is built with React + Vite + TypeScript. - -Development shape: - -- run the Go API separately -- run Vite in `frontend/` -- proxy `/api/*` to the Go server - -Production shape: - -- build the frontend into `internal/webui/dist` -- run the Go server -- the Go server serves the built frontend and API from the same origin - -## Railway deployment - -The recommended production-like deployment for this repo is a single Railway service backed by the included `Dockerfile`. - -Expected Railway shape: - -- one web service for the whole app -- repo-linked to `main` -- one attached volume mounted at `/app/data` -- `SQLITE_PATH=/app/data/nitrolite-go-example.db` - -Recommended first-time flow: - -1. Link the repo to the target project: +## Frontend Development ```bash -railway link --workspace --project +cd frontend +npm ci +npm run dev ``` -2. Add or link the service that will run this repo. -3. Add a volume and mount it at `/app/data`. -4. Set the required variables on the service. -5. Deploy from the repo or run `railway up` from the repo root. - -If you are deploying inside the Yellow org, use the appropriate internal workspace/project instead of the placeholders above. +The Vite dev server proxies `/api/*` to the Go server. Production assets build into `internal/webui/dist`. -Useful Railway CLI commands: - -```bash -railway volume add --mount-path /app/data -railway variable set CLEARNODE_WS_URL=... DEMO_PRIVATE_KEY=... CONSOLE_API_KEY=... BLOCKCHAIN_RPC_URLS='{"11155111":"https://..."}' HOME_BLOCKCHAINS='{"yusd":11155111,"yellow":11155111}' SQLITE_PATH=/app/data/nitrolite-go-example.db STORE_NAME="Nitrolite App Session Store" STORE_APP_ID=default -railway up --service -railway service status --service -``` - -If Railway cannot fetch the GitHub repo initially, the fallback is a first deploy from the local checkout with `railway up`, then converting the service to repo-linked afterward. - -## Required environment +## Environment Required: - `CLEARNODE_WS_URL` - `DEMO_PRIVATE_KEY` -- `CONSOLE_API_KEY` - `BLOCKCHAIN_RPC_URLS` - `HOME_BLOCKCHAINS` -Optional with defaults: +Optional: -- `PORT=8080` locally; Railway injects `PORT` automatically +- `PORT=8080` - `LOG_LEVEL=info` -- `SQLITE_PATH=./data/nitrolite-go-example.db` +- `SQLITE_PATH=./data/nitrolite-store-example.db` - `STORE_NAME=Nitrolite App Session Store` - `STORE_APP_ID=default` -- `STORE_APP_PRIVATE_KEY=` to override the derived store-app signer - -Runtime assumptions: - -- the demo signer wallet must already have sandbox funds -- for a shared deployment, the signer should be a team-owned funded sandbox key -- the configured home-channel assets must exist on the node -- the RPC URLs must support the configured home chains -- `/healthz` reports process health even while the SDK is reconnecting; `/readyz` stays `503` until the Clearnode connection is live - -## API shape - -Public store routes: - -- `POST /api/store/connect/challenge` -- `POST /api/store/connect/verify` -- `GET /api/store/bootstrap?asset=...` -- `POST /api/store/update` -- `GET /api/store/content/{id}?asset=...` -- `GET /healthz` -- `GET /readyz` - -The backend receives the full frontend-constructed update payload, validates it, app-signs it, and submits the same payload to Clearnode. - -## Persistence - -SQLite stores: +- `STORE_APP_PRIVATE_KEY=` +- `STORE_CHANNEL_BOOTSTRAP_AMOUNTS={"yusd":"10","yellow":"10"}` -- browser-scoped store sessions -- purchases -- legacy unused tables that are no longer part of the active product path +## Local Data -Default path: +SQLite stores wallet app sessions and purchases. -- `./data/nitrolite-go-example.db` +Default local path: -Recommended Railway path: +- `./data/nitrolite-store-example.db` -- `/app/data/nitrolite-go-example.db` - -If you are switching from an older build, delete the old local DB first if you want a clean store state: +Reset local store state: ```bash -rm -f ./data/nitrolite-go-example.db +rm -f ./data/nitrolite-store-example.db ``` -## Running tests - -Standard: +## Verification ```bash -go test ./... +go test $(go list ./... | grep -v '/frontend/node_modules/') +go vet ./... +cd frontend +npm ci +npm run lint +npm run typecheck +npm run build +cd .. +docker build -t nitrolite-store-example . ``` - -If your machine blocks cgo builds because of the local Xcode license state, use: - -```bash -CGO_ENABLED=0 GOCACHE=/tmp/nitrolite-go-example-gocache go test ./... -``` - -## Troubleshooting - -If you still see an older UI or the old “Go SDK guided demo” UI: - -- stop the existing process on `:8080` -- restart with `go run ./cmd/server` -- hard refresh the browser - -If store actions fail: - -- check `/healthz` -- confirm the demo wallet has balance in the selected asset -- on Railway, confirm the volume is attached and `SQLITE_PATH` points at `/app/data/nitrolite-go-example.db` -- inspect `/advanced` for raw SDK state -- use `/reference` to inspect the live request/response shapes - -## Where to look - -- [`AGENTS.md`](./AGENTS.md) -- [`CLAUDE.md`](./CLAUDE.md) -- [`docs/api.md`](./docs/api.md) -- [`docs/architecture.md`](./docs/architecture.md) diff --git a/cmd/server/main.go b/cmd/server/main.go index fec2378..7baa23d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -9,11 +9,11 @@ import ( "syscall" "time" - "github.com/layer-3/nitrolite-go-example/internal/config" - internalhttp "github.com/layer-3/nitrolite-go-example/internal/httpapi" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" + "github.com/layer-3/nitrolite-store-example/internal/config" + internalhttp "github.com/layer-3/nitrolite-store-example/internal/httpapi" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" + "github.com/layer-3/nitrolite-store-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/store" ) func main() { diff --git a/docs/api.md b/docs/api.md index 10b2ee7..1428d84 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,83 +1,118 @@ # API -Primary reference surface: [`/reference`](http://localhost:8080/reference) +The store API is intentionally small. App-session creation and state changes are wallet-signature driven; content reads use a public demo gate. -Machine-readable spec: [`/openapi.json`](http://localhost:8080/openapi.json) +## `GET /api/store/bootstrap` -The OpenAPI document served by the Go backend is the source of truth for: +Query: -- route inventory -- request/response examples -- raw write-auth expectations -- store session semantics +- `wallet_address` +- `asset`, optional, defaults to the configured default asset -## Main route groups +Returns store metadata, supported assets, available signed home-channel balance, channel readiness, catalog, current wallet session state, wallet-owned library items, and an optional pending deposit action. -- Health / Wallet / Node -- Store -- Catalog -- Content -- Raw Channel -- Raw Sessions -- Raw Session Keys -- Auth -- Legacy +`channel_readiness.status` is one of: -## Store routes +- `ready`: the selected asset has a signed home-channel state with positive user balance. +- `ack_required`: Nitronode has off-chain funds that need wallet acknowledgement. +- `deposit_required`: the wallet can prepare a channel from on-chain test tokens. +- `funds_required`: no usable off-chain or on-chain funds were found for the selected asset. +- `unavailable`: Nitronode or the configured chain RPC could not be checked. -- `GET /api/v1/store/config` -- `GET /api/v1/catalog` -- `GET /api/v1/catalog/{id}` -- `GET /api/v1/store/session?asset=...` -- `POST /api/v1/store/session/create` -- `POST /api/v1/app-session/submit-state` -- `GET /api/v1/purchases` -- `GET /api/v1/content/{id}` -- `GET /api/v1/balance?asset=...` +Supported demo assets are `yusd` and `yellow`. `yusd` is the default walkthrough asset; `yellow` is retained as a second testnet asset for the same app-session flows. -## Store auth model +## `POST /api/store/init` -Reads are public. +Creates the app session after the frontend signs the app definition. -Store product routes use a browser-scoped cookie: +Request fields: -- `GET /api/v1/store/config` ensures the cookie exists -- store sessions and purchases are isolated per browser cookie value -- no wallet connect and no external login is required in v1 +- `wallet_address`, optional consistency check +- `asset` +- `definition` +- `session_data` +- `user_signature` -Raw mutation routes in `/advanced` use `requireWriteAccess()`: +The backend verifies the shopper signature over `packCreateAppSessionRequestV1(definition, session_data)`, adds the store app signature, calls `sdkClient.CreateAppSession`, persists the session, and returns bootstrap data. -- bearer key or unlocked write-session cookie +## `POST /api/store/update` -Hidden developer-only capability: +Handles user deposit, user withdraw, and purchase updates. -- `app_withdraw` still goes through `POST /api/v1/app-session/submit-state` -- but the server only allows it when write access is present +Request fields: -## Submit-state contract +- `wallet_address`, optional consistency check +- `asset` +- `app_state_update` +- `user_signature` -`POST /api/v1/app-session/submit-state` is the single store mutation endpoint. +The backend verifies the shopper signature over `packAppStateUpdateV1(app_state_update)` and dispatches by `app_state_update.intent`. -Required request fields: +Deposit returns: -- `session_id` -- `asset` -- `session_data` +- `status: "signed"` +- `intent: "user_deposit"` +- `app_signature` +- `pending_action`, containing the signed deposit payload needed for browser-side resume + +Withdraw and purchase return: + +- `status: "submitted"` +- `intent` +- `bootstrap` + +`app_state_update.intent` remains the Nitrolite protocol intent (`deposit`, `withdraw`, or `operate`). The nested `session_data.intent` is the store-level action (`user_deposit`, `user_withdraw`, or `purchase`). + +For deposits, the backend stores a checkpoint before returning the app signature. Bootstrap returns that checkpoint as `pending_action` until Nitronode reflects the submitted app session version, so the frontend can resume after reload without asking MetaMask to sign again. + +## `GET /api/store/content/{id}` + +Opens purchased content for a wallet and asset. + +Query: + +- `wallet_address` +- `asset`, `yusd` or `yellow` + +The backend confirms the wallet session, reconciles pending purchases, and returns content only for a submitted purchase. + +This is intentionally a public example-app read path. It does not prove the caller controls `wallet_address`; production content APIs should use an authenticated read session, signed read proof, or equivalent authorization boundary. -`session_data` is JSON encoded as a string and must describe the action: +`POST /api/store/content/{id}/open` is disabled and returns `405`. + +## Errors + +Errors use: + +```json +{"error":{"code":"stale_version","message":"app session version is stale"}} +``` + +Important signed-flow codes: + +- `invalid_signature` +- `stale_version` +- `insufficient_balance` +- `duplicate_purchase` +- `clearnode_unavailable` +- `clearnode_operation_failed` + +## Session Data + +Deposit: ```json -{"action":"deposit","amount":"1.00"} -{"action":"purchase","item_id":"article-micropayments","price":"0.50"} -{"action":"user_withdraw","amount":"0.50"} -{"action":"app_withdraw","amount":"0.50"} +{"intent":"user_deposit","amount":"1.00"} ``` -The server does not trust client business math: +Withdraw: -- purchase price is revalidated against the seeded catalog -- duplicate purchase is rejected -- user/app withdraw amounts are capped by current allocation -- only one asset is allowed per store session +```json +{"intent":"user_withdraw"} +``` -Use this file as orientation only. For concrete request and response bodies, use the embedded reference. +Purchase: + +```json +{"intent":"purchase","item_id":1,"item_price":"0.9"} +``` diff --git a/docs/architecture.md b/docs/architecture.md index 558a1c1..190e52b 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,83 +1,52 @@ # Architecture -## Runtime shape - -- `cmd/server` loads config, signers, Nitrolite manager, SQLite store, and the HTTP/web handler -- `internal/nitrolite.Manager` owns the active SDK client, health state, and reconnect loop -- `internal/store` owns SQLite persistence for browser-scoped store sessions and purchases -- `internal/service.StorefrontService` owns catalog, session bootstrap, submit-state dispatch, and content gating -- `internal/httpapi` is a thin transport layer with decode -> service -> encode plus raw write auth -- `web/` is a no-build static UI embedded into the Go binary - -## Deployment shape - -- local development runs with `go run ./cmd/server` -- Railway deployment should use the repo `Dockerfile` for deterministic build/start behavior -- Railway persistence should mount a volume at `/app/data` -- the Railway service should set `SQLITE_PATH=/app/data/nitrolite-go-example.db` -- the app remains a single service that serves UI, API, and developer surfaces from the same origin - -## Product surfaces - -- `/` - - App Session Micropayment Store - - deposit, purchase, withdraw, reader, and library -- `/reference` - - embedded RapiDoc explorer backed by `/openapi.json` -- `/advanced` - - raw developer/debug console - - JSON panels, raw mutations, session keys, destructive operations - -## Store session model - -- one browser-scoped store session per asset -- supported assets are data-driven from `HOME_BLOCKCHAINS` -- current seeded catalog supports YUSD and YELLOW pricing -- purchases are tracked per browser cookie and asset - -All product actions after session creation go through: - -- `POST /api/v1/app-session/submit-state` - -The server dispatches by `session_data.action`: - -- `deposit` -- `purchase` -- `user_withdraw` -- `app_withdraw` - -## Trust model - -This v1 build keeps Nitrolite signing on the server: - -- demo/user signer: `DEMO_PRIVATE_KEY` -- store/app signer: derived from `DEMO_PRIVATE_KEY` unless `STORE_APP_PRIVATE_KEY` is set -- browser identity: lightweight cookie namespace only - -That means: - -- the browser does not hold a Nitrolite signer yet -- the same backend signers service every browser -- store isolation is product-level and browser-scoped, not wallet-level - -This is deliberate to keep the example simple and runnable with the current Go SDK setup. - -## Startup sequence - -1. load config -2. initialize demo/user signer -3. derive or load store/app signer -4. initialize Nitrolite manager -5. initialize SQLite store -6. start `manager.Run(ctx)` -7. start `http.Server` - -There is no active merchant runner in the current product path. - -## Catalog and content - -- catalog metadata is seeded in `internal/service/store_app.go` -- each item has per-asset pricing -- content is stored inline with the seeded catalog for now -- successful purchase writes a `purchases` record immediately -- content access checks that purchase record before returning the body +## Runtime Shape + +- `cmd/server` loads config, signers, Nitrolite manager, SQLite store, and HTTP handler. +- `internal/nitrolite.Manager` owns the active SDK client, health state, and reconnect loop. +- `internal/store` persists wallet store sessions, purchases, and resumable deposit checkpoints. +- `internal/service.WalletStoreService` owns bootstrap, app-session creation, signed update verification, catalog, purchase recording, and content gating. +- `internal/httpapi` is a thin transport layer. +- `frontend/` is the React source. +- `internal/webui/dist` is the embedded production build served by Go. + +## Product Surface + +The only product page is `/`. + +It supports: + +- MetaMask connection +- app session creation +- YUSD deposit +- YUSD withdraw +- YUSD item purchase +- Yellow testnet deposit and withdraw +- Yellow testnet item purchase +- public demo purchased-content reading +- activity tracing + +## Store Session Model + +- One wallet-owned store session per supported asset. +- The app session has exactly two participants: shopper wallet and store app signer. +- Each participant has signature weight `1`. +- Quorum is `2`. +- Purchases are keyed by wallet, item, and asset. Deposit checkpoints are keyed by wallet and asset and hold the signed payload until the Clearnode session catches up. The active demo assets are `yusd` and `yellow`; `yusd` is the default walkthrough path. + +## Submission Boundaries + +- App session creation: backend calls `sdkClient.CreateAppSession`. +- Deposit: backend stores a checkpoint and returns the store app signature, frontend calls `submitAppSessionDeposit`, and bootstrap exposes `pending_action` if the browser needs to resume. +- Withdraw: backend calls `sdkClient.SubmitAppState`. +- Purchase: backend calls `sdkClient.SubmitAppState`. +- Content open: frontend calls a public demo GET route; backend verifies the wallet session and submitted purchase before returning content. This is not a production authorization boundary. + +## Startup Sequence + +1. Load config. +2. Initialize app signer. +3. Initialize Nitrolite manager. +4. Initialize SQLite store. +5. Start `manager.Run(ctx)`. +6. Start HTTP server. diff --git a/frontend/index.html b/frontend/index.html index 18be515..55d4594 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ - Simple Content Store + Nitrolite App Session Store
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 998cc25..dd679b1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,11 +8,14 @@ "name": "frontend", "version": "0.0.0", "dependencies": { - "@yellow-org/sdk": "1.2.1", - "@yellow-org/sdk-compat": "1.2.1", + "@yellow-org/sdk": "file:vendor/yellow-org-sdk-1.2.2.tgz", + "clsx": "^2.1.1", "decimal.js": "^10.6.0", + "lucide-react": "^1.11.0", + "motion": "^12.38.0", "react": "^19.2.5", "react-dom": "^19.2.5", + "tailwind-merge": "^3.5.0", "viem": "^2.46.2" }, "devDependencies": { @@ -21,10 +24,13 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "autoprefixer": "^10.5.0", "eslint": "^9.39.4", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.5.0", + "postcss": "^8.5.12", + "tailwindcss": "^3.4.19", "typescript": "~6.0.2", "typescript-eslint": "^8.58.2", "vite": "^8.0.9" @@ -36,6 +42,19 @@ "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", "license": "MIT" }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -684,6 +703,44 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@oxc-project/types": { "version": "0.126.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz", @@ -1433,9 +1490,9 @@ } }, "node_modules/@yellow-org/sdk": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@yellow-org/sdk/-/sdk-1.2.1.tgz", - "integrity": "sha512-ZRV1OjHLkCP3BOKaSRqsqfw8LOKo5TK5XU7LOS8JEiv7kRu3xApjCSjdof8EWkoMdwMYlU0fvRxxD5glTkuWBA==", + "version": "1.2.2", + "resolved": "file:vendor/yellow-org-sdk-1.2.2.tgz", + "integrity": "sha512-fOMrVZ+Qssi9oPY0IXSR7nKTjvma2sEAGTwRKfM4Rqnq85y/sq7cXzWa6ov2YN7+bnnvr3WoXQ+7fJZGqL6DSw==", "license": "MIT", "dependencies": { "abitype": "^1.2.3", @@ -1448,22 +1505,6 @@ "node": ">=20.0.0" } }, - "node_modules/@yellow-org/sdk-compat": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@yellow-org/sdk-compat/-/sdk-compat-1.2.1.tgz", - "integrity": "sha512-ksMLAZ+W0UQijX/8IhXk/d72B7lW0cpXYhkR0w5uytbZBcZbxVooZNEmoPoiJCoNb9n0BTc2k6RYHVNTDHRzgA==", - "license": "MIT", - "dependencies": { - "decimal.js": "^10.4.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@yellow-org/sdk": ">=1.2.1", - "viem": "^2.0.0" - } - }, "node_modules/abitype": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.4.tgz", @@ -1540,6 +1581,47 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1547,6 +1629,43 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1567,6 +1686,19 @@ "node": ">=6.0.0" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", @@ -1578,6 +1710,19 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.28.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", @@ -1622,6 +1767,16 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001790", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", @@ -1659,6 +1814,44 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -1674,6 +1867,15 @@ "node": ">=8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1692,6 +1894,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1721,6 +1933,19 @@ "node": ">= 8" } }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1769,6 +1994,20 @@ "node": ">=8" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.344", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.344.tgz", @@ -1776,6 +2015,16 @@ "dev": true, "license": "ISC" }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1996,6 +2245,36 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2010,6 +2289,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -2041,6 +2330,19 @@ "node": ">=16.0.0" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2079,6 +2381,47 @@ "dev": true, "license": "ISC" }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", + "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.38.0", + "motion-utils": "^12.36.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2094,6 +2437,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2145,6 +2498,19 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -2199,6 +2565,35 @@ "node": ">=0.8.19" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2222,6 +2617,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2270,7 +2675,17 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/js-tokens": { + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", @@ -2634,6 +3049,26 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2667,6 +3102,52 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.11.0.tgz", + "integrity": "sha512-UOhjdztXCgdBReRcIhsvz2siIBogfv/lhJEIViCpLt924dO+GDms9T7DNoucI23s6kEPpe988m5N0D2ajnzb2g==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -2680,6 +3161,47 @@ "node": "*" } }, + "node_modules/motion": { + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.38.0.tgz", + "integrity": "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.38.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", + "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.36.0" + } + }, + "node_modules/motion-utils": { + "version": "12.36.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", + "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2687,6 +3209,18 @@ "dev": true, "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -2720,6 +3254,36 @@ "dev": true, "license": "MIT" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2833,6 +3397,13 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2852,10 +3423,30 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", + "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", "dev": true, "funding": [ { @@ -2881,6 +3472,140 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2901,6 +3626,27 @@ "node": ">=6" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/react": { "version": "19.2.5", "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", @@ -2922,6 +3668,64 @@ "react": "^19.2.5" } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2932,6 +3736,17 @@ "node": ">=4" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rolldown": { "version": "1.0.0-rc.16", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz", @@ -2973,6 +3788,30 @@ "dev": true, "license": "MIT" }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -3035,6 +3874,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3047,6 +3909,90 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", + "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/tinyglobby": { "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", @@ -3064,6 +4010,19 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", @@ -3077,13 +4036,18 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", @@ -3183,6 +4147,13 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/viem": { "version": "2.48.4", "resolved": "https://registry.npmjs.org/viem/-/viem-2.48.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 43a61a2..c36121e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,11 +11,14 @@ "preview": "vite preview" }, "dependencies": { - "@yellow-org/sdk": "1.2.1", - "@yellow-org/sdk-compat": "1.2.1", + "@yellow-org/sdk": "file:vendor/yellow-org-sdk-1.2.2.tgz", + "clsx": "^2.1.1", "decimal.js": "^10.6.0", + "lucide-react": "^1.11.0", + "motion": "^12.38.0", "react": "^19.2.5", "react-dom": "^19.2.5", + "tailwind-merge": "^3.5.0", "viem": "^2.46.2" }, "devDependencies": { @@ -24,10 +27,13 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", + "autoprefixer": "^10.5.0", "eslint": "^9.39.4", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.5.0", + "postcss": "^8.5.12", + "tailwindcss": "^3.4.19", "typescript": "~6.0.2", "typescript-eslint": "^8.58.2", "vite": "^8.0.9" diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/frontend/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/frontend/src/App.css b/frontend/src/App.css index 927d577..d93e460 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,228 +1,25 @@ -.shell { - width: min(1120px, calc(100vw - 32px)); - margin: 0 auto; - padding: 32px 0 56px; +.shimmer-button { + position: relative; + overflow: hidden; } -.hero, -.panel { - background: rgba(255, 249, 239, 0.92); - border: 1px solid rgba(36, 32, 26, 0.08); - border-radius: 28px; - box-shadow: 0 24px 60px rgba(120, 104, 78, 0.14); +.shimmer-button::after { + content: ""; + position: absolute; + inset: -120% auto -120% -40%; + width: 38%; + transform: rotate(18deg); + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.58), transparent); + animation: shimmer-slide 3.8s ease-in-out infinite; + pointer-events: none; } -.hero { - display: grid; - grid-template-columns: minmax(0, 1.6fr) minmax(280px, 0.8fr); - gap: 24px; - padding: 32px; - margin-bottom: 24px; -} - -.eyebrow, -.label, -.meta { - color: #6b6257; - font-size: 0.82rem; - letter-spacing: 0.12em; - text-transform: uppercase; -} - -.lede, -.supporting, -.catalog-item p, -.library-item p { - color: #4a433b; - line-height: 1.65; -} - -.hero h1, -.panel h2, -.reader h3 { - margin: 8px 0 0; - color: #1f1b17; - font-family: 'Iowan Old Style', 'Palatino Linotype', serif; -} - -.hero-actions { - display: flex; - flex-direction: column; - gap: 16px; - align-items: flex-start; -} - -.identity-card, -.stat { - width: 100%; - padding: 18px 20px; - border-radius: 20px; - background: rgba(255, 255, 255, 0.65); - border: 1px solid rgba(36, 32, 26, 0.08); -} - -.grid { - display: grid; - gap: 24px; - margin-bottom: 24px; -} - -.two-up { - grid-template-columns: repeat(2, minmax(0, 1fr)); -} - -.panel { - padding: 28px; -} - -.panel-head { - display: flex; - justify-content: space-between; - gap: 16px; - align-items: flex-start; - margin-bottom: 20px; -} - -.stats { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 16px; - margin-bottom: 18px; -} - -.form-grid { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 16px; - align-items: end; -} - -.form-grid label, -.asset-picker { - display: flex; - flex-direction: column; - gap: 8px; - color: #3f372f; - font-weight: 600; -} - -input, -select, -button { - font: inherit; -} - -input, -select { - border: 1px solid rgba(36, 32, 26, 0.14); - border-radius: 14px; - padding: 13px 14px; - background: rgba(255, 255, 255, 0.92); - color: #201c17; -} - -button { - border: 0; - border-radius: 999px; - padding: 13px 18px; - font-weight: 700; - cursor: pointer; - transition: transform 0.16s ease, opacity 0.16s ease; -} - -button:disabled { - cursor: not-allowed; - opacity: 0.6; -} - -button:not(:disabled):hover { - transform: translateY(-1px); -} - -.primary { - background: linear-gradient(135deg, #145f4f, #1c7f68); - color: #fdfaf4; -} - -.secondary { - background: rgba(255, 255, 255, 0.85); - color: #145f4f; - border: 1px solid rgba(20, 95, 79, 0.2); -} - -.stack { - display: grid; - gap: 14px; -} - -.catalog-item, -.library-item { - display: flex; - justify-content: space-between; - gap: 16px; - align-items: flex-start; - padding: 18px; - border-radius: 20px; - background: rgba(255, 255, 255, 0.75); - border: 1px solid rgba(36, 32, 26, 0.08); -} - -.reader { - background: rgba(255, 255, 255, 0.75); - border-radius: 20px; - padding: 20px; - border: 1px solid rgba(36, 32, 26, 0.08); -} - -.reader pre { - margin: 0; - white-space: pre-wrap; - font-family: 'SF Mono', ui-monospace, monospace; - line-height: 1.7; - color: #2d2a26; -} - -.activity-list { - list-style: none; - padding: 0; - margin: 0; - display: grid; - gap: 10px; -} - -.activity-list li { - padding: 12px 14px; - border-radius: 14px; - background: rgba(255, 255, 255, 0.65); - font-family: 'SF Mono', ui-monospace, monospace; - font-size: 0.9rem; - color: #2e2923; -} - -.alert { - margin-bottom: 24px; - padding: 16px 18px; - border-radius: 18px; - background: #231d18; - color: #fff4e6; -} - -@media (max-width: 900px) { - .hero, - .two-up, - .stats, - .form-grid { - grid-template-columns: 1fr; +@keyframes shimmer-slide { + 0% { + transform: translateX(-220%) rotate(18deg); } - - .catalog-item, - .library-item, - .panel-head { - flex-direction: column; - } - - .shell { - width: min(100vw - 20px, 1120px); - padding-top: 20px; + 42%, + 100% { + transform: translateX(520%) rotate(18deg); } } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index eb0294f..77e2bd0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,32 +1,80 @@ -import { useEffect, useMemo, useRef, useState } from 'react' +import { type ReactNode, useEffect, useMemo, useState } from 'react' import Decimal from 'decimal.js' +import { AnimatePresence, motion, type HTMLMotionProps } from 'motion/react' +import { Activity, AlertTriangle, BookOpen, CheckCircle2, Copy, CreditCard, Library, Loader2, RefreshCw, ShieldCheck, ShoppingBag, Wallet } from 'lucide-react' +import { clsx, type ClassValue } from 'clsx' import { - NitroliteClient, - packCreateAppSessionHash, - packSubmitAppStateHash, - toWalletQuorumSignature, -} from '@yellow-org/sdk-compat' -import { applyCommitTransition, nextState, type State as ChannelState } from '@yellow-org/sdk' + AppSessionWalletSignerV1, + AppStateUpdateIntent, + ChannelDefaultSigner, + Client, + packAppStateUpdateV1, + packCreateAppSessionRequestV1, + withBlockchainRPC, + type AppDefinitionV1, + type AppStateUpdateV1, + type StateSigner, + type TransactionSigner, +} from '@yellow-org/sdk' import { createWalletClient, custom, type Address, type Hex, type WalletClient } from 'viem' import { sepolia } from 'viem/chains' +import { twMerge } from 'tailwind-merge' import './App.css' const DEFAULT_ASSET = 'yusd' -const DEFAULT_WS_URL = import.meta.env.VITE_CLEARNODE_WS_URL || 'wss://clearnode-sandbox.yellow.org/v1/ws' +const DEMO_ASSETS = ['yusd', 'yellow'] +const STORED_ASSET_KEY = 'nitrolite-store:selected-asset' +const DEPOSIT_SUBMIT_TIMEOUT_MS = 45_000 +const MAX_APPROVE_AMOUNT = new Decimal('1e18') +const DEFAULT_WS_URL = import.meta.env.VITE_CLEARNODE_WS_URL || 'wss://nitronode-stress.yellow.org/v1/ws' const DEFAULT_BLOCKCHAIN_RPCS: Record = { 11155111: import.meta.env.VITE_BLOCKCHAIN_RPC_11155111 || 'https://ethereum-sepolia-rpc.publicnode.com', } -const APP_STATE_INTENT = { - Operate: 0, - Deposit: 1, - Withdraw: 2, -} as const type InjectedProvider = { request: (args: { method: string; params?: unknown[] }) => Promise + on?: (event: 'accountsChanged' | 'chainChanged', listener: (value?: unknown) => void) => void + removeListener?: (event: 'accountsChanged' | 'chainChanged', listener: (value?: unknown) => void) => void isMetaMask?: boolean } +class BrowserWalletSigner implements StateSigner, TransactionSigner { + private readonly client: WalletClient + private readonly account: Address + + constructor(client: WalletClient, account: Address) { + this.client = client + this.account = account + } + + getAddress(): Address { + return this.account + } + + async signMessage(message: Hex | { raw: Hex }): Promise { + const raw = typeof message === 'string' ? message : message.raw + return this.client.signMessage({ + account: this.account, + message: { raw }, + }) + } + + async signPersonalMessage(hash: Hex): Promise { + return this.signMessage(hash) + } + + async sendTransaction(tx: Parameters[0]): Promise { + const rest = { ...tx } as Record + delete rest.account + delete rest.chain + return this.client.sendTransaction({ + ...rest, + account: this.account, + chain: sepolia, + } as Parameters[0]) + } +} + type StoreCatalogItem = { id: string title: string @@ -46,6 +94,47 @@ type StoreSession = { session_data?: string } +type RPCAppStateUpdate = { + app_session_id: string + intent: number + version: string + allocations: { + participant: string + asset: string + amount: string + }[] + session_data: string +} + +type StorePendingAction = { + type: string + status: string + asset: string + app_session_id: string + version: number + amount: string + app_state_update: RPCAppStateUpdate + user_signature: Hex + app_signature: Hex + created_at: string + updated_at: string +} + +type ChannelReadinessStatus = 'ready' | 'ack_required' | 'deposit_required' | 'funds_required' | 'unavailable' + +type StoreChannelReadiness = { + status: ChannelReadinessStatus + message: string + home_blockchain_id: number + bootstrap_amount: string + available_balance: string + pending_balance: string + requires_channel_creation: boolean + pending_transition?: string + pending_amount?: string + on_chain_balance: string +} + type StoreLibraryItem = { id: string title: string @@ -64,13 +153,25 @@ type StoreBootstrap = { default_asset: string supported_assets: string[] available_balance: string + channel_readiness: StoreChannelReadiness catalog: StoreCatalogItem[] session: StoreSession library: StoreLibraryItem[] + pending_action?: StorePendingAction } type ContentResponse = StoreCatalogItem +type StoreUpdateResponse = { + status: string + intent: string + asset: string + app_session_id: string + app_signature?: Hex + pending_action?: StorePendingAction + bootstrap?: StoreBootstrap +} + type APIError = { error?: { code: string @@ -78,6 +179,10 @@ type APIError = { } } +function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} + function getMetaMaskProvider(): InjectedProvider | null { const ethereum = (window as Window & { ethereum?: InjectedProvider & { providers?: InjectedProvider[] } }).ethereum if (!ethereum) return null @@ -88,9 +193,43 @@ function getMetaMaskProvider(): InjectedProvider | null { return ethereum.isMetaMask ? ethereum : null } +function loadStoredAsset(): string { + try { + const stored = window.localStorage.getItem(STORED_ASSET_KEY) + return stored && DEMO_ASSETS.includes(stored) ? stored : DEFAULT_ASSET + } catch { + return DEFAULT_ASSET + } +} + +function persistAsset(asset: string) { + try { + window.localStorage.setItem(STORED_ASSET_KEY, asset) + } catch { + // Local storage is best-effort; wallet recovery still works without it. + } +} + +async function createWalletConnections(provider: InjectedProvider, wallet: string) { + const client = createWalletClient({ + account: wallet as Address, + chain: sepolia, + transport: custom(provider), + }) + + const walletSigner = new BrowserWalletSigner(client, wallet as Address) + const nitrolite = await Client.create( + DEFAULT_WS_URL, + new ChannelDefaultSigner(walletSigner), + walletSigner, + withBlockchainRPC(11155111n, DEFAULT_BLOCKCHAIN_RPCS[11155111]), + ) + + return { client, nitrolite } +} + async function readJSON(input: RequestInfo | URL, init?: RequestInit): Promise { const response = await fetch(input, { - credentials: 'include', headers: { 'Content-Type': 'application/json', ...(init?.headers || {}), @@ -116,19 +255,42 @@ function formatAmount(value: string): string { return new Decimal(value || '0').toFixed() } +function parseDecimal(value: string): Decimal | null { + try { + const amount = new Decimal(value) + return amount.isFinite() ? amount : null + } catch { + return null + } +} + +function isPositiveAmount(value: string): boolean { + return parseDecimal(value)?.greaterThan(0) ?? false +} + +function minDecimal(a: Decimal, b: Decimal): Decimal { + return a.lessThan(b) ? a : b +} + +function isAllowanceError(error: unknown): boolean { + const message = error instanceof Error ? error.message : String(error) + const normalized = message.toLowerCase() + return normalized.includes('allowance') && normalized.includes('sufficient') +} + function parseSessionDataLabel(sessionData?: string): string { if (!sessionData) return 'No store activity yet.' try { - const parsed = JSON.parse(sessionData) as { action?: string; item_id?: string; amount?: string; price?: string } - switch (parsed.action) { - case 'bootstrap': + const parsed = JSON.parse(sessionData) as { intent?: string; item_id?: string | number; amount?: string; item_price?: string } + switch (parsed.intent) { + case 'init': return 'Store session ready.' - case 'deposit': - return `Last action: added ${parsed.amount}` + case 'user_deposit': + return 'Last action: deposit signed.' case 'purchase': - return `Last action: purchased ${parsed.item_id} for ${parsed.price}` + return `Last action: purchased ${parsed.item_id} for ${parsed.item_price}` case 'user_withdraw': - return `Last action: withdrew ${parsed.amount}` + return 'Last action: withdrew from store.' default: return 'Store session active.' } @@ -137,49 +299,184 @@ function parseSessionDataLabel(sessionData?: string): string { } } -function toRPCState(state: ChannelState) { +function channelReadinessLabel(status?: ChannelReadinessStatus) { + switch (status) { + case 'ready': + return 'ready' + case 'ack_required': + return 'ack required' + case 'deposit_required': + return 'deposit required' + case 'funds_required': + return 'funds needed' + case 'unavailable': + return 'sync unavailable' + default: + return 'offline' + } +} + +function channelReadinessMessage(readiness: StoreChannelReadiness | undefined, asset: string) { + switch (readiness?.status) { + case 'ready': + return `Home channel is ready with ${formatAmount(readiness.available_balance)} ${asset.toUpperCase()}.` + case 'ack_required': + if (readiness.requires_channel_creation) { + return `${formatAmount(readiness.pending_balance)} ${asset.toUpperCase()} was received off-chain. Sign once to open a home channel and make it available.` + } + return `Acknowledge ${formatAmount(readiness.pending_balance)} ${asset.toUpperCase()} in your pending channel state.` + case 'deposit_required': + return `Prepare a home channel with up to ${formatAmount(readiness.bootstrap_amount)} ${asset.toUpperCase()} from your wallet.` + case 'funds_required': + return `Add ${asset.toUpperCase()} test funds to this wallet before preparing a home channel.` + case 'unavailable': + return readiness.message || 'Channel readiness could not be checked.' + default: + return 'Connect wallet to check channel readiness.' + } +} + +function sessionStatusLabel(status?: string) { + switch (status) { + case 'open': + return 'ready' + case 'missing': + return 'setup required' + case 'sync_failed': + return 'sync pending' + case 'closed': + return 'closed' + default: + return status ?? 'offline' + } +} + +function toRPCDefinition(definition: AppDefinitionV1) { return { - id: state.id, - transition: { - type: state.transition.type, - tx_id: state.transition.txId, - account_id: state.transition.accountId ?? '', - amount: state.transition.amount.toString(), - }, - asset: state.asset, - user_wallet: state.userWallet, - epoch: state.epoch.toString(), - version: state.version.toString(), - home_channel_id: state.homeChannelId ?? undefined, - escrow_channel_id: state.escrowChannelId ?? undefined, - home_ledger: { - token_address: state.homeLedger.tokenAddress, - blockchain_id: state.homeLedger.blockchainId.toString(), - user_balance: state.homeLedger.userBalance.toString(), - user_net_flow: state.homeLedger.userNetFlow.toString(), - node_balance: state.homeLedger.nodeBalance.toString(), - node_net_flow: state.homeLedger.nodeNetFlow.toString(), - }, - escrow_ledger: state.escrowLedger - ? { - token_address: state.escrowLedger.tokenAddress, - blockchain_id: state.escrowLedger.blockchainId.toString(), - user_balance: state.escrowLedger.userBalance.toString(), - user_net_flow: state.escrowLedger.userNetFlow.toString(), - node_balance: state.escrowLedger.nodeBalance.toString(), - node_net_flow: state.escrowLedger.nodeNetFlow.toString(), - } - : undefined, - user_sig: state.userSig, - node_sig: state.nodeSig, + application_id: definition.applicationId, + participants: definition.participants.map((participant) => ({ + wallet_address: participant.walletAddress, + signature_weight: participant.signatureWeight, + })), + quorum: definition.quorum, + nonce: definition.nonce.toString(), + } +} + +function toRPCAppStateUpdate(update: AppStateUpdateV1) { + return { + app_session_id: update.appSessionId, + intent: update.intent, + version: update.version.toString(), + allocations: update.allocations.map((allocation) => ({ + participant: allocation.participant, + asset: allocation.asset, + amount: allocation.amount.toString(), + })), + session_data: update.sessionData, } } +function fromRPCAppStateUpdate(update: RPCAppStateUpdate): AppStateUpdateV1 { + return { + appSessionId: update.app_session_id, + intent: Number(update.intent) as AppStateUpdateIntent, + version: BigInt(update.version), + allocations: update.allocations.map((allocation) => ({ + participant: allocation.participant as Address, + asset: allocation.asset, + amount: new Decimal(allocation.amount), + })), + sessionData: update.session_data, + } +} + +async function withTimeout(promise: Promise, timeoutMs: number, message: string): Promise { + let timeoutID: number | undefined + const timeout = new Promise((_, reject) => { + timeoutID = window.setTimeout(() => reject(new Error(message)), timeoutMs) + }) + try { + return await Promise.race([promise, timeout]) + } finally { + if (timeoutID !== undefined) window.clearTimeout(timeoutID) + } +} + +function MagicPanel({ children, className }: { children: ReactNode; className?: string }) { + return ( + + {children} + + ) +} + +function ActionButton({ children, className, variant = 'primary', icon, ...props }: Omit, 'children'> & { + children: ReactNode + variant?: 'primary' | 'secondary' | 'ghost' + icon?: ReactNode +}) { + return ( + + {icon} + {children} + + ) +} + +function NumberTicker({ value }: { value: string }) { + return ( + + + {formatAmount(value)} + + + ) +} + +function PanelHeader({ label, title, icon }: { label: string; title: string; icon: ReactNode }) { + return ( +
+
+

{label}

+

{title}

+
+
+ {icon} +
+
+ ) +} + export default function App() { const [walletAddress, setWalletAddress] = useState(null) const [walletClient, setWalletClient] = useState(null) - const [nitroliteClient, setNitroliteClient] = useState(null) - const [selectedAsset, setSelectedAsset] = useState(DEFAULT_ASSET) + const [nitroliteClient, setNitroliteClient] = useState(null) + const [selectedAsset, setSelectedAsset] = useState(loadStoredAsset) const [bootstrap, setBootstrap] = useState(null) const [depositAmount, setDepositAmount] = useState('1.00') const [withdrawAmount, setWithdrawAmount] = useState('0.50') @@ -187,12 +484,48 @@ export default function App() { const [busy, setBusy] = useState(null) const [error, setError] = useState(null) const [activity, setActivity] = useState([]) - const autoCreatingRef = useRef(false) const libraryIds = useMemo(() => new Set((bootstrap?.library ?? []).map((item) => item.id)), [bootstrap]) + const assetOptions = useMemo(() => { + const supported = new Set(bootstrap?.supported_assets ?? DEMO_ASSETS) + return DEMO_ASSETS.filter((asset) => supported.has(asset)) + }, [bootstrap]) + const sessionReady = Boolean(bootstrap?.session.app_session_id && bootstrap.session.status === 'open') + const sessionNeedsStart = bootstrap?.session.status === 'missing' || bootstrap?.session.status === 'sync_failed' + const pendingDeposit = bootstrap?.pending_action?.type === 'user_deposit' ? bootstrap.pending_action : null + const channelReadiness = bootstrap?.channel_readiness + const channelReady = channelReadiness?.status === 'ready' + const canRunChannelSetup = channelReadiness?.status === 'ack_required' || channelReadiness?.status === 'deposit_required' + const availableBalance = useMemo(() => parseDecimal(bootstrap?.available_balance ?? '0') ?? new Decimal(0), [bootstrap?.available_balance]) + const pendingChannelBalance = useMemo( + () => parseDecimal(channelReadiness?.pending_balance ?? bootstrap?.available_balance ?? '0') ?? new Decimal(0), + [bootstrap?.available_balance, channelReadiness?.pending_balance], + ) + const pendingChannelDelta = useMemo(() => { + const delta = pendingChannelBalance.minus(availableBalance) + return delta.greaterThan(0) ? delta : new Decimal(0) + }, [availableBalance, pendingChannelBalance]) + const pendingChannelAmount = useMemo( + () => parseDecimal(channelReadiness?.pending_amount ?? pendingChannelDelta.toFixed()) ?? pendingChannelDelta, + [channelReadiness?.pending_amount, pendingChannelDelta], + ) + const hasPendingChannelBalance = Boolean(channelReadiness?.status === 'ack_required' && pendingChannelBalance.greaterThan(availableBalance)) + const requiresChannelCreation = Boolean(channelReadiness?.requires_channel_creation) + const hasWithdrawnChannelBalance = Boolean( + channelReadiness?.status === 'ack_required' && channelReadiness.pending_transition === 'release' && pendingChannelAmount.greaterThan(0), + ) + const depositValue = useMemo(() => parseDecimal(depositAmount), [depositAmount]) + const pendingDepositValue = useMemo(() => (pendingDeposit ? parseDecimal(pendingDeposit.amount) : null), [pendingDeposit]) + const depositExceedsAvailable = Boolean(bootstrap && depositValue?.greaterThan(0) && depositValue.greaterThan(availableBalance)) + const pendingDepositExceedsAvailable = Boolean(bootstrap && pendingDepositValue?.greaterThan(0) && pendingDepositValue.greaterThan(availableBalance)) + const canPrepareChannel = Boolean(walletAddress && nitroliteClient && bootstrap && busy === null && canRunChannelSetup) + const canDeposit = Boolean(walletAddress && sessionReady && channelReady && busy === null && isPositiveAmount(depositAmount) && !depositExceedsAvailable) + const canWithdraw = Boolean(walletAddress && sessionReady && channelReady && busy === null && isPositiveAmount(withdrawAmount)) + const canResumeDeposit = Boolean(walletAddress && nitroliteClient && pendingDeposit && busy === null && !pendingDepositExceedsAvailable) + const canCreateSession = Boolean(sessionNeedsStart && walletAddress && walletClient && busy === null && channelReady) function appendLog(line: string) { - const stamped = `${new Date().toISOString()} ${line}` + const stamped = `${new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })} ${line}` setActivity((current) => [stamped, ...current].slice(0, 40)) } @@ -210,25 +543,89 @@ export default function App() { } } - async function refreshBootstrap(asset: string, clientOverride?: NitroliteClient | null, walletOverride?: string | null, walletClientOverride?: WalletClient | null) { - const client = clientOverride ?? nitroliteClient - const wallet = walletOverride ?? walletAddress - const clientSigner = walletClientOverride ?? walletClient - const next = await readJSON(`/api/store/bootstrap?asset=${encodeURIComponent(asset)}`) - setBootstrap(next) - setSelectedAsset(next.selected_asset) - appendLog(`bootstrap ${asset} -> ${next.session.status}`) + async function hydrateWallet(provider: InjectedProvider, wallet: string, asset: string, label: string) { + await ensureSepolia(provider) + const { client, nitrolite } = await createWalletConnections(provider, wallet) + setWalletAddress(wallet) + setWalletClient(client) + setNitroliteClient(nitrolite) + appendLog(`${label} ${shortAddress(wallet)}`) + await refreshBootstrap(asset, wallet) + } - if (next.session.status === 'missing' && client && wallet && clientSigner && !autoCreatingRef.current) { - autoCreatingRef.current = true + useEffect(() => { + const provider = getMetaMaskProvider() + if (!provider) return + + let cancelled = false + const restore = async (wallet: string) => { + setBusy('restore') + setError(null) try { - const created = await createSession(next, clientSigner, wallet) - setBootstrap(created) - appendLog(`session created ${created.session.app_session_id}`) + await hydrateWallet(provider, wallet, loadStoredAsset(), 'wallet restored') + } catch (restoreError) { + if (!cancelled) { + setError(restoreError instanceof Error ? restoreError.message : 'Failed to restore wallet') + } } finally { - autoCreatingRef.current = false + if (!cancelled) setBusy(null) + } + } + + void provider + .request({ method: 'eth_accounts' }) + .then((accounts) => { + if (cancelled || !Array.isArray(accounts) || typeof accounts[0] !== 'string') return + return restore(accounts[0]) + }) + .catch(() => undefined) + + const onAccountsChanged = (value?: unknown) => { + const wallet = Array.isArray(value) && typeof value[0] === 'string' ? value[0] : null + if (!wallet) { + setWalletAddress(null) + setWalletClient(null) + setNitroliteClient(null) + setBootstrap(null) + setReaderItem(null) + appendLog('wallet disconnected') + return } + void restore(wallet) + } + const onChainChanged = () => { + void provider + .request({ method: 'eth_accounts' }) + .then((accounts) => { + if (!Array.isArray(accounts) || typeof accounts[0] !== 'string') return + return restore(accounts[0]) + }) + .catch(() => undefined) + } + + provider.on?.('accountsChanged', onAccountsChanged) + provider.on?.('chainChanged', onChainChanged) + return () => { + cancelled = true + provider.removeListener?.('accountsChanged', onAccountsChanged) + provider.removeListener?.('chainChanged', onChainChanged) } + // Run once so refreshes do not repeatedly recreate the SDK client. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + async function refreshBootstrap(asset: string, walletOverride?: string | null) { + const wallet = walletOverride ?? walletAddress + if (!wallet) { + throw new Error('Connect a wallet before bootstrapping the store.') + } + const next = await readJSON( + `/api/store/bootstrap?asset=${encodeURIComponent(asset)}&wallet_address=${encodeURIComponent(wallet)}`, + ) + setBootstrap(next) + setSelectedAsset(next.selected_asset) + persistAsset(next.selected_asset) + appendLog(`bootstrap ${asset.toUpperCase()} -> ${sessionStatusLabel(next.session.status)}`) } async function connectWallet() { @@ -248,42 +645,7 @@ export default function App() { throw new Error('MetaMask did not return an account.') } - const client = createWalletClient({ - account: wallet as Address, - chain: sepolia, - transport: custom(provider), - }) - - const challenge = await readJSON<{ challenge_id: string; message: string }>('/api/store/connect/challenge', { - method: 'POST', - body: JSON.stringify({ wallet_address: wallet }), - }) - const rawSignature = await client.signMessage({ - account: wallet as Address, - message: challenge.message, - }) - - await readJSON('/api/store/connect/verify', { - method: 'POST', - body: JSON.stringify({ - challenge_id: challenge.challenge_id, - wallet_address: wallet, - signature: rawSignature, - }), - }) - - const nitrolite = await NitroliteClient.create({ - wsURL: DEFAULT_WS_URL, - walletClient: client, - chainId: 11155111, - blockchainRPCs: DEFAULT_BLOCKCHAIN_RPCS, - }) - - setWalletAddress(wallet) - setWalletClient(client) - setNitroliteClient(nitrolite) - appendLog(`wallet connected ${wallet}`) - await refreshBootstrap(selectedAsset, nitrolite, wallet, client) + await hydrateWallet(provider, wallet, selectedAsset, 'wallet connected') } catch (connectError) { setError(connectError instanceof Error ? connectError.message : 'Failed to connect wallet') } finally { @@ -292,50 +654,122 @@ export default function App() { } async function createSession(nextBootstrap: StoreBootstrap, client: WalletClient, wallet: string) { - const nonce = Date.now() - const sessionData = JSON.stringify({ action: 'bootstrap', asset: nextBootstrap.selected_asset }) - const definition = { - application_id: nextBootstrap.app_id, + const signer = new AppSessionWalletSignerV1(new BrowserWalletSigner(client, wallet as Address)) + const sessionData = JSON.stringify({ intent: 'init' }) + const definition: AppDefinitionV1 = { + applicationId: nextBootstrap.app_id, participants: [ - { wallet_address: wallet, signature_weight: 1 }, - { wallet_address: nextBootstrap.app_signer, signature_weight: 1 }, + { walletAddress: wallet as Address, signatureWeight: 1 }, + { walletAddress: nextBootstrap.app_signer as Address, signatureWeight: 1 }, ], quorum: 2, - nonce: String(nonce), + nonce: BigInt(Date.now() * 1000000), } - const payloadHash = packCreateAppSessionHash({ - application: nextBootstrap.app_id, - participants: definition.participants.map((participant) => ({ - walletAddress: participant.wallet_address as Address, - signatureWeight: participant.signature_weight, - })), - quorum: definition.quorum, - nonce, - sessionData, - }) - - const rawSignature = await client.signMessage({ - account: wallet as Address, - message: { raw: payloadHash }, - }) - const userSignature = toWalletQuorumSignature(rawSignature as Hex) + const payload = packCreateAppSessionRequestV1(definition, sessionData) + const userSignature = await signer.signMessage(payload) - return readJSON('/api/store/update', { + return readJSON('/api/store/init', { method: 'POST', body: JSON.stringify({ + wallet_address: wallet, asset: nextBootstrap.selected_asset, - kind: 'create_session', - definition, + definition: toRPCDefinition(definition), session_data: sessionData, user_signature: userSignature, }), }) } + async function startSession() { + if (!bootstrap || !walletClient || !walletAddress) return + if (!sessionNeedsStart) return + + setBusy('create-session') + setError(null) + try { + const created = await createSession(bootstrap, walletClient, walletAddress) + setBootstrap(created) + appendLog(`session created ${shortAddress(created.session.app_session_id ?? '')}`) + } catch (createError) { + setError(createError instanceof Error ? createError.message : 'Failed to create store session') + } finally { + setBusy(null) + } + } + + async function checkpointWithApproval(asset: string): Promise { + if (!nitroliteClient || !walletAddress || !bootstrap) throw new Error('Connect a wallet before preparing a channel.') + try { + return await nitroliteClient.checkpoint(asset) + } catch (checkpointError) { + if (!isAllowanceError(checkpointError)) { + const message = checkpointError instanceof Error ? checkpointError.message : String(checkpointError) + if (message.toLowerCase().includes('does not require a blockchain operation')) return null + throw checkpointError + } + const signedState = await nitroliteClient.getLatestState(walletAddress as Address, asset, true) + const chainID = signedState.homeLedger.blockchainId || BigInt(bootstrap.channel_readiness.home_blockchain_id) + appendLog(`approve ${asset.toUpperCase()} channel spend`) + await nitroliteClient.approveToken(chainID, asset, MAX_APPROVE_AMOUNT) + return await nitroliteClient.checkpoint(asset) + } + } + + async function prepareChannel() { + if (!bootstrap || !walletAddress || !nitroliteClient) return + const readiness = bootstrap.channel_readiness + const asset = bootstrap.selected_asset + if (readiness.status !== 'ack_required' && readiness.status !== 'deposit_required') return + + setBusy('prepare-channel') + setError(null) + try { + if (readiness.status === 'ack_required') { + appendLog(`acknowledge ${asset.toUpperCase()} channel state`) + try { + await nitroliteClient.acknowledge(asset) + } catch (ackError) { + const message = ackError instanceof Error ? ackError.message : String(ackError) + if (!message.toLowerCase().includes('already acknowledged')) throw ackError + } + } else { + const chainID = BigInt(readiness.home_blockchain_id) + const configuredAmount = parseDecimal(readiness.bootstrap_amount) ?? new Decimal(10) + const onChainBalance = await nitroliteClient.getOnChainBalance(chainID, asset, walletAddress as Address) + const amount = minDecimal(configuredAmount, onChainBalance) + if (!amount.greaterThan(0)) { + throw new Error(`Add ${asset.toUpperCase()} test funds to this wallet before preparing a home channel.`) + } + appendLog(`prepare ${asset.toUpperCase()} channel ${amount.toFixed()}`) + try { + await nitroliteClient.deposit(chainID, asset, amount) + } catch (depositError) { + if (!isAllowanceError(depositError)) throw depositError + appendLog(`approve ${asset.toUpperCase()} channel spend`) + await nitroliteClient.approveToken(chainID, asset, MAX_APPROVE_AMOUNT) + await nitroliteClient.deposit(chainID, asset, amount) + } + } + + const txHash = await checkpointWithApproval(asset) + appendLog(txHash ? `channel checkpoint ${shortAddress(txHash)}` : `channel state synced`) + await refreshBootstrap(asset) + } catch (setupError) { + setError(setupError instanceof Error ? setupError.message : 'Failed to prepare channel') + try { + await refreshBootstrap(asset) + } catch { + // Keep the setup error visible. + } + } finally { + setBusy(null) + } + } + async function submitPurchase(item: StoreCatalogItem) { if (!bootstrap || !walletAddress || !walletClient) return - if (!bootstrap.session.app_session_id || bootstrap.session.status !== 'open') { + if (!sessionReady) { setError('Store session is not ready yet.') return } @@ -354,45 +788,34 @@ export default function App() { } const sessionData = JSON.stringify({ - action: 'purchase', - item_id: item.id, - price: price.toFixed(), + intent: 'purchase', + item_id: Number.isFinite(Number(item.id)) ? Number(item.id) : item.id, + item_price: price.toFixed(), }) - const appStateUpdate = { - app_session_id: bootstrap.session.app_session_id, - intent: APP_STATE_INTENT.Operate, - version: String(version), + const appStateUpdate: AppStateUpdateV1 = { + appSessionId: bootstrap.session.app_session_id!, + intent: AppStateUpdateIntent.Operate, + version: BigInt(version), allocations: [ - { participant: walletAddress as Address, asset: bootstrap.selected_asset, amount: nextUser.toFixed() }, - { participant: bootstrap.app_signer as Address, asset: bootstrap.selected_asset, amount: nextApp.toFixed() }, + { participant: walletAddress as Address, asset: bootstrap.selected_asset, amount: nextUser }, + { participant: bootstrap.app_signer as Address, asset: bootstrap.selected_asset, amount: nextApp }, ], - session_data: sessionData, - } - - const payloadHash = packSubmitAppStateHash({ - appSessionId: appStateUpdate.app_session_id as Hex, - intent: appStateUpdate.intent, - version, - allocations: appStateUpdate.allocations, sessionData, - }) + } - const rawSignature = await walletClient.signMessage({ - account: walletAddress as Address, - message: { raw: payloadHash }, - }) - const userSignature = toWalletQuorumSignature(rawSignature) + const payload = packAppStateUpdateV1(appStateUpdate) + const userSignature = await new AppSessionWalletSignerV1(new BrowserWalletSigner(walletClient, walletAddress as Address)).signMessage(payload) - const next = await readJSON('/api/store/update', { + const result = await readJSON('/api/store/update', { method: 'POST', body: JSON.stringify({ asset: bootstrap.selected_asset, - kind: 'submit_app_state', - app_state_update: appStateUpdate, + app_state_update: toRPCAppStateUpdate(appStateUpdate), user_signature: userSignature, }), }) - setBootstrap(next) + if (!result.bootstrap) throw new Error('Purchase succeeded but bootstrap was not returned.') + setBootstrap(result.bootstrap) appendLog(`purchase ${item.id}`) } catch (purchaseError) { setError(purchaseError instanceof Error ? purchaseError.message : 'Failed to buy item') @@ -403,7 +826,7 @@ export default function App() { async function submitWithdraw() { if (!bootstrap || !walletAddress || !walletClient) return - if (!bootstrap.session.app_session_id || bootstrap.session.status !== 'open') { + if (!sessionReady) { setError('Store session is not ready yet.') return } @@ -412,6 +835,9 @@ export default function App() { setError(null) try { const amount = new Decimal(withdrawAmount) + if (!amount.greaterThan(0)) { + throw new Error('Withdraw amount must be greater than zero.') + } const version = bootstrap.session.version + 1 const currentUser = new Decimal(bootstrap.session.user_allocation) const currentApp = new Decimal(bootstrap.session.app_allocation) @@ -420,46 +846,92 @@ export default function App() { throw new Error('Withdraw amount exceeds your store balance.') } - const sessionData = JSON.stringify({ - action: 'user_withdraw', - amount: amount.toFixed(), - }) - const appStateUpdate = { - app_session_id: bootstrap.session.app_session_id, - intent: APP_STATE_INTENT.Withdraw, - version: String(version), + const sessionData = JSON.stringify({ intent: 'user_withdraw' }) + const appStateUpdate: AppStateUpdateV1 = { + appSessionId: bootstrap.session.app_session_id!, + intent: AppStateUpdateIntent.Withdraw, + version: BigInt(version), allocations: [ - { participant: walletAddress as Address, asset: bootstrap.selected_asset, amount: nextUser.toFixed() }, - { participant: bootstrap.app_signer as Address, asset: bootstrap.selected_asset, amount: currentApp.toFixed() }, + { participant: walletAddress as Address, asset: bootstrap.selected_asset, amount: nextUser }, + { participant: bootstrap.app_signer as Address, asset: bootstrap.selected_asset, amount: currentApp }, ], - session_data: sessionData, + sessionData, } - const payloadHash = packSubmitAppStateHash({ - appSessionId: appStateUpdate.app_session_id as Hex, - intent: appStateUpdate.intent, - version, - allocations: appStateUpdate.allocations, - sessionData, - }) - const rawSignature = await walletClient.signMessage({ - account: walletAddress as Address, - message: { raw: payloadHash }, - }) + const payload = packAppStateUpdateV1(appStateUpdate) + const userSignature = await new AppSessionWalletSignerV1(new BrowserWalletSigner(walletClient, walletAddress as Address)).signMessage(payload) - const next = await readJSON('/api/store/update', { + const result = await readJSON('/api/store/update', { method: 'POST', body: JSON.stringify({ asset: bootstrap.selected_asset, - kind: 'submit_app_state', - app_state_update: appStateUpdate, - user_signature: toWalletQuorumSignature(rawSignature), + app_state_update: toRPCAppStateUpdate(appStateUpdate), + user_signature: userSignature, }), }) - setBootstrap(next) + if (!result.bootstrap) throw new Error('Withdraw succeeded but bootstrap was not returned.') + setBootstrap(result.bootstrap) appendLog(`withdraw ${amount.toFixed()}`) } catch (withdrawError) { - setError(withdrawError instanceof Error ? withdrawError.message : 'Failed to withdraw') + const message = withdrawError instanceof Error ? withdrawError.message : 'Failed to withdraw' + setError( + message.startsWith('failed to submit app state: ') + ? `Nitronode rejected the withdraw state: ${message.slice('failed to submit app state: '.length)}` + : message, + ) + try { + await refreshBootstrap(bootstrap.selected_asset) + } catch { + // Keep the withdraw error visible. + } + } finally { + setBusy(null) + } + } + + async function finishDeposit(appStateUpdate: AppStateUpdateV1, userSignature: Hex, appSignature: Hex, asset: string, amount: Decimal) { + if (!nitroliteClient) throw new Error('Connect a wallet before submitting the deposit.') + appendLog(`deposit signed ${amount.toFixed()} ${asset.toUpperCase()}; submitting`) + await assertHomeChannelCanDeposit(asset, amount) + await withTimeout( + nitroliteClient.submitAppSessionDeposit(appStateUpdate, [userSignature, appSignature], asset, amount), + DEPOSIT_SUBMIT_TIMEOUT_MS, + 'Deposit is signed, but the Nitronode submit did not finish yet. Use Resume deposit after refresh.', + ) + await refreshBootstrap(asset) + appendLog(`deposit ${amount.toFixed()} ${asset.toUpperCase()} submitted`) + } + + async function assertHomeChannelCanDeposit(asset: string, amount: Decimal) { + if (!nitroliteClient || !walletAddress) throw new Error('Connect a wallet before submitting the deposit.') + let state + try { + state = await nitroliteClient.getLatestState(walletAddress as Address, asset, true) + } catch { + throw new Error(`Open and fund a ${asset.toUpperCase()} home channel before using this store.`) + } + const channelBalance = new Decimal(state.homeLedger.userBalance) + if (channelBalance.lessThan(amount)) { + throw new Error(`Deposit amount exceeds your available ${asset.toUpperCase()} channel funds.`) + } + } + + async function resumeDeposit() { + if (!pendingDeposit) return + + setBusy('resume-deposit') + setError(null) + try { + const amount = new Decimal(pendingDeposit.amount) + const appStateUpdate = fromRPCAppStateUpdate(pendingDeposit.app_state_update) + await finishDeposit(appStateUpdate, pendingDeposit.user_signature, pendingDeposit.app_signature, pendingDeposit.asset, amount) + } catch (resumeError) { + setError(resumeError instanceof Error ? resumeError.message : 'Failed to resume deposit') + try { + await refreshBootstrap(pendingDeposit.asset) + } catch { + // The original recovery error is more useful to the user. + } } finally { setBusy(null) } @@ -467,7 +939,7 @@ export default function App() { async function submitDeposit() { if (!bootstrap || !walletAddress || !walletClient || !nitroliteClient) return - if (!bootstrap.session.app_session_id || bootstrap.session.status !== 'open') { + if (!sessionReady) { setError('Store session is not ready yet.') return } @@ -476,69 +948,73 @@ export default function App() { setError(null) try { const amount = new Decimal(depositAmount) + if (!amount.greaterThan(0)) { + throw new Error('Deposit amount must be greater than zero.') + } + const available = new Decimal(bootstrap.available_balance || '0') + if (amount.greaterThan(available)) { + if (!available.greaterThan(0)) { + throw new Error(`Open and fund a ${bootstrap.selected_asset.toUpperCase()} home channel before depositing.`) + } + throw new Error(`Deposit amount exceeds your available ${bootstrap.selected_asset.toUpperCase()} channel funds.`) + } const version = bootstrap.session.version + 1 const currentUser = new Decimal(bootstrap.session.user_allocation) const currentApp = new Decimal(bootstrap.session.app_allocation) const nextUser = currentUser.plus(amount) - const sessionData = JSON.stringify({ - action: 'deposit', - amount: amount.toFixed(), - }) - const appStateUpdate = { - app_session_id: bootstrap.session.app_session_id, - intent: APP_STATE_INTENT.Deposit, - version: String(version), + const sessionData = JSON.stringify({ intent: 'user_deposit', amount: amount.toFixed() }) + const appStateUpdate: AppStateUpdateV1 = { + appSessionId: bootstrap.session.app_session_id!, + intent: AppStateUpdateIntent.Deposit, + version: BigInt(version), allocations: [ - { participant: walletAddress as Address, asset: bootstrap.selected_asset, amount: nextUser.toFixed() }, - { participant: bootstrap.app_signer as Address, asset: bootstrap.selected_asset, amount: currentApp.toFixed() }, + { participant: walletAddress as Address, asset: bootstrap.selected_asset, amount: nextUser }, + { participant: bootstrap.app_signer as Address, asset: bootstrap.selected_asset, amount: currentApp }, ], - session_data: sessionData, - } - - const payloadHash = packSubmitAppStateHash({ - appSessionId: appStateUpdate.app_session_id as Hex, - intent: appStateUpdate.intent, - version, - allocations: appStateUpdate.allocations, sessionData, - }) - const rawSignature = await walletClient.signMessage({ - account: walletAddress as Address, - message: { raw: payloadHash }, - }) - const userSignature = toWalletQuorumSignature(rawSignature) + } - const currentState = await nitroliteClient.innerClient.getLatestState(walletAddress as Address, bootstrap.selected_asset, false) - const proposedState = nextState(currentState) - applyCommitTransition(proposedState, bootstrap.session.app_session_id, amount) - proposedState.userSig = await nitroliteClient.innerClient.signState(proposedState) + const payload = packAppStateUpdateV1(appStateUpdate) + const userSignature = await new AppSessionWalletSignerV1(new BrowserWalletSigner(walletClient, walletAddress as Address)).signMessage(payload) - const next = await readJSON('/api/store/update', { + const result = await readJSON('/api/store/update', { method: 'POST', body: JSON.stringify({ asset: bootstrap.selected_asset, - kind: 'submit_deposit_state', - app_state_update: appStateUpdate, + app_state_update: toRPCAppStateUpdate(appStateUpdate), user_signature: userSignature, - user_state: toRPCState(proposedState), }), }) - setBootstrap(next) - appendLog(`deposit ${amount.toFixed()}`) + if (!result.app_signature) throw new Error('Backend did not return an app signature for deposit.') + await finishDeposit(appStateUpdate, userSignature, result.app_signature, bootstrap.selected_asset, amount) } catch (depositError) { setError(depositError instanceof Error ? depositError.message : 'Failed to add funds') + try { + await refreshBootstrap(bootstrap.selected_asset) + } catch { + // Preserve the deposit error while leaving any checkpoint visible if bootstrap succeeds. + } } finally { setBusy(null) } } async function openContent(itemID: string) { - if (!bootstrap) return + if (!bootstrap || !walletAddress) return + if (!bootstrap.session.app_session_id) { + setError('Store session is not ready yet.') + return + } + setBusy(`content:${itemID}`) setError(null) try { - const item = await readJSON(`/api/store/content/${encodeURIComponent(itemID)}?asset=${encodeURIComponent(bootstrap.selected_asset)}`) + const params = new URLSearchParams({ + wallet_address: walletAddress, + asset: bootstrap.selected_asset, + }) + const item = await readJSON(`/api/store/content/${encodeURIComponent(itemID)}?${params.toString()}`) setReaderItem(item) appendLog(`open content ${itemID}`) } catch (contentError) { @@ -557,183 +1033,445 @@ export default function App() { } } - useEffect(() => { - if (!bootstrap || !walletAddress || !nitroliteClient) return - if (bootstrap.selected_asset === selectedAsset) return - void refreshBootstrap(selectedAsset) - }, [selectedAsset, bootstrap, walletAddress, nitroliteClient]) + function switchAsset(asset: string) { + setReaderItem(null) + persistAsset(asset) + if (walletAddress) { + setBusy(`asset:${asset}`) + setError(null) + void refreshBootstrap(asset) + .catch((refreshError) => { + setError(refreshError instanceof Error ? refreshError.message : 'Failed to refresh store') + }) + .finally(() => { + setBusy(null) + }) + } else { + setSelectedAsset(asset) + } + } - return ( -
-
-
-

Content store

-

Simple content store

-

- Connect MetaMask, add funds, buy content instantly, read what you own, and withdraw what remains. + function channelSetupActionLabel() { + if (busy === 'prepare-channel') return 'Preparing' + switch (channelReadiness?.status) { + case 'ack_required': + return 'Make available' + case 'deposit_required': + return 'Prepare channel' + case 'funds_required': + return 'Funds needed' + case 'unavailable': + return 'Reconnect' + default: + return 'Prepare channel' + } + } + + function renderChannelSetupPanel() { + if (!bootstrap || channelReady) return null + const title = hasWithdrawnChannelBalance + ? 'Make withdrawn balance available' + : requiresChannelCreation + ? 'Make received funds available' + : channelReadiness?.status === 'ack_required' + ? 'Make pending balance available' + : channelReadinessLabel(channelReadiness?.status) + const message = hasWithdrawnChannelBalance + ? `${formatAmount(pendingChannelAmount.toFixed())} ${selectedAsset.toUpperCase()} from your store withdrawal is pending. Sign once to add it back to your available channel balance.` + : requiresChannelCreation + ? `${formatAmount(pendingChannelBalance.toFixed())} ${selectedAsset.toUpperCase()} was received off-chain. Sign once, then checkpoint to open your home channel and make it available.` + : channelReadiness?.status === 'ack_required' + ? `${formatAmount(pendingChannelBalance.toFixed())} ${selectedAsset.toUpperCase()} is pending in your channel. Sign once to make it available.` + : channelReadinessMessage(channelReadiness, selectedAsset) + + return ( +

+
+

+ + {title}

+

+ {message} +

+ {hasPendingChannelBalance ? ( +
+ + Available now: {formatAmount(availableBalance.toFixed())} {selectedAsset.toUpperCase()} + + + After signing: {formatAmount(pendingChannelBalance.toFixed())} {selectedAsset.toUpperCase()} + +
+ ) : null}
-
- -
- Wallet - {shortAddress(walletAddress)} + : } + > + {channelSetupActionLabel()} + +
+ ) + } + + return ( +
+ +
+

Content store

+

Nitrolite App Session Store

+

+ YUSD-first content purchases with Yellow as a second testnet asset lane. +

+
+ + + Sepolia + + + + {sessionStatusLabel(bootstrap?.session.status)} +
-
- {error ?
{error}
: null} - -
-
-
-
- Store -

{bootstrap?.store_name ?? 'Store'}

-
- +
+ : } + > + {busy === 'restore' ? 'Restoring' : busy === 'connect' ? 'Connecting' : walletAddress ? 'Reconnect' : 'Connect'} + +
+

Wallet

+

{shortAddress(walletAddress)}

+
+
+ + + + {error ? ( + + {error} + + ) : null} + + +
+ + } /> + +
+ {assetOptions.map((asset) => ( + + ))}
-
-
- Available balance - {bootstrap ? formatAmount(bootstrap.available_balance) : '0'} +
+
+

Available

+ +

{selectedAsset}

+ {hasPendingChannelBalance ? ( +

+ Pending: {formatAmount(pendingChannelBalance.toFixed())} {selectedAsset.toUpperCase()} +

+ ) : null}
-
- Store balance - {bootstrap ? formatAmount(bootstrap.session.user_allocation) : '0'} +
+

Store balance

+ +

{selectedAsset}

-
- Store status - {bootstrap?.session.status ?? 'Connect first'} +
+

App signer

+ {shortAddress(bootstrap?.app_signer ?? null)} +

Quorum 2

-

{bootstrap ? parseSessionDataLabel(bootstrap.session.session_data) : 'Connect MetaMask to start shopping.'}

- -
- - - - -
-
+

+ {bootstrap ? parseSessionDataLabel(bootstrap.session.session_data) : 'Connect wallet to load the store.'} +

-
-
-
- Library -

What you own

+ {sessionNeedsStart && channelReady ? ( +
+

+ {bootstrap?.session.status === 'sync_failed' + ? 'The previous store session is not synced. Sign once to start a fresh store session.' + : 'Sign once to start a store session and unlock deposits.'} +

+ : } + > + {busy === 'create-session' ? 'Starting' : 'Sign to start'} +
-
+ ) : null} + + {sessionNeedsStart ? renderChannelSetupPanel() : null} + + {pendingDeposit ? ( +
+
+

+ + Deposit checkpoint ready +

+

+ {pendingDepositExceedsAvailable + ? `${formatAmount(pendingDeposit.amount)} ${pendingDeposit.asset.toUpperCase()} exceeds the current available balance. Enter a smaller deposit to replace it, or top up before resuming.` + : `${formatAmount(pendingDeposit.amount)} ${pendingDeposit.asset.toUpperCase()} is signed at version ${pendingDeposit.version}. Resume submits it to Nitronode without another MetaMask prompt.`} +

+
+ : } + > + {busy === 'resume-deposit' ? 'Resuming' : 'Resume'} + +
+ ) : null} + + {sessionReady && !channelReady ? renderChannelSetupPanel() : null} + + {sessionReady && channelReady ? ( +
+ + : } + > + {busy === 'deposit' ? 'Depositing' : 'Deposit'} + + + + : } + > + {busy === 'withdraw' ? 'Withdrawing' : 'Withdraw'} + +
+ ) : null} + + + + } /> {bootstrap?.library.length ? ( -
- {bootstrap.library.map((item) => ( -
-
- {item.title} -

{item.description}

- {item.type} · bought for {item.price} + + {bootstrap.library.map((item, index) => ( + +
+
+

{item.title}

+

{item.description}

+

+ {item.type} / {item.price} {selectedAsset.toUpperCase()} +

+
+ openContent(item.id)} + icon={busy === `content:${item.id}` ? : } + > + {busy === `content:${item.id}` ? 'Opening' : 'Read'} +
- -
+ ))} -
+ ) : ( -

Buy something from the catalog and it will appear here.

+
+ Your purchased items will appear here. +
)} -
-
- -
-
-
-
- Catalog -

Browse content

+ +
+ +
+ + } /> + + {bootstrap?.catalog.length ? ( +
+ {bootstrap.catalog.map((item, index) => { + const owned = libraryIds.has(item.id) + return ( + +
+
+
+ Item {item.id} + {item.prices[selectedAsset]} {selectedAsset.toUpperCase()} +
+

{item.title}

+

{item.description}

+

{item.type}

+
+ submitPurchase(item)} + icon={owned ? : busy === `purchase:${item.id}` ? : } + > + {owned ? 'Owned' : busy === `purchase:${item.id}` ? 'Purchasing' : 'Purchase'} + +
+
+ ) + })}
-
- -
- {(bootstrap?.catalog ?? []).map((item) => ( -
-
- {item.title} -

{item.description}

- {item.type} · {item.prices[selectedAsset]} -
- -
- ))} -
-
- -
-
-
- Reader -

Open content

+ ) : ( +
+ Catalog loads after wallet connection.
-
+ )} + + + + } /> {readerItem ? ( -
-

{readerItem.title}

-
{readerItem.content}
+
+

+ {readerItem.type} / {readerItem.prices[selectedAsset]} {selectedAsset.toUpperCase()} +

+
{readerItem.content}
) : ( -

Open an item from your library to read it here.

+
+ Select a library item to read. +
)} -
-
+ + -
-
+ +
- Browser activity -

Recent actions

+

Browser activity

+

Recent actions

- +
{activity.length ? ( -
    + {activity.map((entry) => ( -
  • {entry}
  • + + + {entry} + ))} -
+ ) : ( -

No activity yet.

+
+ No activity yet. +
)} -
+
) } diff --git a/frontend/src/index.css b/frontend/src/index.css index f46b9f8..69d29ad 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,10 +1,11 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + :root { - font-family: 'SF Pro Text', 'Inter', system-ui, sans-serif; - color: #1f1b17; - background: - radial-gradient(circle at top left, rgba(34, 113, 96, 0.16), transparent 30%), - radial-gradient(circle at top right, rgba(201, 150, 70, 0.14), transparent 28%), - linear-gradient(180deg, #fbf7ef 0%, #f3ecdf 100%); + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + color: #0d0d0d; + background: #fffef7; font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; @@ -19,12 +20,63 @@ html, body, #root { min-height: 100%; + max-width: 100%; } body { margin: 0; + overflow-x: hidden; + background: + radial-gradient(circle at 10% 0%, rgba(252, 208, 0, 0.18), transparent 26rem), + linear-gradient(rgba(13, 13, 13, 0.045) 1px, transparent 1px), + linear-gradient(90deg, rgba(13, 13, 13, 0.045) 1px, transparent 1px), + #fffef7; + background-size: auto, 32px 32px, 32px 32px, auto; +} + +button, +input { + font: inherit; +} + +button:focus-visible, +input:focus-visible { + outline: 3px solid rgba(252, 208, 0, 0.72); + outline-offset: 2px; } -a { - color: inherit; +@layer components { + .glass-panel { + @apply border border-black/10 bg-white/80 shadow-card backdrop-blur-xl; + } + + .metric-card { + @apply rounded-2xl border border-black/10 bg-white/80 p-4 shadow-sm; + } + + .label-text { + @apply text-[0.68rem] font-black uppercase tracking-[0.18em] text-black/50; + } + + .status-pill { + @apply inline-flex items-center gap-1.5 rounded-full border border-black/10 bg-white/90 px-3 py-1 text-xs font-black uppercase tracking-wide text-black; + } + + .shine-border { + position: relative; + overflow: hidden; + } + + .shine-border::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient(120deg, rgba(252, 208, 0, 0.86), rgba(255, 255, 255, 0), rgba(13, 13, 13, 0.28)); + -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + } } diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs new file mode 100644 index 0000000..0a4839f --- /dev/null +++ b/frontend/tailwind.config.cjs @@ -0,0 +1,26 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./index.html', './src/**/*.{ts,tsx}'], + theme: { + extend: { + colors: { + ink: '#0d0d0d', + paper: '#fffef7', + yellow: { + brand: '#fcd000', + surface: '#fff7c7', + line: '#d4b21d', + }, + }, + boxShadow: { + card: '0 18px 60px rgba(0, 0, 0, 0.10)', + glow: '0 0 0 1px rgba(252, 208, 0, 0.35), 0 18px 50px rgba(252, 208, 0, 0.16)', + }, + backgroundImage: { + 'hero-grid': + 'linear-gradient(rgba(13, 13, 13, 0.055) 1px, transparent 1px), linear-gradient(90deg, rgba(13, 13, 13, 0.055) 1px, transparent 1px)', + }, + }, + }, + plugins: [], +} diff --git a/frontend/vendor/yellow-org-sdk-1.2.2.tgz b/frontend/vendor/yellow-org-sdk-1.2.2.tgz new file mode 100644 index 0000000..dca9e77 Binary files /dev/null and b/frontend/vendor/yellow-org-sdk-1.2.2.tgz differ diff --git a/go.mod b/go.mod index 52dbc23..60edfb9 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,13 @@ -module github.com/layer-3/nitrolite-go-example +module github.com/layer-3/nitrolite-store-example go 1.25.0 -require github.com/layer-3/nitrolite v1.2.0 +require ( + github.com/ethereum/go-ethereum v1.17.1 + github.com/layer-3/nitrolite v1.2.0 + github.com/shopspring/decimal v1.4.0 + modernc.org/sqlite v1.48.2 +) require ( github.com/Microsoft/go-winio v0.6.2 // indirect @@ -15,7 +20,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect - github.com/ethereum/go-ethereum v1.17.1 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -29,7 +33,6 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shopspring/decimal v1.4.0 // indirect github.com/supranational/blst v0.3.16 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect @@ -46,5 +49,4 @@ require ( modernc.org/libc v1.70.0 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - modernc.org/sqlite v1.48.2 // indirect ) diff --git a/go.sum b/go.sum index 7fa5e2f..253bff3 100644 --- a/go.sum +++ b/go.sum @@ -82,6 +82,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -94,6 +96,8 @@ github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY4 github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= @@ -220,9 +224,10 @@ go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= @@ -230,14 +235,14 @@ golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -246,11 +251,31 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= +modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= +modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= +modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c= modernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/internal/config/config.go b/internal/config/config.go index 645e2a9..eee6745 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -10,19 +10,17 @@ import ( // Config contains runtime configuration for the example service. type Config struct { - Port string - LogLevel string - ClearnodeWSURL string - DemoPrivateKey string - ConsoleAPIKey string - SQLitePath string - StoreName string - StoreAppID string - StoreAppPrivateKey string - MerchantName string - MerchantAppID string - BlockchainRPCURLs map[string]string - HomeBlockchains map[string]uint64 + Port string + LogLevel string + ClearnodeWSURL string + DemoPrivateKey string + SQLitePath string + StoreName string + StoreAppID string + StoreAppPrivateKey string + BlockchainRPCURLs map[string]string + HomeBlockchains map[string]uint64 + StoreChannelBootstrapAmounts map[string]string } // Load reads process env and an optional .env file into a validated Config. @@ -36,13 +34,14 @@ func Load(dotenvPath string) (*Config, error) { LogLevel: getEnv("LOG_LEVEL", "info"), ClearnodeWSURL: os.Getenv("CLEARNODE_WS_URL"), DemoPrivateKey: os.Getenv("DEMO_PRIVATE_KEY"), - ConsoleAPIKey: os.Getenv("CONSOLE_API_KEY"), - SQLitePath: getEnv("SQLITE_PATH", "./data/nitrolite-go-example.db"), + SQLitePath: getEnv("SQLITE_PATH", "./data/nitrolite-store-example.db"), StoreName: getEnv("STORE_NAME", "Nitrolite App Session Store"), StoreAppID: getEnv("STORE_APP_ID", "default"), StoreAppPrivateKey: strings.TrimSpace(os.Getenv("STORE_APP_PRIVATE_KEY")), - MerchantName: getEnv("MERCHANT_NAME", "Nitrolite Sandbox Merchant"), - MerchantAppID: getEnv("MERCHANT_APP_ID", "default"), + StoreChannelBootstrapAmounts: map[string]string{ + "yusd": "10", + "yellow": "10", + }, } if err := parseJSONEnv("BLOCKCHAIN_RPC_URLS", &cfg.BlockchainRPCURLs); err != nil { @@ -51,6 +50,11 @@ func Load(dotenvPath string) (*Config, error) { if err := parseJSONEnv("HOME_BLOCKCHAINS", &cfg.HomeBlockchains); err != nil { return nil, err } + if raw := strings.TrimSpace(os.Getenv("STORE_CHANNEL_BOOTSTRAP_AMOUNTS")); raw != "" { + if err := json.Unmarshal([]byte(raw), &cfg.StoreChannelBootstrapAmounts); err != nil { + return nil, fmt.Errorf("invalid STORE_CHANNEL_BOOTSTRAP_AMOUNTS: %w", err) + } + } if err := cfg.Validate(); err != nil { return nil, err @@ -66,23 +70,20 @@ func (c *Config) Validate() error { return fmt.Errorf("missing CLEARNODE_WS_URL") case c.DemoPrivateKey == "": return fmt.Errorf("missing DEMO_PRIVATE_KEY") - case len(c.ConsoleAPIKey) < 32: - return fmt.Errorf("CONSOLE_API_KEY must be at least 32 characters") case strings.TrimSpace(c.SQLitePath) == "": return fmt.Errorf("missing SQLITE_PATH") case strings.TrimSpace(c.StoreName) == "": return fmt.Errorf("missing STORE_NAME") case strings.TrimSpace(c.StoreAppID) == "": return fmt.Errorf("missing STORE_APP_ID") - case strings.TrimSpace(c.MerchantName) == "": - return fmt.Errorf("missing MERCHANT_NAME") - case strings.TrimSpace(c.MerchantAppID) == "": - return fmt.Errorf("missing MERCHANT_APP_ID") case len(c.BlockchainRPCURLs) == 0: return fmt.Errorf("missing BLOCKCHAIN_RPC_URLS") case len(c.HomeBlockchains) == 0: return fmt.Errorf("missing HOME_BLOCKCHAINS") } + if len(c.StoreChannelBootstrapAmounts) == 0 { + return fmt.Errorf("missing STORE_CHANNEL_BOOTSTRAP_AMOUNTS") + } return nil } diff --git a/internal/httpapi/appsession.go b/internal/httpapi/appsession.go deleted file mode 100644 index b4c679a..0000000 --- a/internal/httpapi/appsession.go +++ /dev/null @@ -1,210 +0,0 @@ -package httpapi - -import ( - "net/http" - - "github.com/layer-3/nitrolite-go-example/internal/service" -) - -type registerAppRequest struct { - AppID string `json:"app_id"` - Metadata string `json:"metadata"` - CreationApprovalNotRequired bool `json:"creation_approval_not_required"` -} - -type createSessionRequest struct { - ApplicationID string `json:"application_id"` - InitialAllocations []service.InitialAllocationInput `json:"initial_allocations"` - SessionData string `json:"session_data"` -} - -func appsHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - page, err := positiveUint32Query(r, "page", 1) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - perPage, err := positiveUint32Query(r, "per_page", 20) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - apps, meta, err := appSessions.GetApps(r.Context(), service.AppListFilter{ - AppID: optionalQuery(r, "app_id"), - OwnerWallet: optionalQuery(r, "owner_wallet"), - Page: page, - PerPage: perPage, - }) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "apps": encodeApps(apps), - "pagination": encodePagination(meta), - }) - } -} - -func registerAppHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req registerAppRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - if err := appSessions.RegisterApp(r.Context(), req.AppID, req.Metadata, req.CreationApprovalNotRequired); err != nil { - writeServiceError(w, err) - return - } - - w.WriteHeader(http.StatusNoContent) - } -} - -func sessionsHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - page, err := positiveUint32Query(r, "page", 1) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - perPage, err := positiveUint32Query(r, "per_page", 20) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - sessions, meta, err := appSessions.GetSessions(r.Context(), service.SessionListFilter{ - Status: r.URL.Query().Get("status"), - AppSessionID: optionalQuery(r, "app_session_id"), - Participant: optionalQuery(r, "participant"), - Page: page, - PerPage: perPage, - }) - if err != nil { - writeServiceError(w, err) - return - } - - encoded := make([]appSessionResponse, 0, len(sessions)) - for _, session := range sessions { - encoded = append(encoded, encodeAppSession(session)) - } - - writeJSON(w, http.StatusOK, map[string]any{ - "sessions": encoded, - "pagination": encodePagination(meta), - }) - } -} - -func sessionDetailHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - detail, err := appSessions.GetSession(r.Context(), r.PathValue("session_id")) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "session": encodeAppSession(detail.Session), - "app_definition": encodeAppDefinition(detail.AppDefinition), - }) - } -} - -func createSessionHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req createSessionRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - created, err := appSessions.CreateSession(r.Context(), service.CreateAppSessionRequest{ - ApplicationID: req.ApplicationID, - InitialAllocations: req.InitialAllocations, - SessionData: req.SessionData, - }) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "session_id": created.SessionID, - "version": created.Version, - "status": created.Status, - }) - } -} - -func depositSessionHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req service.DepositAppSessionRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - deposited, err := appSessions.DepositSession(r.Context(), r.PathValue("session_id"), req) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "session_id": deposited.SessionID, - "version": deposited.Version, - "node_sig": deposited.NodeSig, - }) - } -} - -func operateSessionHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req service.OperateAppSessionRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - updated, err := appSessions.OperateSession(r.Context(), r.PathValue("session_id"), req) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "session_id": updated.SessionID, - "version": updated.Version, - }) - } -} - -func closeSessionHandler(appSessions *service.AppSessionService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req struct{} - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - closed, err := appSessions.CloseSession(r.Context(), r.PathValue("session_id")) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "session_id": closed.SessionID, - "status": closed.Status, - "final_allocations": encodeAppAllocations(closed.FinalAllocations), - }) - } -} diff --git a/internal/httpapi/auth.go b/internal/httpapi/auth.go deleted file mode 100644 index 6db9bea..0000000 --- a/internal/httpapi/auth.go +++ /dev/null @@ -1,310 +0,0 @@ -package httpapi - -import ( - "crypto/rand" - "encoding/base64" - "errors" - "net/http" - "strings" - "sync" - "time" - - "github.com/layer-3/nitrolite-go-example/internal/store" -) - -const ( - writeSessionCookieName = "nitrolite_write_session" - writeSessionTTL = 2 * time.Hour - storeBrowserCookieName = "nitrolite_store_browser" - storeBrowserCookieTTL = 30 * 24 * time.Hour -) - -type unlockRequest struct { - APIKey string `json:"api_key"` -} - -type authStatusResponse struct { - Unlocked bool `json:"unlocked"` - ExpiresAt string `json:"expires_at,omitempty"` -} - -type writeSessionStore struct { - mu sync.Mutex - sessions map[string]time.Time - now func() time.Time -} - -func newWriteSessionStore() *writeSessionStore { - return &writeSessionStore{ - sessions: make(map[string]time.Time), - now: time.Now, - } -} - -func (s *writeSessionStore) Create() (string, time.Time, error) { - token, err := randomToken() - if err != nil { - return "", time.Time{}, err - } - expiresAt := s.now().UTC().Add(writeSessionTTL) - - s.mu.Lock() - defer s.mu.Unlock() - s.sessions[token] = expiresAt - return token, expiresAt, nil -} - -func (s *writeSessionStore) Validate(token string) (time.Time, bool) { - if token == "" { - return time.Time{}, false - } - - s.mu.Lock() - defer s.mu.Unlock() - - expiresAt, ok := s.sessions[token] - if !ok { - return time.Time{}, false - } - if !expiresAt.After(s.now().UTC()) { - delete(s.sessions, token) - return time.Time{}, false - } - return expiresAt, true -} - -func (s *writeSessionStore) Delete(token string) { - if token == "" { - return - } - s.mu.Lock() - defer s.mu.Unlock() - delete(s.sessions, token) -} - -func authUnlockHandler(expectedAPIKey string, sessions *writeSessionStore) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req unlockRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - if strings.TrimSpace(req.APIKey) == "" { - writeError(w, http.StatusBadRequest, "invalid_request", "api_key is required") - return - } - if strings.TrimSpace(req.APIKey) != expectedAPIKey { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing or invalid api key") - return - } - - token, expiresAt, err := sessions.Create() - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create write session") - return - } - - http.SetCookie(w, newWriteSessionCookie(token, expiresAt, requestIsSecure(r))) - writeJSON(w, http.StatusOK, authStatusResponse{ - Unlocked: true, - ExpiresAt: expiresAt.Format(time.RFC3339), - }) - } -} - -func authLockHandler(sessions *writeSessionStore) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - token, _ := readWriteSession(r) - sessions.Delete(token) - - http.SetCookie(w, &http.Cookie{ - Name: writeSessionCookieName, - Value: "", - Path: "/", - HttpOnly: true, - MaxAge: -1, - SameSite: http.SameSiteLaxMode, - Secure: requestIsSecure(r), - }) - - writeJSON(w, http.StatusOK, authStatusResponse{Unlocked: false}) - } -} - -func authStatusHandler(expectedAPIKey string, sessions *writeSessionStore) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - if hasValidBearerKey(r, expectedAPIKey) { - writeJSON(w, http.StatusOK, authStatusResponse{Unlocked: true}) - return - } - - token, ok := readWriteSession(r) - if !ok { - writeJSON(w, http.StatusOK, authStatusResponse{Unlocked: false}) - return - } - - expiresAt, ok := sessions.Validate(token) - if !ok { - writeJSON(w, http.StatusOK, authStatusResponse{Unlocked: false}) - return - } - - writeJSON(w, http.StatusOK, authStatusResponse{ - Unlocked: true, - ExpiresAt: expiresAt.Format(time.RFC3339), - }) - } -} - -func requireWriteAccess(expectedAPIKey string, sessions *writeSessionStore, next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if hasValidBearerKey(r, expectedAPIKey) { - next.ServeHTTP(w, r) - return - } - - token, ok := readWriteSession(r) - if ok { - if _, valid := sessions.Validate(token); valid { - next.ServeHTTP(w, r) - return - } - } - - writeError(w, http.StatusUnauthorized, "unauthorized", "missing or invalid api key") - }) -} - -func requireLeaseOwnership(sessions *writeSessionStore, leases *store.Store, next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token, ok := readWriteSession(r) - if !ok { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing write session") - return - } - lease, err := leases.GetLease(r.Context()) - if err != nil { - if err == store.ErrNotFound { - writeError(w, http.StatusConflict, "conflict", "operator lease not held") - return - } - writeError(w, http.StatusInternalServerError, "internal_error", "failed to read operator lease") - return - } - if lease.SessionToken != token { - writeError(w, http.StatusConflict, "conflict", "operator lease held by another session") - return - } - - next.ServeHTTP(w, r) - }) -} - -func requireOperatorLease(expectedAPIKey string, sessions *writeSessionStore, leases *store.Store, next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token, ok := readWriteSession(r) - if !ok { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing write session") - return - } - if _, valid := sessions.Validate(token); !valid { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing or invalid api key") - return - } - - lease, err := leases.ActiveLeaseForSession(r.Context(), token) - if err != nil { - switch err { - case store.ErrNotFound: - writeError(w, http.StatusConflict, "conflict", "operator lease held by another session or expired") - default: - writeError(w, http.StatusInternalServerError, "internal_error", "failed to read operator lease") - } - return - } - if lease == nil { - writeError(w, http.StatusConflict, "conflict", "operator lease not held") - return - } - - next.ServeHTTP(w, r) - }) -} - -func hasValidBearerKey(r *http.Request, expected string) bool { - authHeader := strings.TrimSpace(r.Header.Get("Authorization")) - if authHeader == "" { - return false - } - token := strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer ")) - return token != "" && token == expected -} - -func readWriteSession(r *http.Request) (string, bool) { - cookie, err := r.Cookie(writeSessionCookieName) - if err != nil { - return "", false - } - token := strings.TrimSpace(cookie.Value) - return token, token != "" -} - -func newWriteSessionCookie(token string, expiresAt time.Time, secure bool) *http.Cookie { - return &http.Cookie{ - Name: writeSessionCookieName, - Value: token, - Path: "/", - Expires: expiresAt, - HttpOnly: true, - SameSite: http.SameSiteLaxMode, - Secure: secure, - } -} - -func requestIsSecure(r *http.Request) bool { - if r.TLS != nil { - return true - } - return strings.EqualFold(strings.TrimSpace(r.Header.Get("X-Forwarded-Proto")), "https") -} - -func randomToken() (string, error) { - buf := make([]byte, 32) - if _, err := rand.Read(buf); err != nil { - return "", err - } - return base64.RawURLEncoding.EncodeToString(buf), nil -} - -var errNoCookie = errors.New("missing cookie") - -func ensureStoreBrowserSession(w http.ResponseWriter, r *http.Request) (string, bool, error) { - if token, ok := readStoreBrowserSession(r); ok { - return token, false, nil - } - - token, err := randomToken() - if err != nil { - return "", false, err - } - http.SetCookie(w, &http.Cookie{ - Name: storeBrowserCookieName, - Value: token, - Path: "/", - Expires: time.Now().UTC().Add(storeBrowserCookieTTL), - HttpOnly: true, - SameSite: http.SameSiteLaxMode, - Secure: requestIsSecure(r), - }) - return token, true, nil -} - -func readStoreBrowserSession(r *http.Request) (string, bool) { - cookie, err := r.Cookie(storeBrowserCookieName) - if err != nil { - return "", false - } - token := strings.TrimSpace(cookie.Value) - return token, token != "" -} diff --git a/internal/httpapi/balance.go b/internal/httpapi/balance.go deleted file mode 100644 index 068fd8b..0000000 --- a/internal/httpapi/balance.go +++ /dev/null @@ -1,52 +0,0 @@ -package httpapi - -import ( - "net/http" - - "github.com/layer-3/nitrolite-go-example/internal/service" -) - -func balancesHandler(balanceService *service.BalanceService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - balances, err := balanceService.GetBalances(r.Context()) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "balances": encodeBalances(balances), - }) - } -} - -func transactionsHandler(balanceService *service.BalanceService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - page, err := positiveUint32Query(r, "page", 1) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - perPage, err := positiveUint32Query(r, "per_page", 20) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - transactions, meta, err := balanceService.GetTransactions(r.Context(), service.TransactionsFilter{ - Asset: optionalQuery(r, "asset"), - Page: page, - PerPage: perPage, - }) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "transactions": encodeTransactions(transactions), - "pagination": encodePagination(meta), - }) - } -} diff --git a/internal/httpapi/channel.go b/internal/httpapi/channel.go deleted file mode 100644 index 56f636b..0000000 --- a/internal/httpapi/channel.go +++ /dev/null @@ -1,53 +0,0 @@ -package httpapi - -import ( - "net/http" - - "github.com/layer-3/nitrolite-go-example/internal/service" -) - -func channelHandler(channelService *service.ChannelService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - asset, err := requireQuery(r, "asset") - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - channel, err := channelService.GetHomeChannel(r.Context(), asset) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "channel": encodeChannel(channel), - }) - } -} - -func channelStateHandler(channelService *service.ChannelService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - asset, err := requireQuery(r, "asset") - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - onlySigned, err := optionalBoolQuery(r, "only_signed", false) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - state, err := channelService.GetLatestState(r.Context(), asset, onlySigned) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "state": encodeState(state), - }) - } -} diff --git a/internal/httpapi/demo.go b/internal/httpapi/demo.go deleted file mode 100644 index ceaec42..0000000 --- a/internal/httpapi/demo.go +++ /dev/null @@ -1,19 +0,0 @@ -package httpapi - -import ( - "net/http" - - "github.com/layer-3/nitrolite-go-example/internal/service" -) - -func demoOverviewHandler(demoService *service.DemoService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - overview, err := demoService.GetOverview(r.Context(), r.URL.Query().Get("asset")) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, encodeDemoOverview(overview)) - } -} diff --git a/internal/httpapi/encode.go b/internal/httpapi/encode.go deleted file mode 100644 index 6470c00..0000000 --- a/internal/httpapi/encode.go +++ /dev/null @@ -1,531 +0,0 @@ -package httpapi - -import ( - "time" - - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/service" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" -) - -type nodeConfigResponse struct { - NodeAddress string `json:"nodeAddress"` - NodeVersion string `json:"nodeVersion"` - SupportedSigValidators []string `json:"supportedSigValidators"` - Blockchains []blockchainResponse `json:"blockchains"` -} - -type blockchainResponse struct { - ID uint64 `json:"id"` - Name string `json:"name"` - ChannelHubAddress string `json:"channelHubAddress"` - LockingContractAddress string `json:"lockingContractAddress"` - BlockStep uint64 `json:"blockStep"` -} - -type assetResponse struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - Decimals uint8 `json:"decimals"` - SuggestedBlockchainID uint64 `json:"suggestedBlockchainID"` - Tokens []tokenResponse `json:"tokens"` -} - -type tokenResponse struct { - Name string `json:"name"` - Symbol string `json:"symbol"` - Address string `json:"address"` - BlockchainID uint64 `json:"blockchainId"` - Decimals uint8 `json:"decimals"` -} - -type balanceResponse struct { - Asset string `json:"asset"` - Balance string `json:"balance"` -} - -type paginationResponse struct { - Page uint32 `json:"page"` - PerPage uint32 `json:"perPage"` - TotalCount uint32 `json:"totalCount"` - PageCount uint32 `json:"pageCount"` -} - -type transactionResponse struct { - ID string `json:"id"` - Asset string `json:"asset"` - Type string `json:"type"` - From string `json:"from"` - To string `json:"to"` - SenderNewStateID *string `json:"senderNewStateID,omitempty"` - ReceiverNewStateID *string `json:"receiverNewStateID,omitempty"` - Amount string `json:"amount"` - Timestamp string `json:"timestamp"` -} - -type channelResponse struct { - ChannelID string `json:"channelID"` - UserWallet string `json:"userWallet"` - Asset string `json:"asset"` - Type string `json:"type"` - BlockchainID uint64 `json:"blockchainID"` - TokenAddress string `json:"tokenAddress"` - ChallengeDuration uint32 `json:"challengeDuration"` - ChallengeExpiresAt *string `json:"challengeExpiresAt,omitempty"` - Nonce uint64 `json:"nonce"` - ApprovedSigValidators string `json:"approvedSigValidators"` - Status string `json:"status"` - StateVersion uint64 `json:"stateVersion"` -} - -type stateResponse struct { - ID string `json:"id"` - Asset string `json:"asset"` - UserWallet string `json:"userWallet"` - Epoch uint64 `json:"epoch"` - Version uint64 `json:"version"` - HomeChannelID *string `json:"homeChannelID,omitempty"` - EscrowChannelID *string `json:"escrowChannelID,omitempty"` - Transition transitionResponse `json:"transition"` - HomeLedger ledgerResponse `json:"homeLedger"` - EscrowLedger *ledgerResponse `json:"escrowLedger,omitempty"` - UserSig *string `json:"userSig,omitempty"` - NodeSig *string `json:"nodeSig,omitempty"` -} - -type transitionResponse struct { - Type string `json:"type"` - TxID string `json:"txID"` - AccountID string `json:"accountID"` - Amount string `json:"amount"` -} - -type ledgerResponse struct { - TokenAddress string `json:"tokenAddress"` - BlockchainID uint64 `json:"blockchainID"` - UserBalance string `json:"userBalance"` - UserNetFlow string `json:"userNetFlow"` - NodeBalance string `json:"nodeBalance"` - NodeNetFlow string `json:"nodeNetFlow"` -} - -type appInfoResponse struct { - AppID string `json:"app_id"` - OwnerWallet string `json:"owner_wallet"` - Metadata string `json:"metadata"` - Version uint64 `json:"version"` - CreationApprovalNotRequired bool `json:"creation_approval_not_required"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type appParticipantResponse struct { - WalletAddress string `json:"wallet_address"` - SignatureWeight uint8 `json:"signature_weight"` -} - -type appDefinitionResponse struct { - ApplicationID string `json:"application_id"` - Participants []appParticipantResponse `json:"participants"` - Quorum uint8 `json:"quorum"` - Nonce uint64 `json:"nonce"` -} - -type appAllocationResponse struct { - Participant string `json:"participant"` - Asset string `json:"asset"` - Amount string `json:"amount"` -} - -type appSessionResponse struct { - AppSessionID string `json:"app_session_id"` - ApplicationID string `json:"application_id"` - Participants []appParticipantResponse `json:"participants"` - Quorum uint8 `json:"quorum"` - Nonce uint64 `json:"nonce"` - Status string `json:"status"` - Version uint64 `json:"version"` - SessionData string `json:"session_data"` - Allocations []appAllocationResponse `json:"allocations"` -} - -type appSessionKeyStateResponse struct { - UserAddress string `json:"user_address"` - SessionKey string `json:"session_key"` - Version uint64 `json:"version"` - ApplicationIDs []string `json:"application_ids"` - AppSessionIDs []string `json:"app_session_ids"` - ExpiresAt string `json:"expires_at"` - UserSig string `json:"user_sig"` -} - -type channelSessionKeyStateResponse struct { - UserAddress string `json:"user_address"` - SessionKey string `json:"session_key"` - Version uint64 `json:"version"` - Assets []string `json:"assets"` - ExpiresAt string `json:"expires_at"` - UserSig string `json:"user_sig"` -} - -type healthResponse struct { - Connected bool `json:"connected"` - Ready bool `json:"ready"` - SignerAddress string `json:"signer_address"` -} - -type walletResponse struct { - Address string `json:"address"` - HomeBlockchains map[string]uint64 `json:"home_blockchains"` -} - -type demoGuidanceResponse struct { - NextAction string `json:"next_action"` - Headline string `json:"headline"` - Description string `json:"description"` - SyncPending bool `json:"sync_pending"` -} - -type demoOverviewResponse struct { - Status healthResponse `json:"status"` - Wallet walletResponse `json:"wallet"` - SelectedAsset string `json:"selected_asset"` - Assets []assetResponse `json:"assets"` - Balances []balanceResponse `json:"balances"` - Channel *channelResponse `json:"channel,omitempty"` - LatestState *stateResponse `json:"latest_state,omitempty"` - LatestActivity *transactionResponse `json:"latest_activity,omitempty"` - Apps []appInfoResponse `json:"apps"` - Sessions []appSessionResponse `json:"sessions"` - ChannelGuidance demoGuidanceResponse `json:"channel_guidance"` - AppGuidance demoGuidanceResponse `json:"app_guidance"` -} - -func encodeNodeConfig(cfg *core.NodeConfig) nodeConfigResponse { - supported := make([]string, 0, len(cfg.SupportedSigValidators)) - for _, validator := range cfg.SupportedSigValidators { - supported = append(supported, validator.String()) - } - - return nodeConfigResponse{ - NodeAddress: cfg.NodeAddress, - NodeVersion: cfg.NodeVersion, - SupportedSigValidators: supported, - Blockchains: encodeBlockchains(cfg.Blockchains), - } -} - -func encodeHealth(health nitrolite.Health) healthResponse { - return healthResponse{ - Connected: health.Connected, - Ready: health.Ready, - SignerAddress: health.SignerAddress, - } -} - -func encodeBlockchains(blockchains []core.Blockchain) []blockchainResponse { - items := make([]blockchainResponse, 0, len(blockchains)) - for _, blockchain := range blockchains { - items = append(items, blockchainResponse{ - ID: blockchain.ID, - Name: blockchain.Name, - ChannelHubAddress: blockchain.ChannelHubAddress, - LockingContractAddress: blockchain.LockingContractAddress, - BlockStep: blockchain.BlockStep, - }) - } - return items -} - -func encodeAssets(assets []core.Asset) []assetResponse { - items := make([]assetResponse, 0, len(assets)) - for _, asset := range assets { - tokens := make([]tokenResponse, 0, len(asset.Tokens)) - for _, token := range asset.Tokens { - tokens = append(tokens, tokenResponse{ - Name: token.Name, - Symbol: token.Symbol, - Address: token.Address, - BlockchainID: token.BlockchainID, - Decimals: token.Decimals, - }) - } - - items = append(items, assetResponse{ - Name: asset.Name, - Symbol: asset.Symbol, - Decimals: asset.Decimals, - SuggestedBlockchainID: asset.SuggestedBlockchainID, - Tokens: tokens, - }) - } - return items -} - -func encodeBalances(balances []core.BalanceEntry) []balanceResponse { - items := make([]balanceResponse, 0, len(balances)) - for _, balance := range balances { - items = append(items, balanceResponse{ - Asset: balance.Asset, - Balance: balance.Balance.String(), - }) - } - return items -} - -func encodePagination(meta core.PaginationMetadata) paginationResponse { - return paginationResponse{ - Page: meta.Page, - PerPage: meta.PerPage, - TotalCount: meta.TotalCount, - PageCount: meta.PageCount, - } -} - -func encodeTransactions(transactions []core.Transaction) []transactionResponse { - items := make([]transactionResponse, 0, len(transactions)) - for _, transaction := range transactions { - items = append(items, encodeTransaction(transaction)) - } - return items -} - -func encodeTransaction(transaction core.Transaction) transactionResponse { - return transactionResponse{ - ID: transaction.ID, - Asset: transaction.Asset, - Type: transaction.TxType.String(), - From: transaction.FromAccount, - To: transaction.ToAccount, - SenderNewStateID: transaction.SenderNewStateID, - ReceiverNewStateID: transaction.ReceiverNewStateID, - Amount: transaction.Amount.String(), - Timestamp: transaction.CreatedAt.UTC().Format(time.RFC3339), - } -} - -func encodeChannel(channel *core.Channel) channelResponse { - var challengeExpiresAt *string - if channel.ChallengeExpiresAt != nil { - value := channel.ChallengeExpiresAt.UTC().Format(time.RFC3339) - challengeExpiresAt = &value - } - - return channelResponse{ - ChannelID: channel.ChannelID, - UserWallet: channel.UserWallet, - Asset: channel.Asset, - Type: channelTypeString(channel.Type), - BlockchainID: channel.BlockchainID, - TokenAddress: channel.TokenAddress, - ChallengeDuration: channel.ChallengeDuration, - ChallengeExpiresAt: challengeExpiresAt, - Nonce: channel.Nonce, - ApprovedSigValidators: channel.ApprovedSigValidators, - Status: channel.Status.String(), - StateVersion: channel.StateVersion, - } -} - -func encodeState(state *core.State) stateResponse { - var escrowLedger *ledgerResponse - if state.EscrowLedger != nil { - encoded := encodeLedger(*state.EscrowLedger) - escrowLedger = &encoded - } - - return stateResponse{ - ID: state.ID, - Asset: state.Asset, - UserWallet: state.UserWallet, - Epoch: state.Epoch, - Version: state.Version, - HomeChannelID: state.HomeChannelID, - EscrowChannelID: state.EscrowChannelID, - Transition: transitionResponse{ - Type: state.Transition.Type.String(), - TxID: state.Transition.TxID, - AccountID: state.Transition.AccountID, - Amount: state.Transition.Amount.String(), - }, - HomeLedger: encodeLedger(state.HomeLedger), - EscrowLedger: escrowLedger, - UserSig: state.UserSig, - NodeSig: state.NodeSig, - } -} - -func encodeLedger(ledger core.Ledger) ledgerResponse { - return ledgerResponse{ - TokenAddress: ledger.TokenAddress, - BlockchainID: ledger.BlockchainID, - UserBalance: ledger.UserBalance.String(), - UserNetFlow: ledger.UserNetFlow.String(), - NodeBalance: ledger.NodeBalance.String(), - NodeNetFlow: ledger.NodeNetFlow.String(), - } -} - -func channelTypeString(channelType core.ChannelType) string { - switch channelType { - case core.ChannelTypeHome: - return "home" - case core.ChannelTypeEscrow: - return "escrow" - default: - return "unknown" - } -} - -func encodeApps(apps []app.AppInfoV1) []appInfoResponse { - items := make([]appInfoResponse, 0, len(apps)) - for _, item := range apps { - items = append(items, appInfoResponse{ - AppID: item.App.ID, - OwnerWallet: item.App.OwnerWallet, - Metadata: item.App.Metadata, - Version: item.App.Version, - CreationApprovalNotRequired: item.App.CreationApprovalNotRequired, - CreatedAt: item.CreatedAt.UTC().Format(time.RFC3339), - UpdatedAt: item.UpdatedAt.UTC().Format(time.RFC3339), - }) - } - return items -} - -func encodeAppParticipants(participants []app.AppParticipantV1) []appParticipantResponse { - items := make([]appParticipantResponse, 0, len(participants)) - for _, participant := range participants { - items = append(items, appParticipantResponse{ - WalletAddress: participant.WalletAddress, - SignatureWeight: participant.SignatureWeight, - }) - } - return items -} - -func encodeAppDefinition(definition app.AppDefinitionV1) appDefinitionResponse { - return appDefinitionResponse{ - ApplicationID: definition.ApplicationID, - Participants: encodeAppParticipants(definition.Participants), - Quorum: definition.Quorum, - Nonce: definition.Nonce, - } -} - -func encodeAppAllocations(allocations []app.AppAllocationV1) []appAllocationResponse { - items := make([]appAllocationResponse, 0, len(allocations)) - for _, allocation := range allocations { - items = append(items, appAllocationResponse{ - Participant: allocation.Participant, - Asset: allocation.Asset, - Amount: allocation.Amount.String(), - }) - } - return items -} - -func encodeAppSession(session app.AppSessionInfoV1) appSessionResponse { - status := "open" - if session.IsClosed { - status = "closed" - } - return appSessionResponse{ - AppSessionID: session.AppSessionID, - ApplicationID: session.AppDefinition.ApplicationID, - Participants: encodeAppParticipants(session.AppDefinition.Participants), - Quorum: session.AppDefinition.Quorum, - Nonce: session.AppDefinition.Nonce, - Status: status, - Version: session.Version, - SessionData: session.SessionData, - Allocations: encodeAppAllocations(session.Allocations), - } -} - -func encodeAppSessionKeyStates(states []app.AppSessionKeyStateV1) []appSessionKeyStateResponse { - items := make([]appSessionKeyStateResponse, 0, len(states)) - for _, state := range states { - items = append(items, appSessionKeyStateResponse{ - UserAddress: state.UserAddress, - SessionKey: state.SessionKey, - Version: state.Version, - ApplicationIDs: append([]string(nil), state.ApplicationIDs...), - AppSessionIDs: append([]string(nil), state.AppSessionIDs...), - ExpiresAt: state.ExpiresAt.UTC().Format(time.RFC3339), - UserSig: state.UserSig, - }) - } - return items -} - -func encodeChannelSessionKeyStates(states []core.ChannelSessionKeyStateV1) []channelSessionKeyStateResponse { - items := make([]channelSessionKeyStateResponse, 0, len(states)) - for _, state := range states { - items = append(items, channelSessionKeyStateResponse{ - UserAddress: state.UserAddress, - SessionKey: state.SessionKey, - Version: state.Version, - Assets: append([]string(nil), state.Assets...), - ExpiresAt: state.ExpiresAt.UTC().Format(time.RFC3339), - UserSig: state.UserSig, - }) - } - return items -} - -func encodeDemoGuidance(guidance service.DemoGuidance) demoGuidanceResponse { - return demoGuidanceResponse{ - NextAction: guidance.NextAction, - Headline: guidance.Headline, - Description: guidance.Description, - SyncPending: guidance.SyncPending, - } -} - -func encodeDemoOverview(overview *service.DemoOverview) demoOverviewResponse { - var channel *channelResponse - if overview.Channel != nil { - encoded := encodeChannel(overview.Channel) - channel = &encoded - } - - var latestState *stateResponse - if overview.LatestState != nil { - encoded := encodeState(overview.LatestState) - latestState = &encoded - } - - var latestActivity *transactionResponse - if overview.LatestActivity != nil { - encoded := encodeTransaction(*overview.LatestActivity) - latestActivity = &encoded - } - - return demoOverviewResponse{ - Status: encodeHealth(overview.Health), - Wallet: walletResponse{ - Address: overview.WalletAddress, - HomeBlockchains: overview.HomeBlockchains, - }, - SelectedAsset: overview.SelectedAsset, - Assets: encodeAssets(overview.Assets), - Balances: encodeBalances(overview.Balances), - Channel: channel, - LatestState: latestState, - LatestActivity: latestActivity, - Apps: encodeApps(overview.Apps), - Sessions: encodeAppSessions(overview.Sessions), - ChannelGuidance: encodeDemoGuidance(overview.ChannelGuidance), - AppGuidance: encodeDemoGuidance(overview.AppGuidance), - } -} - -func encodeAppSessions(sessions []app.AppSessionInfoV1) []appSessionResponse { - items := make([]appSessionResponse, 0, len(sessions)) - for _, session := range sessions { - items = append(items, encodeAppSession(session)) - } - return items -} diff --git a/internal/httpapi/health.go b/internal/httpapi/health.go index d22cdbb..50f4412 100644 --- a/internal/httpapi/health.go +++ b/internal/httpapi/health.go @@ -3,7 +3,7 @@ package httpapi import ( "net/http" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" ) func healthHandler(manager *nitrolite.Manager) http.HandlerFunc { diff --git a/internal/httpapi/merchant.go b/internal/httpapi/merchant.go deleted file mode 100644 index d2ab4e5..0000000 --- a/internal/httpapi/merchant.go +++ /dev/null @@ -1,518 +0,0 @@ -package httpapi - -import ( - "encoding/json" - "net/http" - "strings" - "time" - - "github.com/layer-3/nitrolite-go-example/internal/service" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/shopspring/decimal" -) - -type createPaymentRequestBody struct { - Title string `json:"title"` - Description string `json:"description"` - Asset string `json:"asset"` - Amount string `json:"amount"` -} - -type payoutBody struct { - Asset string `json:"asset"` - Amount string `json:"amount"` - DestinationWallet string `json:"destination_wallet"` -} - -type leaseStatusResponse struct { - Held bool `json:"held"` - OwnedByCurrentSession bool `json:"owned_by_current_session"` - AcquiredAt string `json:"acquired_at,omitempty"` - HeartbeatAt string `json:"heartbeat_at,omitempty"` - ExpiresAt string `json:"expires_at,omitempty"` -} - -type paymentRequestResponse struct { - PaymentRequestID string `json:"payment_request_id"` - Slug string `json:"slug"` - Title string `json:"title"` - Description string `json:"description"` - Asset string `json:"asset"` - Amount string `json:"amount"` - Status string `json:"status"` - OrderID string `json:"order_id,omitempty"` - OperationID string `json:"operation_id,omitempty"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type orderResponse struct { - OrderID string `json:"order_id"` - PaymentRequestID string `json:"payment_request_id"` - OperationID string `json:"operation_id"` - AppSessionID string `json:"app_session_id,omitempty"` - Title string `json:"title"` - Description string `json:"description"` - Asset string `json:"asset"` - Amount string `json:"amount"` - Status string `json:"status"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type payoutResponse struct { - PayoutID string `json:"payout_id"` - OperationID string `json:"operation_id"` - Asset string `json:"asset"` - Amount string `json:"amount"` - DestinationWallet string `json:"destination_wallet"` - Status string `json:"status"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type operationResponse struct { - OperationID string `json:"operation_id"` - Type string `json:"type"` - ResourceID string `json:"resource_id"` - Status string `json:"status"` - ErrorMessage string `json:"error_message,omitempty"` - Payload any `json:"payload,omitempty"` - QueuedAt string `json:"queued_at"` - StartedAt *string `json:"started_at,omitempty"` - CompletedAt *string `json:"completed_at,omitempty"` -} - -func dashboardOverviewHandler(dashboard *service.MerchantDashboardService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - overview, err := dashboard.GetOverview(r.Context(), r.URL.Query().Get("asset")) - if err != nil { - writeServiceError(w, err) - return - } - payload := map[string]any{ - "merchant_name": overview.MerchantName, - "status": encodeHealth(overview.Health), - "wallet": walletResponse{Address: overview.WalletAddress, HomeBlockchains: overview.HomeBlockchains}, - "selected_asset": overview.SelectedAsset, - "assets": encodeAssets(overview.Assets), - "balances": encodeBalances(overview.Balances), - "payment_requests": encodePaymentRequests(overview.PaymentRequests), - "orders": encodeOrders(overview.Orders), - "payouts": encodePayouts(overview.Payouts), - "operations": encodeOperations(overview.Operations), - "summary": map[string]any{ - "available_balance": overview.Summary.AvailableBalance, - "reserved_balance": overview.Summary.ReservedBalance, - "pending_count": overview.Summary.PendingCount, - "open_orders": overview.Summary.OpenOrders, - }, - } - if overview.Channel != nil { - encoded := encodeChannel(overview.Channel) - payload["channel"] = encoded - } - if overview.LatestState != nil { - encoded := encodeState(overview.LatestState) - payload["latest_state"] = encoded - } - if overview.LatestActivity != nil { - encoded := encodeTransaction(*overview.LatestActivity) - payload["latest_activity"] = encoded - } - if overview.Lease != nil { - payload["lease"] = encodeLeaseStatus(overview.Lease, tokenOwnsLease(r, overview.Lease)) - } - writeJSON(w, http.StatusOK, payload) - } -} - -func createPaymentRequestHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var body createPaymentRequestBody - if err := decodeJSON(r, &body); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - amount, err := decimal.NewFromString(strings.TrimSpace(body.Amount)) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", "amount must be a decimal string") - return - } - result, err := merchant.CreatePaymentRequest(r.Context(), service.CreatePaymentRequestRequest{ - Title: body.Title, - Description: body.Description, - Asset: body.Asset, - Amount: amount, - }, requestBaseURL(r)) - if err != nil { - writeServiceError(w, err) - return - } - - response := encodePaymentRequest(result.PaymentRequest) - writeJSON(w, http.StatusCreated, map[string]any{ - "payment_request_id": response.PaymentRequestID, - "slug": response.Slug, - "pay_url": result.PayURL, - "status": response.Status, - "payment_request": response, - }) - } -} - -func paymentRequestPageHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - slug := r.PathValue("slug") - page, err := merchant.GetPaymentRequestPage(r.Context(), slug) - if err != nil { - writeServiceError(w, err) - return - } - payload := map[string]any{ - "merchant_name": page.MerchantName, - "payment_request": encodePaymentRequest(page.PaymentRequest), - } - if page.Order != nil { - payload["order"] = encodeOrder(*page.Order) - } - if page.Operation != nil { - payload["operation"] = encodeOperation(*page.Operation) - } - writeJSON(w, http.StatusOK, payload) - } -} - -func payPaymentRequestHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - result, err := merchant.PayPaymentRequest(r.Context(), r.PathValue("slug")) - if err != nil { - writeServiceError(w, err) - return - } - - status := http.StatusAccepted - if !result.Created { - status = http.StatusOK - } - writeJSON(w, status, map[string]any{ - "operation_id": result.Operation.ID, - "resource_id": result.ResourceID, - "status": result.Operation.Status, - }) - } -} - -func ordersHandler(appStore *store.Store) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - orders, err := appStore.ListOrders(r.Context(), 50) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to list orders") - return - } - writeJSON(w, http.StatusOK, map[string]any{"orders": encodeOrders(orders)}) - } -} - -func orderDetailHandler(appStore *store.Store) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - order, err := appStore.GetOrder(r.Context(), r.PathValue("id")) - if err != nil { - if err == store.ErrNotFound { - writeError(w, http.StatusUnprocessableEntity, "not_found", "order not found") - return - } - writeError(w, http.StatusInternalServerError, "internal_error", "failed to load order") - return - } - writeJSON(w, http.StatusOK, map[string]any{"order": encodeOrder(*order)}) - } -} - -func settleOrderHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - result, err := merchant.QueueOrderResolution(r.Context(), r.PathValue("id"), "settle") - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusAccepted, map[string]any{ - "operation_id": result.Operation.ID, - "resource_id": result.ResourceID, - "status": result.Operation.Status, - }) - } -} - -func refundOrderHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - result, err := merchant.QueueOrderResolution(r.Context(), r.PathValue("id"), "refund") - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusAccepted, map[string]any{ - "operation_id": result.Operation.ID, - "resource_id": result.ResourceID, - "status": result.Operation.Status, - }) - } -} - -func payoutsHandler(appStore *store.Store) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - payouts, err := appStore.ListPayouts(r.Context(), 50) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to list payouts") - return - } - writeJSON(w, http.StatusOK, map[string]any{"payouts": encodePayouts(payouts)}) - } -} - -func createPayoutHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var body payoutBody - if err := decodeJSON(r, &body); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - amount, err := decimal.NewFromString(strings.TrimSpace(body.Amount)) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", "amount must be a decimal string") - return - } - result, err := merchant.QueuePayout(r.Context(), service.PayoutRequest{ - Asset: body.Asset, - Amount: amount, - DestinationWallet: body.DestinationWallet, - }) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusAccepted, map[string]any{ - "operation_id": result.Operation.ID, - "resource_id": result.ResourceID, - "status": result.Operation.Status, - }) - } -} - -func operationHandler(merchant *service.MerchantService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - op, err := merchant.GetOperation(r.Context(), r.PathValue("id")) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"operation": encodeOperation(*op)}) - } -} - -func leaseStatusHandler(leases *store.Store) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - lease, err := leases.GetLease(r.Context()) - if err != nil { - if err == store.ErrNotFound { - writeJSON(w, http.StatusOK, leaseStatusResponse{Held: false}) - return - } - writeError(w, http.StatusInternalServerError, "internal_error", "failed to read operator lease") - return - } - writeJSON(w, http.StatusOK, encodeLeaseStatus(lease, tokenOwnsLease(r, lease))) - } -} - -func leaseAcquireHandler(leases *store.Store, ttl time.Duration) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - token, ok := readWriteSession(r) - if !ok { - writeError(w, http.StatusBadRequest, "invalid_request", "lease acquisition requires a browser write session") - return - } - lease, err := leases.AcquireLease(r.Context(), token, ttl) - if err != nil { - if err == store.ErrConflict { - writeError(w, http.StatusConflict, "conflict", "operator lease held by another session") - return - } - writeError(w, http.StatusInternalServerError, "internal_error", "failed to acquire operator lease") - return - } - writeJSON(w, http.StatusOK, encodeLeaseStatus(lease, true)) - } -} - -func leaseReleaseHandler(leases *store.Store) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - token, _ := readWriteSession(r) - if err := leases.ReleaseLease(r.Context(), token); err != nil && err != store.ErrNotFound { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to release operator lease") - return - } - writeJSON(w, http.StatusOK, leaseStatusResponse{Held: false}) - } -} - -func leaseHeartbeatHandler(leases *store.Store, ttl time.Duration) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - token, _ := readWriteSession(r) - lease, err := leases.HeartbeatLease(r.Context(), token, ttl) - if err != nil { - if err == store.ErrNotFound { - writeError(w, http.StatusConflict, "conflict", "operator lease not held by this session") - return - } - writeError(w, http.StatusInternalServerError, "internal_error", "failed to heartbeat operator lease") - return - } - writeJSON(w, http.StatusOK, encodeLeaseStatus(lease, true)) - } -} - -func encodeLeaseStatus(lease *store.OperatorLease, owned bool) leaseStatusResponse { - if lease == nil { - return leaseStatusResponse{Held: false} - } - return leaseStatusResponse{ - Held: true, - OwnedByCurrentSession: owned, - AcquiredAt: lease.AcquiredAt.UTC().Format(time.RFC3339), - HeartbeatAt: lease.HeartbeatAt.UTC().Format(time.RFC3339), - ExpiresAt: lease.ExpiresAt.UTC().Format(time.RFC3339), - } -} - -func encodePaymentRequests(items []store.PaymentRequest) []paymentRequestResponse { - out := make([]paymentRequestResponse, 0, len(items)) - for _, item := range items { - out = append(out, encodePaymentRequest(item)) - } - return out -} - -func encodePaymentRequest(item store.PaymentRequest) paymentRequestResponse { - return paymentRequestResponse{ - PaymentRequestID: item.ID, - Slug: item.Slug, - Title: item.Title, - Description: item.Description, - Asset: item.Asset, - Amount: item.Amount, - Status: item.Status, - OrderID: item.OrderID, - OperationID: item.OperationID, - CreatedAt: item.CreatedAt.UTC().Format(time.RFC3339), - UpdatedAt: item.UpdatedAt.UTC().Format(time.RFC3339), - } -} - -func encodeOrders(items []store.Order) []orderResponse { - out := make([]orderResponse, 0, len(items)) - for _, item := range items { - out = append(out, encodeOrder(item)) - } - return out -} - -func encodeOrder(item store.Order) orderResponse { - return orderResponse{ - OrderID: item.ID, - PaymentRequestID: item.PaymentRequestID, - OperationID: item.OperationID, - AppSessionID: item.AppSessionID, - Title: item.Title, - Description: item.Description, - Asset: item.Asset, - Amount: item.Amount, - Status: item.Status, - CreatedAt: item.CreatedAt.UTC().Format(time.RFC3339), - UpdatedAt: item.UpdatedAt.UTC().Format(time.RFC3339), - } -} - -func encodePayouts(items []store.Payout) []payoutResponse { - out := make([]payoutResponse, 0, len(items)) - for _, item := range items { - out = append(out, encodePayout(item)) - } - return out -} - -func encodePayout(item store.Payout) payoutResponse { - return payoutResponse{ - PayoutID: item.ID, - OperationID: item.OperationID, - Asset: item.Asset, - Amount: item.Amount, - DestinationWallet: item.DestinationWallet, - Status: item.Status, - CreatedAt: item.CreatedAt.UTC().Format(time.RFC3339), - UpdatedAt: item.UpdatedAt.UTC().Format(time.RFC3339), - } -} - -func encodeOperations(items []store.Operation) []operationResponse { - out := make([]operationResponse, 0, len(items)) - for _, item := range items { - out = append(out, encodeOperation(item)) - } - return out -} - -func encodeOperation(item store.Operation) operationResponse { - var payload any - if parsed, err := decodeOperationPayload(item.Payload); err == nil { - payload = parsed - } - var startedAt *string - if item.StartedAt != nil { - value := item.StartedAt.UTC().Format(time.RFC3339) - startedAt = &value - } - var completedAt *string - if item.CompletedAt != nil { - value := item.CompletedAt.UTC().Format(time.RFC3339) - completedAt = &value - } - return operationResponse{ - OperationID: item.ID, - Type: item.Type, - ResourceID: item.ResourceID, - Status: item.Status, - ErrorMessage: item.ErrorMessage, - Payload: payload, - QueuedAt: item.QueuedAt.UTC().Format(time.RFC3339), - StartedAt: startedAt, - CompletedAt: completedAt, - } -} - -func tokenOwnsLease(r *http.Request, lease *store.OperatorLease) bool { - if lease == nil { - return false - } - token, ok := readWriteSession(r) - return ok && token == lease.SessionToken -} - -func requestBaseURL(r *http.Request) string { - scheme := "http" - if requestIsSecure(r) { - scheme = "https" - } - return scheme + "://" + r.Host -} - -func decodeOperationPayload(raw string) (any, error) { - if strings.TrimSpace(raw) == "" { - return nil, nil - } - var payload any - if err := json.Unmarshal([]byte(raw), &payload); err != nil { - return nil, err - } - return payload, nil -} diff --git a/internal/httpapi/mutations.go b/internal/httpapi/mutations.go deleted file mode 100644 index 00dce43..0000000 --- a/internal/httpapi/mutations.go +++ /dev/null @@ -1,179 +0,0 @@ -package httpapi - -import ( - "net/http" - - "github.com/layer-3/nitrolite-go-example/internal/service" - "github.com/shopspring/decimal" -) - -type approveRequest struct { - BlockchainID uint64 `json:"blockchain_id"` - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -type depositRequest struct { - BlockchainID uint64 `json:"blockchain_id"` - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -type withdrawRequest struct { - BlockchainID uint64 `json:"blockchain_id"` - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -type transferRequest struct { - Recipient string `json:"recipient"` - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -type checkpointRequest struct { - Asset string `json:"asset"` -} - -type closeChannelRequest struct { - Asset string `json:"asset"` -} - -type challengeRequest struct { - Asset string `json:"asset"` -} - -func approveHandler(mutations *service.MutationService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req approveRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - txHash, err := mutations.ApproveToken(r.Context(), req.BlockchainID, req.Asset, req.Amount) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{"tx_hash": txHash}) - } -} - -func depositHandler(mutations *service.MutationService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req depositRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - state, err := mutations.Deposit(r.Context(), req.BlockchainID, req.Asset, req.Amount) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "state": encodeState(state), - "ready_for_checkpoint": true, - }) - } -} - -func withdrawHandler(mutations *service.MutationService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req withdrawRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - state, err := mutations.Withdraw(r.Context(), req.BlockchainID, req.Asset, req.Amount) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "state": encodeState(state), - "ready_for_checkpoint": true, - }) - } -} - -func transferHandler(mutations *service.MutationService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req transferRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - state, err := mutations.Transfer(r.Context(), req.Recipient, req.Asset, req.Amount) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "state": encodeState(state), - "note": "off-chain only, no checkpoint needed", - }) - } -} - -func checkpointHandler(mutations *service.MutationService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req checkpointRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - txHash, err := mutations.Checkpoint(r.Context(), req.Asset) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{"tx_hash": txHash}) - } -} - -func closeChannelHandler(channelService *service.ChannelService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req closeChannelRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - state, err := channelService.CloseChannel(r.Context(), service.CloseChannelRequest{Asset: req.Asset}) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{"state": encodeState(state)}) - } -} - -func challengeHandler(channelService *service.ChannelService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req challengeRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - result, err := channelService.ChallengeLatestState(r.Context(), service.ChallengeRequest{Asset: req.Asset}) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{"tx_hash": result.TxHash}) - } -} diff --git a/internal/httpapi/node.go b/internal/httpapi/node.go deleted file mode 100644 index bd4393f..0000000 --- a/internal/httpapi/node.go +++ /dev/null @@ -1,53 +0,0 @@ -package httpapi - -import ( - "net/http" - - "github.com/layer-3/nitrolite-go-example/internal/service" -) - -func nodeConfigHandler(nodeService *service.NodeService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - cfg, err := nodeService.GetConfig(r.Context()) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, encodeNodeConfig(cfg)) - } -} - -func nodeBlockchainsHandler(nodeService *service.NodeService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - blockchains, err := nodeService.GetBlockchains(r.Context()) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "blockchains": encodeBlockchains(blockchains), - }) - } -} - -func nodeAssetsHandler(nodeService *service.NodeService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - blockchainID, err := optionalUint64Query(r, "blockchain_id") - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - assets, err := nodeService.GetAssets(r.Context(), blockchainID) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "assets": encodeAssets(assets), - }) - } -} diff --git a/internal/httpapi/openapi.go b/internal/httpapi/openapi.go deleted file mode 100644 index b208fab..0000000 --- a/internal/httpapi/openapi.go +++ /dev/null @@ -1,574 +0,0 @@ -package httpapi - -import ( - "encoding/json" - "net/http" - "sort" - - "github.com/layer-3/nitrolite-go-example/internal/config" -) - -func openAPIHandler(cfg *config.Config) http.HandlerFunc { - spec := buildOpenAPISpec(cfg) - payload, err := json.Marshal(spec) - if err != nil { - panic(err) - } - - return func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - _, _ = w.Write(payload) - } -} - -func buildOpenAPISpec(cfg *config.Config) map[string]any { - exampleAsset, exampleChain := openAPIAssetAndChain(cfg.HomeBlockchains) - if exampleAsset == "" { - exampleAsset = "yusd" - } - if exampleChain == 0 { - exampleChain = 11155111 - } - - return map[string]any{ - "openapi": "3.1.0", - "info": map[string]any{ - "title": "Nitrolite Go Example API", - "version": "1.0.0", - "description": "App Session Micropayment Store reference API for the Nitrolite Go example. The public product surface is a content store at `/`, while `/reference` and `/advanced` remain hidden developer surfaces for direct route exploration.", - }, - "servers": []map[string]any{{"url": "/"}}, - "tags": []map[string]any{ - {"name": "Health / Wallet / Node"}, - {"name": "Store"}, - {"name": "Catalog"}, - {"name": "Content"}, - {"name": "Raw Channel"}, - {"name": "Raw Sessions"}, - {"name": "Raw Session Keys"}, - {"name": "Auth"}, - {"name": "Legacy"}, - }, - "components": map[string]any{ - "securitySchemes": map[string]any{ - "bearerAuth": map[string]any{ - "type": "http", - "scheme": "bearer", - "bearerFormat": "API key", - }, - "writeSessionCookie": map[string]any{ - "type": "apiKey", - "in": "cookie", - "name": writeSessionCookieName, - }, - }, - "schemas": map[string]any{ - "ErrorEnvelope": map[string]any{ - "type": "object", - "properties": map[string]any{ - "error": map[string]any{ - "type": "object", - "properties": map[string]any{ - "code": map[string]any{"type": "string"}, - "message": map[string]any{"type": "string"}, - }, - "required": []string{"code", "message"}, - }, - }, - "required": []string{"error"}, - }, - "UnlockRequest": map[string]any{ - "type": "object", - "properties": map[string]any{ - "api_key": map[string]any{"type": "string"}, - }, - "required": []string{"api_key"}, - }, - "UnlockStatus": map[string]any{ - "type": "object", - "properties": map[string]any{ - "unlocked": map[string]any{"type": "boolean"}, - "expires_at": map[string]any{"type": "string", "format": "date-time"}, - }, - }, - "GenericObject": genericObjectSchema(), - }, - }, - "paths": map[string]any{ - "/healthz": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Process health", "Current process and clearnode connectivity.", "", map[string]any{"status": "ok", "clearnode": "connected", "signer": "0xabc"}), - }, - "/readyz": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Readiness", "Readiness after SDK initialization and ping.", "", map[string]any{"status": "ready"}), - }, - "/api/v1/auth/status": map[string]any{ - "get": readOperation("Auth", "Write unlock status", "Returns whether writes are unlocked for the current browser session.", "UnlockStatus", map[string]any{"unlocked": false}), - }, - "/api/v1/auth/unlock": map[string]any{ - "post": writeAccessOperation("Auth", "Unlock writes", "Verifies the demo write key and sets a short-lived HttpOnly write-session cookie.", requestBody("UnlockRequest", map[string]any{"api_key": "paste-demo-key-here"}), "UnlockStatus", map[string]any{"unlocked": true}), - }, - "/api/v1/auth/lock": map[string]any{ - "post": writeAccessOperation("Auth", "Lock writes", "Clears the browser write-session cookie.", nil, "UnlockStatus", map[string]any{"unlocked": false}), - }, - "/api/v1/wallet": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Wallet", "Current backend signer address and configured home chains.", "", map[string]any{ - "address": "0x562679665e9fb0ed7a4251effe9672553e9a5406", - "homeBlockchains": map[string]any{exampleAsset: exampleChain}, - }), - }, - "/api/v1/node/config": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Node config", "Supported chains and node metadata.", "", map[string]any{ - "nodeAddress": "0xc76632d91d45ec88304ab2a983451d9edf908c0d", - "blockchains": []map[string]any{{"id": exampleChain, "name": "ethereum_sepolia"}}, - }), - }, - "/api/v1/node/blockchains": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Supported blockchains", "Lists chains exposed by the node.", "", map[string]any{ - "blockchains": []map[string]any{{"id": exampleChain, "name": "ethereum_sepolia"}}, - }), - }, - "/api/v1/node/assets": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Supported assets", "Lists supported assets and token addresses.", "", map[string]any{ - "assets": []map[string]any{{ - "name": "Yellow USD", - "symbol": exampleAsset, - "decimals": 6, - "suggestedBlockchainID": exampleChain, - }}, - }), - }, - "/api/v1/store/config": map[string]any{ - "get": readOperation("Store", "Store config", "Returns store metadata, supported assets, and the seeded catalog summary. The first request also ensures a browser-scoped store session cookie exists.", "", map[string]any{ - "browser_session_id": "browser_123", - "store": map[string]any{ - "store_name": cfg.StoreName, - "app_id": cfg.StoreAppID, - "default_asset": exampleAsset, - "supported_assets": []string{exampleAsset}, - "catalog": []map[string]any{{"id": "book-go-101", "title": "Go Systems Handbook"}}, - }, - }), - }, - "/api/v1/catalog": map[string]any{ - "get": readOperation("Catalog", "Catalog listing", "Lists the store catalog filtered to a selected asset.", "", map[string]any{ - "items": []map[string]any{{ - "id": "book-go-101", - "title": "Go Systems Handbook", - "type": "book", - "description": "A practical field guide to Go services.", - "prices": map[string]any{exampleAsset: "2.50"}, - }}, - }), - }, - "/api/v1/catalog/{id}": map[string]any{ - "get": readOperation("Catalog", "Catalog item", "Returns one catalog item for the requested asset.", "", map[string]any{ - "item": map[string]any{ - "id": "book-go-101", - "title": "Go Systems Handbook", - "type": "book", - "description": "A practical field guide to Go services.", - "prices": map[string]any{exampleAsset: "2.50"}, - }, - }), - }, - "/api/v1/store/session": map[string]any{ - "get": readOperation("Store", "Current store session", "Returns the browser-scoped store session summary for one asset. If no session exists yet, the status is `missing`.", "", map[string]any{ - "session": map[string]any{ - "asset": exampleAsset, - "status": "missing", - "available_balance": "5", - "user_allocation": "0", - "app_allocation": "0", - }, - }), - }, - "/api/v1/store/session/create": map[string]any{ - "post": map[string]any{ - "tags": []string{"Store"}, - "summary": "Create or load store session", - "description": "Creates one browser-scoped app session for the selected asset if it does not already exist, or returns the existing one.", - "requestBody": requestBody("", map[string]any{"asset": exampleAsset}), - "responses": standardResponses(http.StatusOK, "", map[string]any{ - "session": map[string]any{ - "asset": exampleAsset, - "app_session_id": "0xsession", - "status": "open", - "version": 1, - "user_allocation": "0", - "app_allocation": "0", - }, - }, true), - }, - }, - "/api/v1/app-session/submit-state": map[string]any{ - "post": map[string]any{ - "tags": []string{"Store"}, - "summary": "Submit store app-session state", - "description": "Single store mutation endpoint. The server inspects `session_data.action` and dispatches deposit, purchase, `user_withdraw`, or hidden `app_withdraw` logic. Purchase pricing is always revalidated against the server catalog.", - "requestBody": requestBody("", map[string]any{ - "session_id": "0xsession", - "asset": exampleAsset, - "session_data": "{\"action\":\"purchase\",\"item_id\":\"book-go-101\",\"price\":\"2.50\"}", - }), - "responses": standardResponses(http.StatusOK, "", map[string]any{ - "session": map[string]any{ - "asset": exampleAsset, - "app_session_id": "0xsession", - "status": "open", - "version": 2, - "user_allocation": "2.50", - "app_allocation": "2.50", - "session_data": "{\"action\":\"purchase\",\"item_id\":\"book-go-101\",\"price\":\"2.50\"}", - }, - }, true), - }, - }, - "/api/v1/purchases": map[string]any{ - "get": readOperation("Content", "Purchased items", "Lists purchased items for the current browser-scoped store identity and selected asset.", "", map[string]any{ - "purchases": []map[string]any{{ - "item_id": "book-go-101", - "asset": exampleAsset, - "app_session_id": "0xsession", - "version": 2, - }}, - }), - }, - "/api/v1/content/{id}": map[string]any{ - "get": readOperation("Content", "Purchased content", "Returns content only if the current browser session has already purchased the item for the selected asset.", "", map[string]any{ - "item": map[string]any{ - "id": "book-go-101", - "title": "Go Systems Handbook", - "type": "book", - "description": "A practical field guide to Go services.", - "prices": map[string]any{exampleAsset: "2.50"}, - "content": "Go Systems Handbook\\n\\nThis sample chapter walks through interfaces and runtime lifecycles.", - }, - }), - }, - "/api/v1/balance": map[string]any{ - "get": readOperation("Store", "Store balance summary", "Returns the available off-session balance plus the current user and app allocations for one asset.", "", map[string]any{ - "asset": exampleAsset, - "available_balance": "5", - "user_allocation": "2.50", - "app_allocation": "2.50", - "session_status": "open", - "session_id": "0xsession", - "version": 2, - }), - }, - "/api/v1/balances": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Balances", "Current off-chain balances for the backend signer.", "", map[string]any{ - "balances": []map[string]any{{"asset": exampleAsset, "balance": "2.5"}}, - }), - }, - "/api/v1/transactions": map[string]any{ - "get": readOperation("Health / Wallet / Node", "Transactions", "Recent transaction history for the signer.", "", map[string]any{ - "transactions": []map[string]any{{"asset": exampleAsset, "type": "transfer", "amount": "1"}}, - }), - }, - "/api/v1/channel": map[string]any{ - "get": readOperation("Raw Channel", "Home channel", "Returns the home channel summary for an asset.", "", map[string]any{ - "channel": map[string]any{"asset": exampleAsset, "stateVersion": 4, "status": "open"}, - }), - }, - "/api/v1/channel/state": map[string]any{ - "get": readOperation("Raw Channel", "Latest state", "Returns the latest state for an asset. Use `only_signed=true` for the latest co-signed state.", "", map[string]any{ - "state": map[string]any{"asset": exampleAsset, "version": 4}, - }), - }, - "/api/v1/approve": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Approve token", "Approves the locking contract to spend the selected ERC-20.", requestBody("", map[string]any{ - "blockchain_id": exampleChain, - "asset": exampleAsset, - "amount": "1", - }), "", map[string]any{"tx_hash": "0xapprove"}), - }, - "/api/v1/deposit": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Deposit", "Builds and submits the next deposit state.", requestBody("", map[string]any{ - "blockchain_id": exampleChain, - "asset": exampleAsset, - "amount": "1", - }), "", map[string]any{ - "ready_for_checkpoint": true, - "state": map[string]any{"version": 4, "asset": exampleAsset}, - }), - }, - "/api/v1/withdraw": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Withdraw", "Builds and submits the next withdrawal state.", requestBody("", map[string]any{ - "blockchain_id": exampleChain, - "asset": exampleAsset, - "amount": "0.5", - }), "", map[string]any{ - "ready_for_checkpoint": true, - "state": map[string]any{"version": 5, "asset": exampleAsset}, - }), - }, - "/api/v1/transfer": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Transfer", "Builds and submits an off-chain transfer state.", requestBody("", map[string]any{ - "recipient": "0x1111111111111111111111111111111111111111", - "asset": exampleAsset, - "amount": "0.25", - }), "", map[string]any{ - "state": map[string]any{"version": 6, "asset": exampleAsset}, - }), - }, - "/api/v1/checkpoint": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Checkpoint", "Submits the latest signed state on-chain.", requestBody("", map[string]any{ - "asset": exampleAsset, - }), "", map[string]any{"tx_hash": "0xcheckpoint"}), - }, - "/api/v1/challenge": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Challenge latest state", "Challenges the latest signed state for the selected asset.", requestBody("", map[string]any{"asset": exampleAsset}), "", map[string]any{"tx_hash": "0xchallenge"}), - }, - "/api/v1/channel/close": map[string]any{ - "post": writeAccessOperation("Raw Channel", "Close channel", "Builds the finalize state for the selected asset.", requestBody("", map[string]any{"asset": exampleAsset}), "", map[string]any{"state": map[string]any{"version": 7, "asset": exampleAsset}}), - }, - "/api/v1/apps": map[string]any{ - "get": readOperation("Raw Sessions", "Apps", "Lists registered apps.", "", map[string]any{"apps": []map[string]any{{"app_id": cfg.StoreAppID, "creation_approval_not_required": true}}}), - }, - "/api/v1/apps/register": map[string]any{ - "post": writeAccessOperation("Raw Sessions", "Register app", "Registers a new app definition.", requestBody("", map[string]any{ - "app_id": "demo-app", - "metadata": "{}", - "creation_approval_not_required": true, - }), "", map[string]any{"status": "registered"}), - }, - "/api/v1/sessions": map[string]any{ - "get": readOperation("Raw Sessions", "Sessions", "Lists sessions for the signer by default.", "", map[string]any{ - "sessions": []map[string]any{{"app_session_id": "0xsession", "application_id": cfg.StoreAppID, "status": "open", "version": 4}}, - }), - "post": writeAccessOperation("Raw Sessions", "Create session", "Creates a single-signer app session for the backend signer.", requestBody("", map[string]any{ - "application_id": cfg.StoreAppID, - "initial_allocations": []map[string]any{ - {"asset": exampleAsset, "amount": "0.5"}, - }, - "session_data": "{}", - }), "", map[string]any{"session_id": "0xsession", "status": "open", "version": 2}), - }, - "/api/v1/sessions/{session_id}": map[string]any{ - "get": readOperation("Raw Sessions", "Session detail", "Returns the session and app definition for a specific session.", "", map[string]any{ - "session": map[string]any{"app_session_id": "0xsession", "version": 4}, - "app_definition": map[string]any{"application_id": cfg.StoreAppID}, - }), - }, - "/api/v1/sessions/{session_id}/deposit": map[string]any{ - "post": writeAccessOperation("Raw Sessions", "Session deposit", "Deposits into an open app session.", requestBody("", map[string]any{ - "asset": exampleAsset, - "amount": "0.25", - }), "", map[string]any{"session_id": "0xsession", "version": 3, "node_sig": "0xnodesig"}), - }, - "/api/v1/sessions/{session_id}/state": map[string]any{ - "post": writeAccessOperation("Raw Sessions", "Operate session", "Submits an operate update for the selected session.", requestBody("", map[string]any{ - "allocations": []map[string]any{{"participant": "0xabc", "asset": exampleAsset, "amount": "0.5"}}, - "session_data": "{\"turn\":1}", - }), "", map[string]any{"session_id": "0xsession", "version": 4}), - }, - "/api/v1/sessions/{session_id}/close": map[string]any{ - "post": writeAccessOperation("Raw Sessions", "Close session", "Closes the selected session using its current allocations.", requestBody("", map[string]any{}), "", map[string]any{"session_id": "0xsession", "status": "closed"}), - }, - "/api/v1/session-keys/channel": map[string]any{ - "get": readOperation("Raw Session Keys", "Channel session keys", "Lists active channel session key states.", "", map[string]any{"states": []any{}}), - "post": writeAccessOperation("Raw Session Keys", "Register channel session key", "Registers a channel session key state.", requestBody("", map[string]any{ - "session_key": "0x1111111111111111111111111111111111111111", - "assets": []string{exampleAsset}, - "expires_at": "2030-01-01T00:00:00Z", - }), "", map[string]any{"state": map[string]any{"session_key": "0x1111111111111111111111111111111111111111", "version": 1}}), - }, - "/api/v1/session-keys/app": map[string]any{ - "get": readOperation("Raw Session Keys", "App session keys", "Lists active app session key states.", "", map[string]any{"states": []any{}}), - "post": writeAccessOperation("Raw Session Keys", "Register app session key", "Registers an app session key state.", requestBody("", map[string]any{ - "session_key": "0x1111111111111111111111111111111111111111", - "application_ids": []string{cfg.StoreAppID}, - "app_session_ids": []string{}, - "expires_at": "2030-01-01T00:00:00Z", - }), "", map[string]any{"state": map[string]any{"session_key": "0x1111111111111111111111111111111111111111", "version": 1}}), - }, - "/api/v1/demo/overview": map[string]any{ - "get": readOperation("Legacy", "Legacy demo overview", "Legacy guided-demo aggregate kept for compatibility with the earlier protocol-first UI.", "", map[string]any{ - "selected_asset": exampleAsset, - "channel_guidance": map[string]any{ - "next_action": "approve_and_deposit", - "headline": "Fund the home channel", - }, - }), - }, - }, - } -} - -func readOperation(tag string, summary string, description string, schemaName string, example any) map[string]any { - return map[string]any{ - "tags": []string{tag}, - "summary": summary, - "description": description, - "responses": standardResponses(http.StatusOK, schemaName, example, false), - } -} - -func writeAccessOperation(tag string, summary string, description string, request any, schemaName string, example any) map[string]any { - op := map[string]any{ - "tags": []string{tag}, - "summary": summary, - "description": description, - "responses": standardResponses(http.StatusOK, schemaName, example, true), - "security": []map[string]any{ - {"writeSessionCookie": []string{}}, - {"bearerAuth": []string{}}, - }, - } - if request != nil { - op["requestBody"] = request - } - return op -} - -func operatorLeaseOperation(tag string, summary string, description string, request any, schemaName string, example any, statusCode int) map[string]any { - op := map[string]any{ - "tags": []string{tag}, - "summary": summary, - "description": description, - "responses": standardResponses(statusCode, schemaName, example, true), - "security": []map[string]any{ - {"writeSessionCookie": []string{}}, - }, - } - if request != nil { - op["requestBody"] = request - } - return op -} - -func asyncOperatorOperation(tag string, summary string, description string, requestExample any, responseExample any) map[string]any { - return map[string]any{ - "tags": []string{tag}, - "summary": summary, - "description": description, - "requestBody": requestBody("", requestExample), - "security": []map[string]any{ - {"writeSessionCookie": []string{}}, - }, - "responses": standardResponses(http.StatusAccepted, "AsyncOperationAccepted", responseExample, true), - } -} - -func asyncPublicOperation(tag string, summary string, description string, requestExample any, responseExample any) map[string]any { - return map[string]any{ - "tags": []string{tag}, - "summary": summary, - "description": description, - "requestBody": requestBody("", requestExample), - "responses": standardResponses(http.StatusAccepted, "AsyncOperationAccepted", responseExample, true), - } -} - -func leaseOwnershipOperation(tag string, summary string, description string, request any, schemaName string, example any) map[string]any { - return map[string]any{ - "tags": []string{tag}, - "summary": summary, - "description": description, - "requestBody": request, - "security": []map[string]any{ - {"writeSessionCookie": []string{}}, - }, - "responses": standardResponses(http.StatusOK, schemaName, example, true), - } -} - -func standardResponses(statusCode int, schemaName string, example any, allowWriteErrors bool) map[string]any { - statusText := "ok" - switch statusCode { - case http.StatusCreated: - statusText = "created" - case http.StatusAccepted: - statusText = "accepted" - } - - out := map[string]any{ - statusCodeKey(statusCode): map[string]any{ - "description": statusText, - "content": map[string]any{ - "application/json": map[string]any{ - "schema": responseSchema(schemaName), - "example": example, - }, - }, - }, - "400": errorResponse("invalid request"), - "422": errorResponse("operation failed"), - "503": errorResponse("service unavailable"), - } - if allowWriteErrors { - out["409"] = errorResponse("conflict") - out["401"] = errorResponse("missing or invalid api key") - } - return out -} - -func statusCodeKey(statusCode int) string { - switch statusCode { - case http.StatusCreated: - return "201" - case http.StatusAccepted: - return "202" - default: - return "200" - } -} - -func errorResponse(description string) map[string]any { - return map[string]any{ - "description": description, - "content": map[string]any{ - "application/json": map[string]any{ - "schema": schemaRef("ErrorEnvelope"), - }, - }, - } -} - -func requestBody(schemaName string, example any) map[string]any { - schema := genericObjectSchema() - if schemaName != "" { - schema = schemaRef(schemaName) - } - return map[string]any{ - "required": true, - "content": map[string]any{ - "application/json": map[string]any{ - "schema": schema, - "example": example, - }, - }, - } -} - -func responseSchema(schemaName string) any { - if schemaName == "" { - return genericObjectSchema() - } - return schemaRef(schemaName) -} - -func genericObjectSchema() map[string]any { - return map[string]any{ - "type": "object", - "additionalProperties": true, - } -} - -func schemaRef(name string) map[string]any { - return map[string]any{"$ref": "#/components/schemas/" + name} -} - -func openAPIAssetAndChain(homeBlockchains map[string]uint64) (string, uint64) { - assets := make([]string, 0, len(homeBlockchains)) - for asset := range homeBlockchains { - assets = append(assets, asset) - } - sort.Strings(assets) - if len(assets) == 0 { - return "", 0 - } - return assets[0], homeBlockchains[assets[0]] -} diff --git a/internal/httpapi/query.go b/internal/httpapi/query.go deleted file mode 100644 index 78f0ae9..0000000 --- a/internal/httpapi/query.go +++ /dev/null @@ -1,60 +0,0 @@ -package httpapi - -import ( - "fmt" - "net/http" - "strconv" - "strings" -) - -func requireQuery(r *http.Request, key string) (string, error) { - value := strings.TrimSpace(r.URL.Query().Get(key)) - if value == "" { - return "", fmt.Errorf("missing %s", key) - } - return value, nil -} - -func optionalQuery(r *http.Request, key string) *string { - value := strings.TrimSpace(r.URL.Query().Get(key)) - if value == "" { - return nil - } - return &value -} - -func optionalUint64Query(r *http.Request, key string) (*uint64, error) { - raw := strings.TrimSpace(r.URL.Query().Get(key)) - if raw == "" { - return nil, nil - } - value, err := strconv.ParseUint(raw, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid %s", key) - } - return &value, nil -} - -func optionalBoolQuery(r *http.Request, key string, fallback bool) (bool, error) { - raw := strings.TrimSpace(r.URL.Query().Get(key)) - if raw == "" { - return fallback, nil - } - value, err := strconv.ParseBool(raw) - if err != nil { - return false, fmt.Errorf("invalid %s", key) - } - return value, nil -} - -func positiveUint32Query(r *http.Request, key string, fallback uint32) (uint32, error) { - raw := strings.TrimSpace(r.URL.Query().Get(key)) - if raw == "" { - return fallback, nil - } - value, err := strconv.ParseUint(raw, 10, 32) - if err != nil || value == 0 { - return 0, fmt.Errorf("invalid %s", key) - } - return uint32(value), nil -} diff --git a/internal/httpapi/response.go b/internal/httpapi/response.go index 1437ba8..f925a1e 100644 --- a/internal/httpapi/response.go +++ b/internal/httpapi/response.go @@ -5,7 +5,7 @@ import ( "errors" "net/http" - "github.com/layer-3/nitrolite-go-example/internal/service" + "github.com/layer-3/nitrolite-store-example/internal/service" ) type errorEnvelope struct { @@ -35,24 +35,30 @@ func writeError(w http.ResponseWriter, status int, code string, message string) func writeServiceError(w http.ResponseWriter, err error) { var validationErr service.ValidationError if errors.As(err, &validationErr) { - writeError(w, http.StatusBadRequest, "invalid_request", validationErr.Error()) + writeError(w, http.StatusBadRequest, validationErr.Code(), validationErr.Error()) return } var notFoundErr service.NotFoundError if errors.As(err, ¬FoundErr) { - writeError(w, http.StatusUnprocessableEntity, "not_found", notFoundErr.Error()) + writeError(w, http.StatusUnprocessableEntity, notFoundErr.Code(), notFoundErr.Error()) return } var conflictErr service.ConflictError if errors.As(err, &conflictErr) { - writeError(w, http.StatusConflict, "conflict", conflictErr.Error()) + writeError(w, http.StatusConflict, conflictErr.Code(), conflictErr.Error()) + return + } + + var upstreamErr service.UpstreamError + if errors.As(err, &upstreamErr) { + writeError(w, http.StatusBadGateway, "nitronode_operation_failed", upstreamErr.Error()) return } if errors.Is(err, service.ErrUnavailable) { - writeError(w, http.StatusServiceUnavailable, "service_unavailable", "clearnode not reachable") + writeError(w, http.StatusServiceUnavailable, "nitronode_unavailable", service.ErrUnavailable.Error()) return } writeError(w, http.StatusUnprocessableEntity, "sdk_operation_failed", err.Error()) diff --git a/internal/httpapi/routes_test.go b/internal/httpapi/routes_test.go index f912b61..b8fea1a 100644 --- a/internal/httpapi/routes_test.go +++ b/internal/httpapi/routes_test.go @@ -3,28 +3,43 @@ package httpapi import ( "context" "encoding/json" + "errors" "log/slog" "net/http" "net/http/httptest" "path/filepath" - "strings" + "reflect" "testing" - "github.com/layer-3/nitrolite-go-example/internal/config" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" - "github.com/layer-3/nitrolite/pkg/app" + "github.com/layer-3/nitrolite-store-example/internal/config" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" + "github.com/layer-3/nitrolite-store-example/internal/service" + "github.com/layer-3/nitrolite-store-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/store" + "github.com/layer-3/nitrolite-store-example/internal/testsupport" "github.com/layer-3/nitrolite/pkg/core" - "github.com/layer-3/nitrolite/pkg/sign" - sdk "github.com/layer-3/nitrolite/sdk/go" "github.com/shopspring/decimal" ) const httpAPITestPrivateKey = "0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318" -func TestStoreBootstrapRequiresWalletConnection(t *testing.T) { +func fundedHTTPState(wallet string, asset string, balance string) *core.State { + homeChannelID := "0xhome" + return &core.State{ + ID: "0xstate", + Asset: asset, + UserWallet: wallet, + HomeChannelID: &homeChannelID, + HomeLedger: core.Ledger{ + UserBalance: decimal.RequireFromString(balance), + UserNetFlow: decimal.RequireFromString(balance), + NodeBalance: decimal.Zero, + NodeNetFlow: decimal.Zero, + }, + } +} + +func TestStoreBootstrapRequiresWalletAddress(t *testing.T) { t.Parallel() handler := newTestHandler(t, &testsupport.FakeClient{}) @@ -33,38 +48,31 @@ func TestStoreBootstrapRequiresWalletConnection(t *testing.T) { handler.ServeHTTP(rec, req) - if rec.Code != http.StatusUnauthorized { - t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusUnauthorized, rec.Body.String()) + if rec.Code != http.StatusBadRequest { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusBadRequest, rec.Body.String()) } var payload errorEnvelope if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { t.Fatalf("json.Unmarshal() error = %v", err) } - if payload.Error.Code != "unauthorized" { - t.Fatalf("error code = %q, want unauthorized", payload.Error.Code) + if payload.Error.Code != "invalid_request" { + t.Fatalf("error code = %q, want invalid_request", payload.Error.Code) } } -func TestStoreConnectVerifyAndBootstrap(t *testing.T) { +func TestStoreBootstrapWithWalletAddress(t *testing.T) { t.Parallel() + walletAddress := "0x1111111111111111111111111111111111111111" handler := newTestHandler(t, &testsupport.FakeClient{ - GetBalancesFunc: func(context.Context, string) ([]core.BalanceEntry, error) { - return []core.BalanceEntry{ - {Asset: "yusd", Balance: decimal.RequireFromString("7")}, - {Asset: "yellow", Balance: decimal.RequireFromString("3")}, - }, nil - }, - GetAppSessionsFunc: func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { - return nil, core.PaginationMetadata{}, nil + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + balances := map[string]string{"yusd": "7", "yellow": "3"} + return fundedHTTPState(wallet, asset, balances[asset]), nil }, }) - userSigner := mustUserSigner(t) - authCookie := connectWallet(t, handler, userSigner) - req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yusd", nil) - req.AddCookie(authCookie) + req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yusd&wallet_address="+walletAddress, nil) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) @@ -74,15 +82,17 @@ func TestStoreConnectVerifyAndBootstrap(t *testing.T) { } var payload struct { - StoreName string `json:"store_name"` - AppID string `json:"app_id"` - AppSigner string `json:"app_signer"` - WalletAddress string `json:"wallet_address"` - SelectedAsset string `json:"selected_asset"` - DefaultAsset string `json:"default_asset"` + WalletAddress string `json:"wallet_address"` + SelectedAsset string `json:"selected_asset"` SupportedAssets []string `json:"supported_assets"` - AvailableBalance string `json:"available_balance"` - Catalog []struct { + AvailableBalance string `json:"available_balance"` + ChannelReadiness struct { + Status string `json:"status"` + HomeBlockchainID uint64 `json:"home_blockchain_id"` + BootstrapAmount string `json:"bootstrap_amount"` + RequiresChannelCreation bool `json:"requires_channel_creation"` + } `json:"channel_readiness"` + Catalog []struct { ID string `json:"id"` } `json:"catalog"` Session struct { @@ -95,15 +105,30 @@ func TestStoreConnectVerifyAndBootstrap(t *testing.T) { t.Fatalf("json.Unmarshal() error = %v", err) } - if payload.WalletAddress != userSigner.Address() { - t.Fatalf("wallet_address = %q, want %q", payload.WalletAddress, userSigner.Address()) + if payload.WalletAddress != walletAddress { + t.Fatalf("wallet_address = %q, want %q", payload.WalletAddress, walletAddress) } if payload.SelectedAsset != "yusd" { t.Fatalf("selected_asset = %q, want yusd", payload.SelectedAsset) } + if !reflect.DeepEqual(payload.SupportedAssets, []string{"yusd", "yellow"}) { + t.Fatalf("supported_assets = %#v, want yusd/yellow", payload.SupportedAssets) + } if payload.AvailableBalance != "7" { t.Fatalf("available_balance = %q, want 7", payload.AvailableBalance) } + if payload.ChannelReadiness.Status != "ready" { + t.Fatalf("channel_readiness.status = %q, want ready", payload.ChannelReadiness.Status) + } + if payload.ChannelReadiness.HomeBlockchainID != 11155111 { + t.Fatalf("channel_readiness.home_blockchain_id = %d, want 11155111", payload.ChannelReadiness.HomeBlockchainID) + } + if payload.ChannelReadiness.BootstrapAmount != "10" { + t.Fatalf("channel_readiness.bootstrap_amount = %q, want 10", payload.ChannelReadiness.BootstrapAmount) + } + if payload.ChannelReadiness.RequiresChannelCreation { + t.Fatal("channel_readiness.requires_channel_creation = true, want false") + } if payload.Session.Status != "missing" { t.Fatalf("session.status = %q, want missing", payload.Session.Status) } @@ -113,72 +138,116 @@ func TestStoreConnectVerifyAndBootstrap(t *testing.T) { if len(payload.Catalog) == 0 { t.Fatal("expected seeded catalog entries") } - if len(payload.SupportedAssets) == 0 { - t.Fatal("expected supported_assets") - } } -func TestStoreConnectVerifyRejectsWrongSignature(t *testing.T) { +func TestStoreBootstrapReportsReceivedFundsNeedChannelCreation(t *testing.T) { t.Parallel() - handler := newTestHandler(t, &testsupport.FakeClient{}) - userSigner := mustUserSigner(t) - challenge := requestChallenge(t, handler, userSigner.Address()) - wrongSigner, err := signing.NewStoreAppSigner("", httpAPITestPrivateKey) - if err != nil { - t.Fatalf("NewStoreAppSigner() error = %v", err) - } + walletAddress := "0x1111111111111111111111111111111111111111" + handler := newTestHandler(t, &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, signed bool) (*core.State, error) { + if signed { + return nil, errors.New("signed state not found") + } + state := fundedHTTPState(wallet, asset, "5") + state.HomeChannelID = nil + return state, nil + }, + }) + + req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yusd&wallet_address="+walletAddress, nil) + rec := httptest.NewRecorder() + + handler.ServeHTTP(rec, req) - verifyReq := httptest.NewRequest(http.MethodPost, "/api/store/connect/verify", strings.NewReader(mustMarshalJSON(t, map[string]string{ - "challenge_id": challenge.ChallengeID, - "wallet_address": userSigner.Address(), - "signature": signChallengeMessage(t, wrongSigner, challenge.Message), - }))) - verifyRec := httptest.NewRecorder() - handler.ServeHTTP(verifyRec, verifyReq) + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusOK, rec.Body.String()) + } - if verifyRec.Code != http.StatusUnauthorized { - t.Fatalf("status = %d, want %d body=%s", verifyRec.Code, http.StatusUnauthorized, verifyRec.Body.String()) + var payload struct { + AvailableBalance string `json:"available_balance"` + ChannelReadiness struct { + Status string `json:"status"` + PendingBalance string `json:"pending_balance"` + RequiresChannelCreation bool `json:"requires_channel_creation"` + } `json:"channel_readiness"` + } + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("json.Unmarshal() error = %v", err) + } + if payload.ChannelReadiness.Status != "ack_required" { + t.Fatalf("channel_readiness.status = %q, want ack_required", payload.ChannelReadiness.Status) + } + if !payload.ChannelReadiness.RequiresChannelCreation { + t.Fatal("channel_readiness.requires_channel_creation = false, want true") + } + if payload.AvailableBalance != "0" { + t.Fatalf("available_balance = %q, want 0", payload.AvailableBalance) + } + if payload.ChannelReadiness.PendingBalance != "5" { + t.Fatalf("channel_readiness.pending_balance = %q, want 5", payload.ChannelReadiness.PendingBalance) } } -func TestStoreContentRequiresOwnership(t *testing.T) { +func TestStoreBootstrapWithYellowAsset(t *testing.T) { t.Parallel() + walletAddress := "0x1111111111111111111111111111111111111111" handler := newTestHandler(t, &testsupport.FakeClient{ - GetBalancesFunc: func(context.Context, string) ([]core.BalanceEntry, error) { - return []core.BalanceEntry{{Asset: "yusd", Balance: decimal.RequireFromString("7")}}, nil + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + balances := map[string]string{"yusd": "7", "yellow": "3"} + return fundedHTTPState(wallet, asset, balances[asset]), nil }, }) - authCookie := connectWallet(t, handler, mustUserSigner(t)) - req := httptest.NewRequest(http.MethodGet, "/api/store/content/article-micropayments?asset=yusd", nil) - req.AddCookie(authCookie) + req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yellow&wallet_address="+walletAddress, nil) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) - if rec.Code != http.StatusConflict { - t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusConflict, rec.Body.String()) + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusOK, rec.Body.String()) + } + + var payload struct { + SelectedAsset string `json:"selected_asset"` + AvailableBalance string `json:"available_balance"` + Catalog []struct { + ID string `json:"id"` + Prices map[string]string `json:"prices"` + } `json:"catalog"` + } + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("json.Unmarshal() error = %v", err) + } + if payload.SelectedAsset != "yellow" { + t.Fatalf("selected_asset = %q, want yellow", payload.SelectedAsset) + } + if payload.AvailableBalance != "3" { + t.Fatalf("available_balance = %q, want 3", payload.AvailableBalance) + } + if len(payload.Catalog) == 0 || payload.Catalog[0].Prices["yellow"] != "1.35" { + t.Fatalf("unexpected yellow catalog = %#v", payload.Catalog) } } -func TestStoreBootstrapReturnsServiceUnavailableWhenDisconnected(t *testing.T) { +func TestStoreContentSignedPostDisabled(t *testing.T) { t.Parallel() - cfg := &config.Config{ - Port: "8080", - LogLevel: "info", - ClearnodeWSURL: "wss://example.invalid", - DemoPrivateKey: httpAPITestPrivateKey, - ConsoleAPIKey: "12345678901234567890123456789012", - BlockchainRPCURLs: map[string]string{"11155111": "https://example.invalid"}, - HomeBlockchains: map[string]uint64{"yellow": 11155111, "yusd": 11155111}, - SQLitePath: filepath.Join(t.TempDir(), "test.db"), - StoreName: "Nitrolite App Session Store", - StoreAppID: "store", - StoreAppPrivateKey: "", + handler := newTestHandler(t, &testsupport.FakeClient{}) + + req := httptest.NewRequest(http.MethodPost, "/api/store/content/1/open", nil) + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, req) + + if rec.Code != http.StatusMethodNotAllowed { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusMethodNotAllowed, rec.Body.String()) } - userSigner := mustUserSigner(t) +} + +func TestStoreBootstrapReportsUnavailableWhenDisconnected(t *testing.T) { + t.Parallel() + + cfg := testConfig(t) appSigner, err := signing.NewStoreAppSigner("", httpAPITestPrivateKey) if err != nil { t.Fatalf("NewStoreAppSigner() error = %v", err) @@ -195,168 +264,150 @@ func TestStoreBootstrapReturnsServiceUnavailableWhenDisconnected(t *testing.T) { } t.Cleanup(func() { _ = appStore.Close() }) - handler, err := NewHandler(cfg, manager, userSigner, appSigner, appStore, slog.Default()) + handler, err := NewHandler(cfg, manager, appSigner, appSigner, appStore, slog.Default()) if err != nil { t.Fatalf("NewHandler() error = %v", err) } - authCookie := connectWallet(t, handler, userSigner) - req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yusd", nil) - req.AddCookie(authCookie) + req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yusd&wallet_address=0x1111111111111111111111111111111111111111", nil) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) - if rec.Code != http.StatusServiceUnavailable { - t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusServiceUnavailable, rec.Body.String()) + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusOK, rec.Body.String()) } -} - -type testHarness struct { - handler http.Handler - store *store.Store - userSigner signing.Signer - appSigner signing.Signer -} - -func newTestHarness(t *testing.T, client *testsupport.FakeClient) testHarness { - t.Helper() - cfg := &config.Config{ - Port: "8080", - LogLevel: "info", - ClearnodeWSURL: "wss://example.invalid", - DemoPrivateKey: httpAPITestPrivateKey, - ConsoleAPIKey: "12345678901234567890123456789012", - BlockchainRPCURLs: map[string]string{"11155111": "https://example.invalid"}, - HomeBlockchains: map[string]uint64{"yellow": 11155111, "yusd": 11155111}, - SQLitePath: filepath.Join(t.TempDir(), "test.db"), - StoreName: "Nitrolite App Session Store", - StoreAppID: "store", - StoreAppPrivateKey: "", + var payload struct { + AvailableBalance string `json:"available_balance"` + ChannelReadiness struct { + Status string `json:"status"` + Message string `json:"message"` + } `json:"channel_readiness"` } - userSigner := mustUserSigner(t) - appSigner, err := signing.NewStoreAppSigner("", httpAPITestPrivateKey) - if err != nil { - t.Fatalf("NewStoreAppSigner() error = %v", err) + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("json.Unmarshal() error = %v", err) } - - manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ - Connected: true, - Ready: true, - SignerAddress: appSigner.Address(), - }, slog.Default()) - appStore, err := store.New(cfg.SQLitePath) - if err != nil { - t.Fatalf("store.New() error = %v", err) + if payload.AvailableBalance != "0" { + t.Fatalf("available_balance = %q, want 0", payload.AvailableBalance) } - t.Cleanup(func() { _ = appStore.Close() }) - - handler, err := NewHandler(cfg, manager, userSigner, appSigner, appStore, slog.Default()) - if err != nil { - t.Fatalf("NewHandler() error = %v", err) + if payload.ChannelReadiness.Status != "unavailable" { + t.Fatalf("channel_readiness.status = %q, want unavailable", payload.ChannelReadiness.Status) } - - return testHarness{handler: handler, store: appStore, userSigner: userSigner, appSigner: appSigner} -} - -func newTestHandler(t *testing.T, client *testsupport.FakeClient) http.Handler { - t.Helper() - return newTestHarness(t, client).handler } -type storeChallengeResponse struct { - ChallengeID string `json:"challenge_id"` - Message string `json:"message"` -} - -func requestChallenge(t *testing.T, handler http.Handler, walletAddress string) storeChallengeResponse { - t.Helper() +func TestWriteServiceErrorUnavailableUsesNitronodeCode(t *testing.T) { + t.Parallel() - req := httptest.NewRequest(http.MethodPost, "/api/store/connect/challenge", strings.NewReader(mustMarshalJSON(t, map[string]string{ - "wallet_address": walletAddress, - }))) rec := httptest.NewRecorder() - handler.ServeHTTP(rec, req) - if rec.Code != http.StatusOK { - t.Fatalf("challenge status = %d, want %d body=%s", rec.Code, http.StatusOK, rec.Body.String()) + writeServiceError(rec, service.ErrUnavailable) + + if rec.Code != http.StatusServiceUnavailable { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusServiceUnavailable, rec.Body.String()) } - var payload storeChallengeResponse + var payload errorEnvelope if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { t.Fatalf("json.Unmarshal() error = %v", err) } - if payload.ChallengeID == "" || payload.Message == "" { - t.Fatalf("unexpected challenge payload = %#v", payload) + if payload.Error.Code != "nitronode_unavailable" { + t.Fatalf("error code = %q, want nitronode_unavailable", payload.Error.Code) + } + if payload.Error.Message != "nitronode not reachable" { + t.Fatalf("error message = %q, want nitronode not reachable", payload.Error.Message) } - return payload } -func connectWallet(t *testing.T, handler http.Handler, signer signing.Signer) *http.Cookie { - t.Helper() +func TestWriteServiceErrorUpstreamUsesNitronodeCode(t *testing.T) { + t.Parallel() - challenge := requestChallenge(t, handler, signer.Address()) - req := httptest.NewRequest(http.MethodPost, "/api/store/connect/verify", strings.NewReader(mustMarshalJSON(t, map[string]string{ - "challenge_id": challenge.ChallengeID, - "wallet_address": signer.Address(), - "signature": signChallengeMessage(t, signer, challenge.Message), - }))) rec := httptest.NewRecorder() - handler.ServeHTTP(rec, req) - if rec.Code != http.StatusOK { - t.Fatalf("verify status = %d, want %d body=%s", rec.Code, http.StatusOK, rec.Body.String()) + writeServiceError(rec, upstreamMappingError{}) + + if rec.Code != http.StatusBadGateway { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusBadGateway, rec.Body.String()) } - cookie := storeAuthCookie(t, rec.Result().Cookies()) - if cookie.Value == "" { - t.Fatal("expected auth cookie value") + var payload errorEnvelope + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("json.Unmarshal() error = %v", err) + } + if payload.Error.Code != "nitronode_operation_failed" { + t.Fatalf("error code = %q, want nitronode_operation_failed", payload.Error.Code) } - return cookie } -func mustUserSigner(t *testing.T) signing.Signer { - t.Helper() +type upstreamMappingError struct{} - signer, err := signing.NewEnvSigner(httpAPITestPrivateKey) - if err != nil { - t.Fatalf("NewEnvSigner() error = %v", err) +func (upstreamMappingError) Error() string { + return "upstream mapping test" +} + +func (upstreamMappingError) As(target any) bool { + upstreamErr, ok := target.(*service.UpstreamError) + if !ok { + return false } - return signer + *upstreamErr = service.UpstreamError{} + return true } -func signChallengeMessage(t *testing.T, signer signing.Signer, message string) string { +func newTestHandler(t *testing.T, client *testsupport.FakeClient) http.Handler { t.Helper() + return newTestHarness(t, client).handler +} - msgSigner, err := sign.NewEthereumMsgSignerFromRaw(signer.TxSigner()) +type testHarness struct { + handler http.Handler + store *store.Store + appSigner signing.Signer +} + +func newTestHarness(t *testing.T, client *testsupport.FakeClient) testHarness { + t.Helper() + + cfg := testConfig(t) + appSigner, err := signing.NewStoreAppSigner("", httpAPITestPrivateKey) if err != nil { - t.Fatalf("NewEthereumMsgSignerFromRaw() error = %v", err) + t.Fatalf("NewStoreAppSigner() error = %v", err) } - signature, err := msgSigner.Sign([]byte(message)) + + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(cfg.SQLitePath) if err != nil { - t.Fatalf("Sign() error = %v", err) + t.Fatalf("store.New() error = %v", err) } - return signature.String() -} - -func mustMarshalJSON(t *testing.T, payload any) string { - t.Helper() + t.Cleanup(func() { _ = appStore.Close() }) - body, err := json.Marshal(payload) + handler, err := NewHandler(cfg, manager, appSigner, appSigner, appStore, slog.Default()) if err != nil { - t.Fatalf("json.Marshal() error = %v", err) + t.Fatalf("NewHandler() error = %v", err) } - return string(body) + + return testHarness{handler: handler, store: appStore, appSigner: appSigner} } -func storeAuthCookie(t *testing.T, cookies []*http.Cookie) *http.Cookie { +func testConfig(t *testing.T) *config.Config { t.Helper() - - for _, cookie := range cookies { - if cookie.Name == storeAuthSessionCookieName { - return cookie - } + return &config.Config{ + Port: "8080", + LogLevel: "info", + ClearnodeWSURL: "wss://example.invalid", + DemoPrivateKey: httpAPITestPrivateKey, + BlockchainRPCURLs: map[string]string{"11155111": "https://example.invalid"}, + HomeBlockchains: map[string]uint64{"yellow": 11155111, "yusd": 11155111}, + SQLitePath: filepath.Join(t.TempDir(), "test.db"), + StoreName: "Nitrolite App Session Store", + StoreAppID: "store", + StoreAppPrivateKey: "", + StoreChannelBootstrapAmounts: map[string]string{ + "yellow": "10", + "yusd": "10", + }, } - t.Fatal("expected store auth cookie") - return nil } diff --git a/internal/httpapi/server.go b/internal/httpapi/server.go index d25957c..92a2501 100644 --- a/internal/httpapi/server.go +++ b/internal/httpapi/server.go @@ -4,12 +4,12 @@ import ( "log/slog" "net/http" - "github.com/layer-3/nitrolite-go-example/internal/config" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/service" - "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/layer-3/nitrolite-go-example/internal/webui" + "github.com/layer-3/nitrolite-store-example/internal/config" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" + "github.com/layer-3/nitrolite-store-example/internal/service" + "github.com/layer-3/nitrolite-store-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/store" + "github.com/layer-3/nitrolite-store-example/internal/webui" ) // NewHandler wires the v1 shopper surface for the refreshed store app. @@ -19,17 +19,25 @@ func NewHandler(cfg *config.Config, manager *nitrolite.Manager, _ signing.Signer return nil, err } - authStore := newStoreAuthStore() - storefront := service.NewWalletStoreService(manager, appStore, appSigner, cfg.StoreName, cfg.StoreAppID, cfg.HomeBlockchains, cfg.ClearnodeWSURL) + storefront := service.NewWalletStoreService( + manager, + appStore, + appSigner, + cfg.StoreName, + cfg.StoreAppID, + cfg.HomeBlockchains, + cfg.ClearnodeWSURL, + cfg.StoreChannelBootstrapAmounts, + ) mux := http.NewServeMux() mux.Handle("GET /healthz", healthHandler(manager)) mux.Handle("GET /readyz", readyHandler(manager)) - mux.Handle("POST /api/store/connect/challenge", storeConnectChallengeHandler(authStore)) - mux.Handle("POST /api/store/connect/verify", storeConnectVerifyHandler(authStore)) - mux.Handle("GET /api/store/bootstrap", storeBootstrapHandler(storefront, authStore)) - mux.Handle("POST /api/store/update", storeUpdateHandler(storefront, authStore)) - mux.Handle("GET /api/store/content/{id}", storeContentHandler(storefront, authStore)) + mux.Handle("GET /api/store/bootstrap", storeBootstrapHandler(storefront)) + mux.Handle("POST /api/store/init", storeInitHandler(storefront)) + mux.Handle("POST /api/store/update", storeUpdateHandler(storefront)) + mux.Handle("GET /api/store/content/{id}", storeContentHandler(storefront)) + mux.Handle("POST /api/store/content/{id}/open", storeContentSignedPostHandler()) mux.Handle("/", ui) return recoveryMiddleware(logger, loggingMiddleware(logger, mux)), nil diff --git a/internal/httpapi/sessionkeys.go b/internal/httpapi/sessionkeys.go deleted file mode 100644 index d881f27..0000000 --- a/internal/httpapi/sessionkeys.go +++ /dev/null @@ -1,112 +0,0 @@ -package httpapi - -import ( - "net/http" - "time" - - "github.com/layer-3/nitrolite-go-example/internal/service" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" -) - -type registerChannelSessionKeyRequest struct { - SessionKey string `json:"session_key"` - Assets []string `json:"assets"` - ExpiresAt string `json:"expires_at"` -} - -type registerAppSessionKeyRequest struct { - SessionKey string `json:"session_key"` - ApplicationIDs []string `json:"application_ids"` - AppSessionIDs []string `json:"app_session_ids"` - ExpiresAt string `json:"expires_at"` -} - -func channelSessionKeysHandler(sessionKeys *service.SessionKeyService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - states, err := sessionKeys.GetChannelKeys(r.Context(), optionalQuery(r, "session_key")) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "states": encodeChannelSessionKeyStates(states), - }) - } -} - -func registerChannelSessionKeyHandler(sessionKeys *service.SessionKeyService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req registerChannelSessionKeyRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - expiresAt, err := time.Parse(time.RFC3339, req.ExpiresAt) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", "invalid expires_at") - return - } - - state, err := sessionKeys.RegisterChannelKey(r.Context(), service.RegisterChannelSessionKeyRequest{ - SessionKey: req.SessionKey, - Assets: req.Assets, - ExpiresAt: expiresAt, - }) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "state": encodeChannelSessionKeyStates([]core.ChannelSessionKeyStateV1{*state})[0], - }) - } -} - -func appSessionKeysHandler(sessionKeys *service.SessionKeyService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - states, err := sessionKeys.GetAppKeys(r.Context(), optionalQuery(r, "session_key")) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "states": encodeAppSessionKeyStates(states), - }) - } -} - -func registerAppSessionKeyHandler(sessionKeys *service.SessionKeyService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req registerAppSessionKeyRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - expiresAt, err := time.Parse(time.RFC3339, req.ExpiresAt) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", "invalid expires_at") - return - } - - state, err := sessionKeys.RegisterAppKey(r.Context(), service.RegisterAppSessionKeyRequest{ - SessionKey: req.SessionKey, - ApplicationIDs: req.ApplicationIDs, - AppSessionIDs: req.AppSessionIDs, - ExpiresAt: expiresAt, - }) - if err != nil { - writeServiceError(w, err) - return - } - - writeJSON(w, http.StatusOK, map[string]any{ - "state": encodeAppSessionKeyStates([]app.AppSessionKeyStateV1{*state})[0], - }) - } -} diff --git a/internal/httpapi/store_public.go b/internal/httpapi/store_public.go index fd861fd..4de23bf 100644 --- a/internal/httpapi/store_public.go +++ b/internal/httpapi/store_public.go @@ -2,12 +2,19 @@ package httpapi import ( "net/http" + "strings" - "github.com/layer-3/nitrolite-go-example/internal/service" + "github.com/layer-3/nitrolite-store-example/internal/service" ) -func storeBootstrapHandler(storefront *service.WalletStoreService, auth *storeAuthStore) http.Handler { - return requireStoreAuth(auth, func(w http.ResponseWriter, r *http.Request, walletAddress string) { +func storeBootstrapHandler(storefront *service.WalletStoreService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + walletAddress := strings.TrimSpace(r.URL.Query().Get("wallet_address")) + if walletAddress == "" { + writeError(w, http.StatusBadRequest, "invalid_request", "wallet_address is required") + return + } + bootstrap, err := storefront.Bootstrap(r.Context(), walletAddress, r.URL.Query().Get("asset")) if err != nil { writeServiceError(w, err) @@ -17,15 +24,15 @@ func storeBootstrapHandler(storefront *service.WalletStoreService, auth *storeAu }) } -func storeUpdateHandler(storefront *service.WalletStoreService, auth *storeAuthStore) http.Handler { - return requireStoreAuth(auth, func(w http.ResponseWriter, r *http.Request, walletAddress string) { - var req service.StoreUpdateRequest +func storeInitHandler(storefront *service.WalletStoreService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var req service.StoreInitRequest if err := decodeJSON(r, &req); err != nil { writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) return } - bootstrap, err := storefront.SubmitUpdate(r.Context(), walletAddress, req) + bootstrap, err := storefront.CreateSession(r.Context(), req) if err != nil { writeServiceError(w, err) return @@ -34,9 +41,29 @@ func storeUpdateHandler(storefront *service.WalletStoreService, auth *storeAuthS }) } -func storeContentHandler(storefront *service.WalletStoreService, auth *storeAuthStore) http.Handler { - return requireStoreAuth(auth, func(w http.ResponseWriter, r *http.Request, walletAddress string) { - item, err := storefront.Content(r.Context(), walletAddress, r.URL.Query().Get("asset"), r.PathValue("id")) +func storeUpdateHandler(storefront *service.WalletStoreService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var req service.StoreUpdateRequest + if err := decodeJSON(r, &req); err != nil { + writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) + return + } + + result, err := storefront.SubmitUpdate(r.Context(), req) + if err != nil { + writeServiceError(w, err) + return + } + writeJSON(w, http.StatusOK, result) + }) +} + +func storeContentHandler(storefront *service.WalletStoreService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + item, err := storefront.Content(r.Context(), r.PathValue("id"), service.StoreContentRequest{ + WalletAddress: r.URL.Query().Get("wallet_address"), + Asset: r.URL.Query().Get("asset"), + }) if err != nil { writeServiceError(w, err) return @@ -44,3 +71,9 @@ func storeContentHandler(storefront *service.WalletStoreService, auth *storeAuth writeJSON(w, http.StatusOK, item) }) } + +func storeContentSignedPostHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "content reads use GET /api/store/content/{id}?wallet_address=...&asset=...") + }) +} diff --git a/internal/httpapi/storeauth_public.go b/internal/httpapi/storeauth_public.go deleted file mode 100644 index d584703..0000000 --- a/internal/httpapi/storeauth_public.go +++ /dev/null @@ -1,248 +0,0 @@ -package httpapi - -import ( - "errors" - "net/http" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/layer-3/nitrolite/pkg/sign" -) - -const ( - storeAuthSessionCookieName = "nitrolite_store_auth" - storeAuthSessionTTL = 30 * 24 * time.Hour - storeAuthChallengeTTL = 5 * time.Minute -) - -type storeAuthChallenge struct { - ID string - WalletAddress string - Message string - ExpiresAt time.Time -} - -type storeAuthSession struct { - Token string - WalletAddress string - ExpiresAt time.Time -} - -var ( - errStoreChallengeNotFound = errors.New("challenge not found") - errStoreChallengeExpired = errors.New("challenge expired") -) - -type storeAuthStore struct { - mu sync.Mutex - now func() time.Time - challenges map[string]storeAuthChallenge - sessions map[string]storeAuthSession -} - -type storeConnectChallengeRequest struct { - WalletAddress string `json:"wallet_address"` -} - -type storeConnectChallengeResponse struct { - ChallengeID string `json:"challenge_id"` - Message string `json:"message"` - ExpiresAt string `json:"expires_at"` -} - -type storeConnectVerifyRequest struct { - ChallengeID string `json:"challenge_id"` - WalletAddress string `json:"wallet_address"` - Signature string `json:"signature"` -} - -type storeConnectVerifyResponse struct { - WalletAddress string `json:"wallet_address"` -} - -func newStoreAuthStore() *storeAuthStore { - return &storeAuthStore{ - now: time.Now, - challenges: make(map[string]storeAuthChallenge), - sessions: make(map[string]storeAuthSession), - } -} - -func (s *storeAuthStore) createChallenge(walletAddress string) (*storeAuthChallenge, error) { - id, err := randomToken() - if err != nil { - return nil, err - } - expiresAt := s.now().UTC().Add(storeAuthChallengeTTL) - challenge := storeAuthChallenge{ - ID: id, - WalletAddress: walletAddress, - Message: "Nitrolite Go Example Store\n\n" + - "Sign this message to use the store.\n" + - "Wallet: " + walletAddress + "\n" + - "Nonce: " + id + "\n" + - "Expires At: " + expiresAt.Format(time.RFC3339), - ExpiresAt: expiresAt, - } - - s.mu.Lock() - defer s.mu.Unlock() - s.challenges[id] = challenge - return &challenge, nil -} - -func (s *storeAuthStore) consumeChallenge(id string) (*storeAuthChallenge, error) { - s.mu.Lock() - defer s.mu.Unlock() - - challenge, ok := s.challenges[id] - if !ok { - return nil, errStoreChallengeNotFound - } - delete(s.challenges, id) - if !challenge.ExpiresAt.After(s.now().UTC()) { - return nil, errStoreChallengeExpired - } - return &challenge, nil -} - -func (s *storeAuthStore) createSession(walletAddress string) (*storeAuthSession, error) { - token, err := randomToken() - if err != nil { - return nil, err - } - session := storeAuthSession{ - Token: token, - WalletAddress: walletAddress, - ExpiresAt: s.now().UTC().Add(storeAuthSessionTTL), - } - - s.mu.Lock() - defer s.mu.Unlock() - s.sessions[token] = session - return &session, nil -} - -func (s *storeAuthStore) walletForToken(token string) (string, bool) { - if strings.TrimSpace(token) == "" { - return "", false - } - s.mu.Lock() - defer s.mu.Unlock() - - session, ok := s.sessions[token] - if !ok { - return "", false - } - if !session.ExpiresAt.After(s.now().UTC()) { - delete(s.sessions, token) - return "", false - } - return session.WalletAddress, true -} - -func storeConnectChallengeHandler(auth *storeAuthStore) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req storeConnectChallengeRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - walletAddress := strings.TrimSpace(req.WalletAddress) - if walletAddress == "" { - writeError(w, http.StatusBadRequest, "invalid_request", "wallet_address is required") - return - } - - challenge, err := auth.createChallenge(walletAddress) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create challenge") - return - } - - writeJSON(w, http.StatusOK, storeConnectChallengeResponse{ - ChallengeID: challenge.ID, - Message: challenge.Message, - ExpiresAt: challenge.ExpiresAt.Format(time.RFC3339), - }) - } -} - -func storeConnectVerifyHandler(auth *storeAuthStore) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req storeConnectVerifyRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - challenge, err := auth.consumeChallenge(strings.TrimSpace(req.ChallengeID)) - if err != nil { - switch err { - case errStoreChallengeNotFound: - writeError(w, http.StatusNotFound, "not_found", err.Error()) - case errStoreChallengeExpired: - writeError(w, http.StatusConflict, "conflict", err.Error()) - default: - writeError(w, http.StatusInternalServerError, "internal_error", "failed to verify challenge") - } - return - } - if !strings.EqualFold(strings.TrimSpace(req.WalletAddress), challenge.WalletAddress) { - writeError(w, http.StatusConflict, "conflict", "wallet_address does not match challenge") - return - } - - signature, err := hexutil.Decode(strings.TrimSpace(req.Signature)) - if err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", "invalid signature") - return - } - recoverer, err := sign.NewAddressRecoverer(sign.TypeEthereumMsg) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to initialize signature verifier") - return - } - address, err := recoverer.RecoverAddress([]byte(challenge.Message), signature) - if err != nil || !strings.EqualFold(address.String(), challenge.WalletAddress) { - writeError(w, http.StatusUnauthorized, "unauthorized", "signature does not match wallet") - return - } - - session, err := auth.createSession(challenge.WalletAddress) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create auth session") - return - } - - http.SetCookie(w, &http.Cookie{ - Name: storeAuthSessionCookieName, - Value: session.Token, - Path: "/", - Expires: session.ExpiresAt, - HttpOnly: true, - SameSite: http.SameSiteLaxMode, - Secure: requestIsSecure(r), - }) - - writeJSON(w, http.StatusOK, storeConnectVerifyResponse{WalletAddress: session.WalletAddress}) - } -} - -func requireStoreAuth(auth *storeAuthStore, next func(http.ResponseWriter, *http.Request, string)) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cookie, err := r.Cookie(storeAuthSessionCookieName) - if err != nil { - writeError(w, http.StatusUnauthorized, "unauthorized", "connect your wallet first") - return - } - walletAddress, ok := auth.walletForToken(cookie.Value) - if !ok { - writeError(w, http.StatusUnauthorized, "unauthorized", "connect your wallet first") - return - } - next(w, r, walletAddress) - }) -} diff --git a/internal/httpapi/storefront.go b/internal/httpapi/storefront.go deleted file mode 100644 index 6ac1290..0000000 --- a/internal/httpapi/storefront.go +++ /dev/null @@ -1,179 +0,0 @@ -package httpapi - -import ( - "errors" - "net/http" - "strings" - - "github.com/layer-3/nitrolite-go-example/internal/service" -) - -type storeAssetRequest struct { - Asset string `json:"asset"` -} - -func storeConfigHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, _, err := ensureStoreBrowserSession(w, r) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create browser session") - return - } - payload := storefront.Config() - writeJSON(w, http.StatusOK, map[string]any{ - "browser_session_id": browserID, - "store": payload, - }) - } -} - -func storeCatalogHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - items, err := storefront.Catalog(r.URL.Query().Get("asset")) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"items": items}) - } -} - -func storeCatalogItemHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - item, err := storefront.CatalogItem(r.URL.Query().Get("asset"), r.PathValue("id")) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"item": item}) - } -} - -func storeSessionHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, _, err := ensureStoreBrowserSession(w, r) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create browser session") - return - } - summary, err := storefront.GetSession(r.Context(), browserID, r.URL.Query().Get("asset")) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"session": summary}) - } -} - -func createStoreSessionHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, _, err := ensureStoreBrowserSession(w, r) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create browser session") - return - } - - var req storeAssetRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - summary, err := storefront.CreateSession(r.Context(), browserID, req.Asset) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"session": summary}) - } -} - -func submitStoreStateHandler(storefront *service.StorefrontService, expectedAPIKey string, sessions *writeSessionStore) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, _, err := ensureStoreBrowserSession(w, r) - if err != nil { - writeError(w, http.StatusInternalServerError, "internal_error", "failed to create browser session") - return - } - - var req service.StoreStateRequest - if err := decodeJSON(r, &req); err != nil { - writeError(w, http.StatusBadRequest, "invalid_request", err.Error()) - return - } - - allowAppWithdraw := hasValidBearerKey(r, expectedAPIKey) - if !allowAppWithdraw { - if token, ok := readWriteSession(r); ok { - _, allowAppWithdraw = sessions.Validate(token) - } - } - - summary, err := storefront.SubmitState(r.Context(), browserID, req, allowAppWithdraw) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"session": summary}) - } -} - -func purchasesHandlerStore(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, ok := readStoreBrowserSession(r) - if !ok { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing browser session") - return - } - summary, err := storefront.GetSession(r.Context(), browserID, r.URL.Query().Get("asset")) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"purchases": summary.Purchases}) - } -} - -func contentHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, ok := readStoreBrowserSession(r) - if !ok { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing browser session") - return - } - item, err := storefront.Content(r.Context(), browserID, r.URL.Query().Get("asset"), r.PathValue("id")) - if err != nil { - var conflictErr service.ConflictError - if errors.As(err, &conflictErr) || strings.Contains(strings.ToLower(err.Error()), "not purchased") { - writeError(w, http.StatusForbidden, "forbidden", "item not purchased") - return - } - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{"item": item}) - } -} - -func storeBalanceHandler(storefront *service.StorefrontService) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - browserID, ok := readStoreBrowserSession(r) - if !ok { - writeError(w, http.StatusUnauthorized, "unauthorized", "missing browser session") - return - } - summary, err := storefront.GetSession(r.Context(), browserID, r.URL.Query().Get("asset")) - if err != nil { - writeServiceError(w, err) - return - } - writeJSON(w, http.StatusOK, map[string]any{ - "asset": summary.Asset, - "available_balance": summary.AvailableBalance, - "user_allocation": summary.UserAllocation, - "app_allocation": summary.AppAllocation, - "session_status": summary.Status, - "session_id": summary.AppSessionID, - "version": summary.Version, - }) - } -} diff --git a/internal/nitrolite/manager.go b/internal/nitrolite/manager.go index 89b7891..cf577d9 100644 --- a/internal/nitrolite/manager.go +++ b/internal/nitrolite/manager.go @@ -9,8 +9,8 @@ import ( "sync/atomic" "time" - "github.com/layer-3/nitrolite-go-example/internal/config" - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/config" + appsigning "github.com/layer-3/nitrolite-store-example/internal/signing" "github.com/layer-3/nitrolite/pkg/app" "github.com/layer-3/nitrolite/pkg/core" sdk "github.com/layer-3/nitrolite/sdk/go" @@ -58,6 +58,7 @@ type Client interface { Withdraw(ctx context.Context, blockchainID uint64, asset string, amount decimal.Decimal) (*core.State, error) Transfer(ctx context.Context, recipientWallet string, asset string, amount decimal.Decimal) (*core.State, error) Checkpoint(ctx context.Context, asset string) (string, error) + GetOnChainBalance(ctx context.Context, chainID uint64, asset string, wallet string) (decimal.Decimal, error) } // Manager is a temporary lifecycle placeholder until the SDK wiring lands. diff --git a/internal/nitrolite/manager_test.go b/internal/nitrolite/manager_test.go index 68f35dd..23eed2c 100644 --- a/internal/nitrolite/manager_test.go +++ b/internal/nitrolite/manager_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" + "github.com/layer-3/nitrolite-store-example/internal/testsupport" ) func TestManagerRunReconnectsAfterClientClosure(t *testing.T) { diff --git a/internal/service/app_helpers.go b/internal/service/app_helpers.go index a850546..cdecdd0 100644 --- a/internal/service/app_helpers.go +++ b/internal/service/app_helpers.go @@ -2,163 +2,15 @@ package service import ( "fmt" - "sort" "strings" "github.com/ethereum/go-ethereum/common/hexutil" - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" + appsigning "github.com/layer-3/nitrolite-store-example/internal/signing" "github.com/layer-3/nitrolite/pkg/app" "github.com/layer-3/nitrolite/pkg/sign" "github.com/shopspring/decimal" ) -func validateAppID(appID string) error { - if !app.AppIDV1Regex.MatchString(strings.TrimSpace(appID)) { - return invalidf("invalid app_id") - } - return nil -} - -func buildSingleParticipantAppDefinition(appID string, signerAddress string, nonce uint64) app.AppDefinitionV1 { - return app.AppDefinitionV1{ - ApplicationID: appID, - Participants: []app.AppParticipantV1{ - { - WalletAddress: signerAddress, - SignatureWeight: 1, - }, - }, - Quorum: 1, - Nonce: nonce, - } -} - -func buildInitialAllocations(signerAddress string, allocations []InitialAllocationInput) ([]app.AppAllocationV1, error) { - if len(allocations) == 0 { - return nil, invalidf("initial_allocations must not be empty") - } - - out := make([]app.AppAllocationV1, 0, len(allocations)) - for _, allocation := range allocations { - asset := strings.TrimSpace(strings.ToLower(allocation.Asset)) - if asset == "" { - return nil, invalidf("asset is required") - } - if !allocation.Amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - - out = append(out, app.AppAllocationV1{ - Participant: signerAddress, - Asset: asset, - Amount: allocation.Amount, - }) - } - - sortAppAllocations(out) - return out, nil -} - -func buildOperateAllocations(defaultParticipant string, allocations []AllocationInput) ([]app.AppAllocationV1, error) { - if len(allocations) == 0 { - return nil, invalidf("allocations must not be empty") - } - - out := make([]app.AppAllocationV1, 0, len(allocations)) - for _, allocation := range allocations { - participant := strings.TrimSpace(allocation.Participant) - if participant == "" { - participant = defaultParticipant - } - asset := strings.TrimSpace(strings.ToLower(allocation.Asset)) - if participant == "" { - return nil, invalidf("participant is required") - } - if asset == "" { - return nil, invalidf("asset is required") - } - if !allocation.Amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - - out = append(out, app.AppAllocationV1{ - Participant: participant, - Asset: asset, - Amount: allocation.Amount, - }) - } - - sortAppAllocations(out) - return out, nil -} - -func buildDepositUpdate(current app.AppSessionInfoV1, signerAddress string, asset string, amount decimal.Decimal) (app.AppStateUpdateV1, error) { - normalizedAsset := strings.TrimSpace(strings.ToLower(asset)) - if normalizedAsset == "" { - return app.AppStateUpdateV1{}, invalidf("asset is required") - } - if !amount.IsPositive() { - return app.AppStateUpdateV1{}, invalidf("amount must be positive") - } - - allocations := cloneAllocations(current.Allocations) - found := false - for i := range allocations { - if strings.EqualFold(allocations[i].Participant, signerAddress) && strings.EqualFold(allocations[i].Asset, normalizedAsset) { - allocations[i].Amount = allocations[i].Amount.Add(amount) - found = true - break - } - } - if !found { - allocations = append(allocations, app.AppAllocationV1{ - Participant: signerAddress, - Asset: normalizedAsset, - Amount: amount, - }) - } - - sortAppAllocations(allocations) - return app.AppStateUpdateV1{ - AppSessionID: current.AppSessionID, - Intent: app.AppStateUpdateIntentDeposit, - Version: current.Version + 1, - Allocations: allocations, - SessionData: current.SessionData, - }, nil -} - -func buildOperateUpdate(current app.AppSessionInfoV1, allocations []app.AppAllocationV1, sessionData string) (app.AppStateUpdateV1, error) { - if len(allocations) == 0 { - return app.AppStateUpdateV1{}, invalidf("allocations must not be empty") - } - allocations = cloneAllocations(allocations) - sortAppAllocations(allocations) - return app.AppStateUpdateV1{ - AppSessionID: current.AppSessionID, - Intent: app.AppStateUpdateIntentOperate, - Version: current.Version + 1, - Allocations: allocations, - SessionData: sessionData, - }, nil -} - -func buildCloseUpdate(current app.AppSessionInfoV1) (app.AppStateUpdateV1, error) { - if len(current.Allocations) == 0 { - return app.AppStateUpdateV1{}, invalidf("session has no allocations") - } - - allocations := cloneAllocations(current.Allocations) - sortAppAllocations(allocations) - return app.AppStateUpdateV1{ - AppSessionID: current.AppSessionID, - Intent: app.AppStateUpdateIntentClose, - Version: current.Version + 1, - Allocations: allocations, - SessionData: current.SessionData, - }, nil -} - func signCreateAppSessionRequest(definition app.AppDefinitionV1, sessionData string, signer appsigning.Signer) (string, error) { payload, err := app.PackCreateAppSessionRequestV1(definition, sessionData) if err != nil { @@ -223,23 +75,13 @@ func parseNumericVersion(raw string) (uint64, error) { return uint64(parsed.IntPart()), nil } -func cloneAllocations(in []app.AppAllocationV1) []app.AppAllocationV1 { - out := make([]app.AppAllocationV1, 0, len(in)) - for _, allocation := range in { - out = append(out, app.AppAllocationV1{ - Participant: allocation.Participant, - Asset: allocation.Asset, - Amount: allocation.Amount, - }) +func parsePositiveAmount(raw string) (decimal.Decimal, error) { + amount, err := decimal.NewFromString(strings.TrimSpace(raw)) + if err != nil { + return decimal.Decimal{}, invalidf("invalid amount") } - return out -} - -func sortAppAllocations(allocations []app.AppAllocationV1) { - sort.Slice(allocations, func(i, j int) bool { - if allocations[i].Participant == allocations[j].Participant { - return allocations[i].Asset < allocations[j].Asset - } - return allocations[i].Participant < allocations[j].Participant - }) + if !amount.IsPositive() { + return decimal.Decimal{}, invalidf("amount must be positive") + } + return amount, nil } diff --git a/internal/service/app_helpers_test.go b/internal/service/app_helpers_test.go deleted file mode 100644 index bc0ae17..0000000 --- a/internal/service/app_helpers_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package service - -import ( - "encoding/hex" - "testing" - - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/sign" - "github.com/shopspring/decimal" -) - -const ( - serviceTestPrivateKey = "0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318" - serviceTestAddress = "0x2c7536e3605d9c16a7a3d7b1898e529396a65c23" -) - -func TestValidateAppID(t *testing.T) { - t.Parallel() - - if err := validateAppID("demo-app"); err != nil { - t.Fatalf("validateAppID(valid) error = %v", err) - } - if err := validateAppID("Demo App"); err == nil { - t.Fatal("validateAppID(invalid) error = nil") - } -} - -func TestBuildSingleParticipantAppDefinition(t *testing.T) { - t.Parallel() - - definition := buildSingleParticipantAppDefinition("demo-app", serviceTestAddress, 42) - if definition.ApplicationID != "demo-app" { - t.Fatalf("ApplicationID = %s", definition.ApplicationID) - } - if len(definition.Participants) != 1 || definition.Participants[0].WalletAddress != serviceTestAddress { - t.Fatalf("Participants = %#v", definition.Participants) - } - if definition.Quorum != 1 || definition.Nonce != 42 { - t.Fatalf("definition = %#v", definition) - } -} - -func TestSignCreateAppSessionRequest(t *testing.T) { - t.Parallel() - - signer := mustTestSigner(t) - definition := buildSingleParticipantAppDefinition("demo-app", signer.Address(), 7) - - signatureHex, err := signCreateAppSessionRequest(definition, "{}", signer) - if err != nil { - t.Fatalf("signCreateAppSessionRequest() error = %v", err) - } - - payload, err := app.PackCreateAppSessionRequestV1(definition, "{}") - if err != nil { - t.Fatalf("PackCreateAppSessionRequestV1() error = %v", err) - } - verifyAppSessionWalletSignature(t, payload, signatureHex, signer.Address()) -} - -func TestBuildDepositUpdate(t *testing.T) { - t.Parallel() - - current := app.AppSessionInfoV1{ - AppSessionID: "0xsession", - Version: 3, - SessionData: "{}", - Allocations: []app.AppAllocationV1{ - {Participant: serviceTestAddress, Asset: "usdc", Amount: decimal.RequireFromString("5")}, - }, - } - - update, err := buildDepositUpdate(current, serviceTestAddress, "usdc", decimal.RequireFromString("2")) - if err != nil { - t.Fatalf("buildDepositUpdate() error = %v", err) - } - if update.Version != 4 { - t.Fatalf("Version = %d, want 4", update.Version) - } - if got := update.Allocations[0].Amount.String(); got != "7" { - t.Fatalf("Amount = %s, want 7", got) - } -} - -func TestBuildOperateAndCloseUpdates(t *testing.T) { - t.Parallel() - - current := app.AppSessionInfoV1{ - AppSessionID: "0xsession", - Version: 1, - SessionData: "{}", - Allocations: []app.AppAllocationV1{ - {Participant: serviceTestAddress, Asset: "usdc", Amount: decimal.RequireFromString("5")}, - }, - } - - operate, err := buildOperateUpdate(current, []app.AppAllocationV1{ - {Participant: serviceTestAddress, Asset: "usdc", Amount: decimal.RequireFromString("8")}, - }, `{"turn":2}`) - if err != nil { - t.Fatalf("buildOperateUpdate() error = %v", err) - } - if operate.Intent != app.AppStateUpdateIntentOperate || operate.Version != 2 { - t.Fatalf("operate = %#v", operate) - } - - closeUpdate, err := buildCloseUpdate(current) - if err != nil { - t.Fatalf("buildCloseUpdate() error = %v", err) - } - if closeUpdate.Intent != app.AppStateUpdateIntentClose || closeUpdate.Version != 2 { - t.Fatalf("closeUpdate = %#v", closeUpdate) - } -} - -func mustTestSigner(t *testing.T) appsigning.Signer { - t.Helper() - - signer, err := appsigning.NewEnvSigner(serviceTestPrivateKey) - if err != nil { - t.Fatalf("NewEnvSigner() error = %v", err) - } - return signer -} - -func verifyAppSessionWalletSignature(t *testing.T, payload []byte, signatureHex string, wallet string) { - t.Helper() - - signatureBytes, err := hex.DecodeString(signatureHex[2:]) - if err != nil { - t.Fatalf("hex.DecodeString() error = %v", err) - } - - validator := app.NewAppSessionKeySigValidatorV1(func(sessionKeyAddr string) (string, error) { - return sessionKeyAddr, nil - }) - if err := validator.Verify(wallet, payload, sign.Signature(signatureBytes)); err != nil { - t.Fatalf("Verify() error = %v", err) - } -} diff --git a/internal/service/app_session.go b/internal/service/app_session.go deleted file mode 100644 index ff333ed..0000000 --- a/internal/service/app_session.go +++ /dev/null @@ -1,476 +0,0 @@ -package service - -import ( - "context" - "fmt" - "strings" - "time" - - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" - "github.com/shopspring/decimal" -) - -// NonceSource provides deterministic nonce generation for app session creation. -type NonceSource func() uint64 - -// AppListFilter controls app list queries. -type AppListFilter struct { - AppID *string - OwnerWallet *string - Page uint32 - PerPage uint32 -} - -// SessionListFilter controls app session list queries. -type SessionListFilter struct { - Status string - AppSessionID *string - Participant *string - Page uint32 - PerPage uint32 -} - -// InitialAllocationInput represents a minimal create-session allocation. -type InitialAllocationInput struct { - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -// AllocationInput represents an app-session allocation input. -type AllocationInput struct { - Participant string `json:"participant"` - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -// CreateAppSessionRequest contains create-session inputs. -type CreateAppSessionRequest struct { - ApplicationID string `json:"application_id"` - InitialAllocations []InitialAllocationInput `json:"initial_allocations"` - SessionData string `json:"session_data"` -} - -// DepositAppSessionRequest contains session deposit inputs. -type DepositAppSessionRequest struct { - Asset string `json:"asset"` - Amount decimal.Decimal `json:"amount"` -} - -// OperateAppSessionRequest contains operate-session inputs. -type OperateAppSessionRequest struct { - Allocations []AllocationInput `json:"allocations"` - SessionData string `json:"session_data"` -} - -// CreatedAppSession captures session creation results. -type CreatedAppSession struct { - SessionID string - Version uint64 - Status string -} - -// DepositedAppSession captures deposit results. -type DepositedAppSession struct { - SessionID string - Version uint64 - NodeSig string -} - -// UpdatedAppSession captures generic update results. -type UpdatedAppSession struct { - SessionID string - Version uint64 -} - -// ClosedAppSession captures close results. -type ClosedAppSession struct { - SessionID string - Version uint64 - Status string - FinalAllocations []app.AppAllocationV1 -} - -// AppSessionDetail groups a session with its definition. -type AppSessionDetail struct { - Session app.AppSessionInfoV1 - AppDefinition app.AppDefinitionV1 -} - -// AppSessionService exposes app registry and app session operations. -type AppSessionService struct { - provider clientProvider - signer appsigning.Signer - nextNonce NonceSource -} - -// NewAppSessionService constructs an AppSessionService. -func NewAppSessionService(provider clientProvider, signer appsigning.Signer, nextNonce NonceSource) *AppSessionService { - if nextNonce == nil { - nextNonce = func() uint64 { return uint64(time.Now().UTC().UnixNano()) } - } - return &AppSessionService{ - provider: provider, - signer: signer, - nextNonce: nextNonce, - } -} - -// GetApps lists registered apps. -func (s *AppSessionService) GetApps(ctx context.Context, filter AppListFilter) ([]app.AppInfoV1, core.PaginationMetadata, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, core.PaginationMetadata{}, err - } - - offset := (filter.Page - 1) * filter.PerPage - limit := filter.PerPage - opts := &sdk.GetAppsOptions{ - AppID: filter.AppID, - OwnerWallet: filter.OwnerWallet, - Pagination: &core.PaginationParams{ - Offset: &offset, - Limit: &limit, - }, - } - - apps, meta, err := client.GetApps(ctx, opts) - if err != nil { - return nil, core.PaginationMetadata{}, fmt.Errorf("failed to get apps: %w", err) - } - return apps, meta, nil -} - -// RegisterApp registers a new app. -func (s *AppSessionService) RegisterApp(ctx context.Context, appID string, metadata string, creationApprovalNotRequired bool) error { - client, _, err := activeClient(s.provider) - if err != nil { - return err - } - - if err := validateAppID(appID); err != nil { - return err - } - - if err := client.RegisterApp(ctx, appID, metadata, creationApprovalNotRequired); err != nil { - return fmt.Errorf("failed to register app: %w", err) - } - return nil -} - -// GetSessions lists app sessions. -func (s *AppSessionService) GetSessions(ctx context.Context, filter SessionListFilter) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, core.PaginationMetadata{}, err - } - - status, err := normalizeStatusFilter(filter.Status) - if err != nil { - return nil, core.PaginationMetadata{}, err - } - - offset := (filter.Page - 1) * filter.PerPage - limit := filter.PerPage - participant := filter.Participant - if filter.AppSessionID == nil && participant == nil && signerAddress != "" { - participant = &signerAddress - } - opts := &sdk.GetAppSessionsOptions{ - AppSessionID: filter.AppSessionID, - Participant: participant, - Status: status, - Pagination: &core.PaginationParams{ - Offset: &offset, - Limit: &limit, - }, - } - - sessions, meta, err := client.GetAppSessions(ctx, opts) - if err != nil { - return nil, core.PaginationMetadata{}, fmt.Errorf("failed to get app sessions: %w", err) - } - return sessions, meta, nil -} - -// GetSession returns a session plus its definition. -func (s *AppSessionService) GetSession(ctx context.Context, sessionID string) (*AppSessionDetail, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - session, err := s.lookupSession(ctx, client, sessionID) - if err != nil { - return nil, err - } - definition, err := client.GetAppDefinition(ctx, sessionID) - if err != nil { - return nil, fmt.Errorf("failed to get app definition: %w", err) - } - - return &AppSessionDetail{ - Session: *session, - AppDefinition: *definition, - }, nil -} - -// CreateSession creates a single-participant app session for the demo signer. -func (s *AppSessionService) CreateSession(ctx context.Context, req CreateAppSessionRequest) (*CreatedAppSession, error) { - return s.createSession(ctx, req.ApplicationID, req.InitialAllocations, req.SessionData) -} - -// CreateEmptySession creates a session without initial allocations for internal orchestration flows. -func (s *AppSessionService) CreateEmptySession(ctx context.Context, applicationID string, sessionData string) (*CreatedAppSession, error) { - return s.createSession(ctx, applicationID, nil, sessionData) -} - -// DepositSession deposits into an app session. -func (s *AppSessionService) DepositSession(ctx context.Context, sessionID string, req DepositAppSessionRequest) (*DepositedAppSession, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - current, err := s.lookupSession(ctx, client, sessionID) - if err != nil { - return nil, err - } - - update, err := buildDepositUpdate(*current, signerAddress, req.Asset, req.Amount) - if err != nil { - return nil, err - } - quorumSig, err := signAppStateUpdate(update, s.signer) - if err != nil { - return nil, err - } - - nodeSig, err := client.SubmitAppSessionDeposit(ctx, update, []string{quorumSig}, strings.ToLower(strings.TrimSpace(req.Asset)), req.Amount) - if err != nil { - return nil, fmt.Errorf("failed to submit app session deposit: %w", err) - } - - return &DepositedAppSession{ - SessionID: sessionID, - Version: update.Version, - NodeSig: nodeSig, - }, nil -} - -// OperateSession submits a generic operate update. -func (s *AppSessionService) OperateSession(ctx context.Context, sessionID string, req OperateAppSessionRequest) (*UpdatedAppSession, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - current, err := s.lookupSession(ctx, client, sessionID) - if err != nil { - return nil, err - } - - allocations, err := buildOperateAllocations(signerAddress, req.Allocations) - if err != nil { - return nil, err - } - update, err := buildOperateUpdate(*current, allocations, req.SessionData) - if err != nil { - return nil, err - } - quorumSig, err := signAppStateUpdate(update, s.signer) - if err != nil { - return nil, err - } - - if err := client.SubmitAppState(ctx, update, []string{quorumSig}); err != nil { - return nil, fmt.Errorf("failed to submit app state: %w", err) - } - - return &UpdatedAppSession{ - SessionID: sessionID, - Version: update.Version, - }, nil -} - -// CloseSession closes an app session using its current allocations. -func (s *AppSessionService) CloseSession(ctx context.Context, sessionID string) (*ClosedAppSession, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - current, err := s.lookupSession(ctx, client, sessionID) - if err != nil { - return nil, err - } - - update, err := buildCloseUpdate(*current) - if err != nil { - return nil, err - } - quorumSig, err := signAppStateUpdate(update, s.signer) - if err != nil { - return nil, err - } - - if err := client.SubmitAppState(ctx, update, []string{quorumSig}); err != nil { - return nil, fmt.Errorf("failed to submit close app state: %w", err) - } - - return &ClosedAppSession{ - SessionID: sessionID, - Version: update.Version, - Status: "closed", - FinalAllocations: cloneAllocations(current.Allocations), - }, nil -} - -func (s *AppSessionService) createSession(ctx context.Context, applicationID string, allocations []InitialAllocationInput, sessionData string) (*CreatedAppSession, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - if err := validateAppID(applicationID); err != nil { - return nil, err - } - - appInfo, err := s.lookupApp(ctx, client, applicationID) - if err != nil { - return nil, err - } - - definition := buildSingleParticipantAppDefinition(applicationID, signerAddress, s.nextNonce()) - quorumSig, err := signCreateAppSessionRequest(definition, sessionData, s.signer) - if err != nil { - return nil, err - } - - opts := []sdk.CreateAppSessionOptions{} - if !appInfo.App.CreationApprovalNotRequired { - ownerSig, err := signCreateAppSessionRequest(definition, sessionData, s.signer) - if err != nil { - return nil, fmt.Errorf("failed to sign owner approval: %w", err) - } - opts = append(opts, sdk.CreateAppSessionOptions{OwnerSig: ownerSig}) - } - - sessionID, version, status, err := client.CreateAppSession(ctx, definition, sessionData, []string{quorumSig}, opts...) - if err != nil { - return nil, fmt.Errorf("failed to create app session: %w", err) - } - - parsedVersion, err := parseDecimalVersion(version) - if err != nil { - return nil, err - } - current := app.AppSessionInfoV1{ - AppSessionID: sessionID, - AppDefinition: definition, - IsClosed: strings.EqualFold(status, "closed"), - SessionData: sessionData, - Version: parsedVersion, - Allocations: nil, - } - - if len(allocations) > 0 { - initialAllocations, err := buildInitialAllocations(signerAddress, allocations) - if err != nil { - return nil, err - } - for _, allocation := range initialAllocations { - update, err := buildDepositUpdate(current, signerAddress, allocation.Asset, allocation.Amount) - if err != nil { - return nil, err - } - quorumSig, err := signAppStateUpdate(update, s.signer) - if err != nil { - return nil, err - } - if _, err := client.SubmitAppSessionDeposit(ctx, update, []string{quorumSig}, allocation.Asset, allocation.Amount); err != nil { - return nil, fmt.Errorf("failed to submit initial app session deposit: %w", err) - } - current.Version = update.Version - current.Allocations = cloneAllocations(update.Allocations) - } - } - - return &CreatedAppSession{ - SessionID: sessionID, - Version: current.Version, - Status: status, - }, nil -} - -func (s *AppSessionService) lookupApp(ctx context.Context, client nitroliteClient, appID string) (*app.AppInfoV1, error) { - if err := validateAppID(appID); err != nil { - return nil, err - } - - opts := &sdk.GetAppsOptions{AppID: &appID} - apps, _, err := client.GetApps(ctx, opts) - if err != nil { - return nil, fmt.Errorf("failed to get apps: %w", err) - } - for _, appInfo := range apps { - if appInfo.App.ID == appID { - return &appInfo, nil - } - } - return nil, notFoundf("app not found") -} - -func (s *AppSessionService) lookupSession(ctx context.Context, client nitroliteClient, sessionID string) (*app.AppSessionInfoV1, error) { - sessionID = strings.TrimSpace(sessionID) - if sessionID == "" { - return nil, invalidf("session_id is required") - } - - opts := &sdk.GetAppSessionsOptions{AppSessionID: &sessionID} - sessions, _, err := client.GetAppSessions(ctx, opts) - if err != nil { - return nil, fmt.Errorf("failed to get app sessions: %w", err) - } - for _, session := range sessions { - if session.AppSessionID == sessionID { - return &session, nil - } - } - return nil, notFoundf("session not found") -} - -type nitroliteClient interface { - GetApps(ctx context.Context, opts *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) - GetAppSessions(ctx context.Context, opts *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) - GetAppDefinition(ctx context.Context, appSessionID string) (*app.AppDefinitionV1, error) - CreateAppSession(ctx context.Context, definition app.AppDefinitionV1, sessionData string, quorumSigs []string, opts ...sdk.CreateAppSessionOptions) (string, string, string, error) - SubmitAppSessionDeposit(ctx context.Context, appStateUpdate app.AppStateUpdateV1, quorumSigs []string, asset string, depositAmount decimal.Decimal) (string, error) - SubmitAppState(ctx context.Context, appStateUpdate app.AppStateUpdateV1, quorumSigs []string) error - RegisterApp(ctx context.Context, appID string, metadata string, creationApprovalNotRequired bool) error -} - -func normalizeStatusFilter(raw string) (*string, error) { - trimmed := strings.TrimSpace(strings.ToLower(raw)) - switch trimmed { - case "", "all": - return nil, nil - case "open", "closed": - return &trimmed, nil - default: - return nil, invalidf("invalid status") - } -} - -func parseDecimalVersion(raw string) (uint64, error) { - parsed, err := decimal.NewFromString(raw) - if err != nil { - return 0, invalidf("invalid version") - } - if !parsed.IsInteger() || parsed.IsNegative() { - return 0, invalidf("invalid version") - } - return uint64(parsed.IntPart()), nil -} diff --git a/internal/service/app_session_test.go b/internal/service/app_session_test.go deleted file mode 100644 index 152fac4..0000000 --- a/internal/service/app_session_test.go +++ /dev/null @@ -1,207 +0,0 @@ -package service - -import ( - "context" - "log/slog" - "testing" - - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" - "github.com/shopspring/decimal" -) - -func TestAppSessionService_RegisterApp(t *testing.T) { - t.Parallel() - - var called bool - svc := newTestAppSessionService(t, &testsupport.FakeClient{ - RegisterAppFunc: func(ctx context.Context, appID string, metadata string, creationApprovalNotRequired bool) error { - called = true - if appID != "demo-app" || metadata != `{"name":"Demo"}` || !creationApprovalNotRequired { - t.Fatalf("RegisterApp args = %q %q %v", appID, metadata, creationApprovalNotRequired) - } - return nil - }, - }) - - if err := svc.RegisterApp(context.Background(), "demo-app", `{"name":"Demo"}`, true); err != nil { - t.Fatalf("RegisterApp() error = %v", err) - } - if !called { - t.Fatal("RegisterApp was not called") - } -} - -func TestAppSessionService_CreateSession(t *testing.T) { - t.Parallel() - - var gotDefinition app.AppDefinitionV1 - var gotSigCount int - var deposited app.AppStateUpdateV1 - svc := newTestAppSessionService(t, &testsupport.FakeClient{ - GetAppsFunc: func(ctx context.Context, opts *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) { - return []app.AppInfoV1{ - {App: app.AppV1{ID: "demo-app", CreationApprovalNotRequired: true}}, - }, core.PaginationMetadata{}, nil - }, - CreateAppSessionFunc: func(ctx context.Context, definition app.AppDefinitionV1, sessionData string, quorumSigs []string, opts ...sdk.CreateAppSessionOptions) (string, string, string, error) { - gotDefinition = definition - gotSigCount = len(quorumSigs) - return "0xsession", "1", "open", nil - }, - SubmitAppSessionDepositFunc: func(ctx context.Context, update app.AppStateUpdateV1, quorumSigs []string, asset string, amount decimal.Decimal) (string, error) { - deposited = update - return "0xnodesig", nil - }, - }) - - created, err := svc.CreateSession(context.Background(), CreateAppSessionRequest{ - ApplicationID: "demo-app", - InitialAllocations: []InitialAllocationInput{ - {Asset: "usdc", Amount: decimal.RequireFromString("5")}, - }, - SessionData: "{}", - }) - if err != nil { - t.Fatalf("CreateSession() error = %v", err) - } - if created.SessionID != "0xsession" || created.Version != 2 || created.Status != "open" { - t.Fatalf("created = %#v", created) - } - if gotDefinition.Nonce != 42 || gotSigCount != 1 { - t.Fatalf("definition/signatures = %#v %d", gotDefinition, gotSigCount) - } - if deposited.Intent != app.AppStateUpdateIntentDeposit || len(deposited.Allocations) != 1 { - t.Fatalf("deposited = %#v", deposited) - } - if deposited.Allocations[0].Amount.String() != "5" { - t.Fatalf("deposit allocations = %#v", deposited.Allocations) - } -} - -func TestAppSessionService_DepositOperateClose(t *testing.T) { - t.Parallel() - - current := app.AppSessionInfoV1{ - AppSessionID: "0xsession", - AppDefinition: app.AppDefinitionV1{ - ApplicationID: "demo-app", - Participants: []app.AppParticipantV1{{WalletAddress: serviceTestAddress, SignatureWeight: 1}}, - Quorum: 1, - Nonce: 42, - }, - IsClosed: false, - SessionData: "{}", - Version: 1, - Allocations: []app.AppAllocationV1{{Participant: serviceTestAddress, Asset: "usdc", Amount: decimal.RequireFromString("5")}}, - } - - var deposited app.AppStateUpdateV1 - var operated app.AppStateUpdateV1 - var closed app.AppStateUpdateV1 - svc := newTestAppSessionService(t, &testsupport.FakeClient{ - GetAppSessionsFunc: func(ctx context.Context, opts *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { - return []app.AppSessionInfoV1{current}, core.PaginationMetadata{}, nil - }, - SubmitAppSessionDepositFunc: func(ctx context.Context, update app.AppStateUpdateV1, quorumSigs []string, asset string, amount decimal.Decimal) (string, error) { - deposited = update - return "0xnodesig", nil - }, - SubmitAppStateFunc: func(ctx context.Context, update app.AppStateUpdateV1, quorumSigs []string) error { - switch update.Intent { - case app.AppStateUpdateIntentOperate: - operated = update - case app.AppStateUpdateIntentClose: - closed = update - } - return nil - }, - }) - - depositResult, err := svc.DepositSession(context.Background(), "0xsession", DepositAppSessionRequest{ - Asset: "usdc", - Amount: decimal.RequireFromString("2"), - }) - if err != nil { - t.Fatalf("DepositSession() error = %v", err) - } - if depositResult.Version != 2 || depositResult.NodeSig != "0xnodesig" { - t.Fatalf("depositResult = %#v", depositResult) - } - if deposited.Allocations[0].Amount.String() != "7" { - t.Fatalf("deposited allocations = %#v", deposited.Allocations) - } - - operateResult, err := svc.OperateSession(context.Background(), "0xsession", OperateAppSessionRequest{ - Allocations: []AllocationInput{ - {Asset: "usdc", Amount: decimal.RequireFromString("8")}, - }, - SessionData: `{"turn":2}`, - }) - if err != nil { - t.Fatalf("OperateSession() error = %v", err) - } - if operateResult.Version != 2 || operated.Intent != app.AppStateUpdateIntentOperate { - t.Fatalf("operate = %#v %#v", operateResult, operated) - } - - closeResult, err := svc.CloseSession(context.Background(), "0xsession") - if err != nil { - t.Fatalf("CloseSession() error = %v", err) - } - if closeResult.Status != "closed" || closed.Intent != app.AppStateUpdateIntentClose { - t.Fatalf("close = %#v %#v", closeResult, closed) - } -} - -func TestAppSessionService_GetSessionsDefaultsToSignerParticipant(t *testing.T) { - t.Parallel() - - var gotParticipant *string - svc := newTestAppSessionService(t, &testsupport.FakeClient{ - GetAppSessionsFunc: func(ctx context.Context, opts *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { - gotParticipant = opts.Participant - return []app.AppSessionInfoV1{}, core.PaginationMetadata{}, nil - }, - }) - - _, _, err := svc.GetSessions(context.Background(), SessionListFilter{ - Status: "all", - Page: 1, - PerPage: 20, - }) - if err != nil { - t.Fatalf("GetSessions() error = %v", err) - } - if gotParticipant == nil || *gotParticipant != serviceTestAddress { - t.Fatalf("participant = %v, want %s", gotParticipant, serviceTestAddress) - } -} - -func newTestAppSessionService(t *testing.T, client *testsupport.FakeClient) *AppSessionService { - t.Helper() - - if client.GetUserAddressFunc == nil { - client.GetUserAddressFunc = func() string { return serviceTestAddress } - } - manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ - Connected: true, - Ready: true, - SignerAddress: serviceTestAddress, - }, slog.Default()) - signer := mustTestServiceSigner(t) - return NewAppSessionService(manager, signer, func() uint64 { return 42 }) -} - -func mustTestServiceSigner(t *testing.T) appsigning.Signer { - t.Helper() - signer, err := appsigning.NewEnvSigner(serviceTestPrivateKey) - if err != nil { - t.Fatalf("NewEnvSigner() error = %v", err) - } - return signer -} diff --git a/internal/service/balance.go b/internal/service/balance.go deleted file mode 100644 index 39263b7..0000000 --- a/internal/service/balance.go +++ /dev/null @@ -1,64 +0,0 @@ -package service - -import ( - "context" - "fmt" - - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" -) - -// TransactionsFilter controls transaction list pagination and filtering. -type TransactionsFilter struct { - Asset *string - Page uint32 - PerPage uint32 -} - -// BalanceService exposes wallet balance and transaction reads. -type BalanceService struct { - provider clientProvider -} - -// NewBalanceService constructs a BalanceService. -func NewBalanceService(provider clientProvider) *BalanceService { - return &BalanceService{provider: provider} -} - -// GetBalances retrieves balances for the demo signer. -func (s *BalanceService) GetBalances(ctx context.Context) ([]core.BalanceEntry, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - balances, err := client.GetBalances(ctx, wallet) - if err != nil { - return nil, fmt.Errorf("failed to get balances: %w", err) - } - return balances, nil -} - -// GetTransactions retrieves transactions for the demo signer. -func (s *BalanceService) GetTransactions(ctx context.Context, filter TransactionsFilter) ([]core.Transaction, core.PaginationMetadata, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, core.PaginationMetadata{}, err - } - - offset := (filter.Page - 1) * filter.PerPage - limit := filter.PerPage - opts := &sdk.GetTransactionsOptions{ - Asset: filter.Asset, - Pagination: &core.PaginationParams{ - Offset: &offset, - Limit: &limit, - }, - } - - transactions, meta, err := client.GetTransactions(ctx, wallet, opts) - if err != nil { - return nil, core.PaginationMetadata{}, fmt.Errorf("failed to get transactions: %w", err) - } - return transactions, meta, nil -} diff --git a/internal/service/channel.go b/internal/service/channel.go deleted file mode 100644 index b4cfd9f..0000000 --- a/internal/service/channel.go +++ /dev/null @@ -1,46 +0,0 @@ -package service - -import ( - "context" - "fmt" - - "github.com/layer-3/nitrolite/pkg/core" -) - -// ChannelService exposes read-only channel state operations. -type ChannelService struct { - provider clientProvider -} - -// NewChannelService constructs a ChannelService. -func NewChannelService(provider clientProvider) *ChannelService { - return &ChannelService{provider: provider} -} - -// GetHomeChannel retrieves the current home channel for an asset. -func (s *ChannelService) GetHomeChannel(ctx context.Context, asset string) (*core.Channel, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - channel, err := client.GetHomeChannel(ctx, wallet, asset) - if err != nil { - return nil, fmt.Errorf("failed to get home channel: %w", err) - } - return channel, nil -} - -// GetLatestState retrieves the latest state for an asset. -func (s *ChannelService) GetLatestState(ctx context.Context, asset string, onlySigned bool) (*core.State, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - state, err := client.GetLatestState(ctx, wallet, asset, onlySigned) - if err != nil { - return nil, fmt.Errorf("failed to get latest state: %w", err) - } - return state, nil -} diff --git a/internal/service/channel_actions.go b/internal/service/channel_actions.go deleted file mode 100644 index bb9c368..0000000 --- a/internal/service/channel_actions.go +++ /dev/null @@ -1,228 +0,0 @@ -package service - -import ( - "context" - "fmt" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/layer-3/nitrolite/pkg/core" - "github.com/shopspring/decimal" -) - -// CloseChannelRequest contains close-channel inputs. -type CloseChannelRequest struct { - Asset string -} - -// ChallengeRequest contains challenge inputs. -type ChallengeRequest struct { - Asset string -} - -// ChallengeResult captures challenge tx hash. -type ChallengeResult struct { - TxHash string -} - -// CloseChannel closes the home channel for an asset. -func (s *ChannelService) CloseChannel(ctx context.Context, req CloseChannelRequest) (*core.State, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - asset := strings.TrimSpace(strings.ToLower(req.Asset)) - if asset == "" { - return nil, invalidf("asset is required") - } - state, err := client.CloseHomeChannel(ctx, asset) - if err != nil { - return nil, fmt.Errorf("failed to close home channel: %w", err) - } - return state, nil -} - -// ChallengeLatestState challenges the latest signed state for an asset. -func (s *ChannelService) ChallengeLatestState(ctx context.Context, req ChallengeRequest) (*ChallengeResult, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, err - } - asset := strings.TrimSpace(strings.ToLower(req.Asset)) - if asset == "" { - return nil, invalidf("asset is required") - } - state, err := client.GetLatestState(ctx, wallet, asset, true) - if err != nil { - return nil, fmt.Errorf("failed to get latest signed state: %w", err) - } - txHash, err := client.Challenge(ctx, *state) - if err != nil { - return nil, fmt.Errorf("failed to challenge state: %w", err) - } - return &ChallengeResult{TxHash: txHash}, nil -} - -// MutationService exposes phase-1/3 channel mutation operations. -type MutationService struct { - provider clientProvider - homeBlockchains map[string]uint64 -} - -// NewMutationService constructs a MutationService. -func NewMutationService(provider clientProvider, homeBlockchains map[string]uint64) *MutationService { - normalized := make(map[string]uint64, len(homeBlockchains)) - for asset, chainID := range homeBlockchains { - normalized[strings.ToLower(strings.TrimSpace(asset))] = chainID - } - return &MutationService{ - provider: provider, - homeBlockchains: normalized, - } -} - -// ApproveToken approves token spending for the demo signer. -func (s *MutationService) ApproveToken(ctx context.Context, chainID uint64, asset string, amount decimal.Decimal) (string, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return "", err - } - normalizedAsset, err := normalizeAsset(asset) - if err != nil { - return "", err - } - if chainID == 0 { - return "", invalidf("blockchain_id must be positive") - } - if err := s.validateHomeBlockchain(normalizedAsset, chainID); err != nil { - return "", err - } - if !amount.IsPositive() { - return "", invalidf("amount must be positive") - } - - txHash, err := client.ApproveToken(ctx, chainID, normalizedAsset, amount) - if err != nil { - return "", fmt.Errorf("failed to approve token: %w", err) - } - return txHash, nil -} - -// Deposit submits a home deposit. -func (s *MutationService) Deposit(ctx context.Context, chainID uint64, asset string, amount decimal.Decimal) (*core.State, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - normalizedAsset, err := normalizeAsset(asset) - if err != nil { - return nil, err - } - if chainID == 0 { - return nil, invalidf("blockchain_id must be positive") - } - if err := s.validateHomeBlockchain(normalizedAsset, chainID); err != nil { - return nil, err - } - if !amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - - state, err := client.Deposit(ctx, chainID, normalizedAsset, amount) - if err != nil { - return nil, fmt.Errorf("failed to deposit: %w", err) - } - return state, nil -} - -// Withdraw submits a home withdrawal. -func (s *MutationService) Withdraw(ctx context.Context, chainID uint64, asset string, amount decimal.Decimal) (*core.State, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - normalizedAsset, err := normalizeAsset(asset) - if err != nil { - return nil, err - } - if chainID == 0 { - return nil, invalidf("blockchain_id must be positive") - } - if err := s.validateHomeBlockchain(normalizedAsset, chainID); err != nil { - return nil, err - } - if !amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - - state, err := client.Withdraw(ctx, chainID, normalizedAsset, amount) - if err != nil { - return nil, fmt.Errorf("failed to withdraw: %w", err) - } - return state, nil -} - -// Transfer submits a transfer. -func (s *MutationService) Transfer(ctx context.Context, recipient string, asset string, amount decimal.Decimal) (*core.State, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - normalizedAsset, err := normalizeAsset(asset) - if err != nil { - return nil, err - } - normalizedRecipient := strings.TrimSpace(recipient) - if normalizedRecipient == "" { - return nil, invalidf("recipient is required") - } - if !common.IsHexAddress(normalizedRecipient) { - return nil, invalidf("invalid recipient") - } - if !amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - - state, err := client.Transfer(ctx, normalizedRecipient, normalizedAsset, amount) - if err != nil { - return nil, fmt.Errorf("failed to transfer: %w", err) - } - return state, nil -} - -// Checkpoint submits a checkpoint. -func (s *MutationService) Checkpoint(ctx context.Context, asset string) (string, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return "", err - } - normalizedAsset, err := normalizeAsset(asset) - if err != nil { - return "", err - } - - txHash, err := client.Checkpoint(ctx, normalizedAsset) - if err != nil { - return "", fmt.Errorf("failed to checkpoint: %w", err) - } - return txHash, nil -} - -func normalizeAsset(asset string) (string, error) { - normalized := strings.ToLower(strings.TrimSpace(asset)) - if normalized == "" { - return "", invalidf("asset is required") - } - return normalized, nil -} - -func (s *MutationService) validateHomeBlockchain(asset string, chainID uint64) error { - expectedChainID, ok := s.homeBlockchains[asset] - if !ok { - return invalidf("asset %s is not configured in HOME_BLOCKCHAINS", asset) - } - if expectedChainID != chainID { - return invalidf("blockchain_id must match configured home chain %d for asset %s", expectedChainID, asset) - } - return nil -} diff --git a/internal/service/channel_actions_test.go b/internal/service/channel_actions_test.go deleted file mode 100644 index fac1aac..0000000 --- a/internal/service/channel_actions_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package service - -import ( - "context" - "log/slog" - "testing" - - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" - "github.com/layer-3/nitrolite/pkg/core" - "github.com/shopspring/decimal" -) - -func TestMutationService_Actions(t *testing.T) { - t.Parallel() - - var approvedAsset string - var depositedAmount decimal.Decimal - var transferredRecipient string - - client := &testsupport.FakeClient{ - GetUserAddressFunc: func() string { return serviceTestAddress }, - ApproveTokenFunc: func(ctx context.Context, chainID uint64, asset string, amount decimal.Decimal) (string, error) { - approvedAsset = asset - return "0xapprove", nil - }, - DepositFunc: func(ctx context.Context, blockchainID uint64, asset string, amount decimal.Decimal) (*core.State, error) { - depositedAmount = amount - return &core.State{ID: "0xdeposit", Asset: asset, Version: 2}, nil - }, - WithdrawFunc: func(ctx context.Context, blockchainID uint64, asset string, amount decimal.Decimal) (*core.State, error) { - return &core.State{ID: "0xwithdraw", Asset: asset, Version: 3}, nil - }, - TransferFunc: func(ctx context.Context, recipientWallet string, asset string, amount decimal.Decimal) (*core.State, error) { - transferredRecipient = recipientWallet - return &core.State{ID: "0xtransfer", Asset: asset, Version: 4}, nil - }, - CheckpointFunc: func(ctx context.Context, asset string) (string, error) { - return "0xcheckpoint", nil - }, - CloseHomeChannelFunc: func(ctx context.Context, asset string) (*core.State, error) { - return &core.State{ID: "0xclose", Asset: asset, Version: 5}, nil - }, - GetLatestStateFunc: func(ctx context.Context, wallet string, asset string, onlySigned bool) (*core.State, error) { - return &core.State{ID: "0xstate", Asset: asset, Version: 6}, nil - }, - ChallengeFunc: func(ctx context.Context, state core.State) (string, error) { - return "0xchallenge", nil - }, - } - - manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ - Connected: true, - Ready: true, - SignerAddress: serviceTestAddress, - }, slog.Default()) - - mutations := NewMutationService(manager, map[string]uint64{"usdc": 80002}) - channel := NewChannelService(manager) - - txHash, err := mutations.ApproveToken(context.Background(), 80002, "USDC", decimal.RequireFromString("100")) - if err != nil { - t.Fatalf("ApproveToken() error = %v", err) - } - if txHash != "0xapprove" || approvedAsset != "usdc" { - t.Fatalf("approve result = %q, asset = %q", txHash, approvedAsset) - } - - state, err := mutations.Deposit(context.Background(), 80002, "usdc", decimal.RequireFromString("5")) - if err != nil { - t.Fatalf("Deposit() error = %v", err) - } - if state.ID != "0xdeposit" || depositedAmount.String() != "5" { - t.Fatalf("deposit state = %#v, amount = %s", state, depositedAmount) - } - - if _, err := mutations.Withdraw(context.Background(), 80002, "usdc", decimal.RequireFromString("2")); err != nil { - t.Fatalf("Withdraw() error = %v", err) - } - - if _, err := mutations.Transfer(context.Background(), "0x1111111111111111111111111111111111111111", "usdc", decimal.RequireFromString("1")); err != nil { - t.Fatalf("Transfer() error = %v", err) - } - if transferredRecipient != "0x1111111111111111111111111111111111111111" { - t.Fatalf("transferredRecipient = %q", transferredRecipient) - } - - checkpointHash, err := mutations.Checkpoint(context.Background(), "usdc") - if err != nil { - t.Fatalf("Checkpoint() error = %v", err) - } - if checkpointHash != "0xcheckpoint" { - t.Fatalf("checkpointHash = %q", checkpointHash) - } - - closedState, err := channel.CloseChannel(context.Background(), CloseChannelRequest{Asset: "usdc"}) - if err != nil { - t.Fatalf("CloseChannel() error = %v", err) - } - if closedState.ID != "0xclose" { - t.Fatalf("closedState = %#v", closedState) - } - - challengeResult, err := channel.ChallengeLatestState(context.Background(), ChallengeRequest{Asset: "usdc"}) - if err != nil { - t.Fatalf("ChallengeLatestState() error = %v", err) - } - if challengeResult.TxHash != "0xchallenge" { - t.Fatalf("challengeResult = %#v", challengeResult) - } -} - -func TestMutationService_Validation(t *testing.T) { - t.Parallel() - - manager := nitrolite.NewManagerWithClient(&testsupport.FakeClient{ - GetUserAddressFunc: func() string { return serviceTestAddress }, - }, nitrolite.Health{ - Connected: true, - Ready: true, - SignerAddress: serviceTestAddress, - }, slog.Default()) - - mutations := NewMutationService(manager, map[string]uint64{"usdc": 80002}) - - if _, err := mutations.Deposit(context.Background(), 0, "usdc", decimal.RequireFromString("1")); err == nil { - t.Fatal("Deposit() error = nil, want validation error") - } - if _, err := mutations.Deposit(context.Background(), 11155111, "usdc", decimal.RequireFromString("1")); err == nil { - t.Fatal("Deposit() mismatched chain error = nil, want validation error") - } - if _, err := mutations.Transfer(context.Background(), "not-an-address", "usdc", decimal.RequireFromString("1")); err == nil { - t.Fatal("Transfer() error = nil, want validation error") - } - if _, err := mutations.Checkpoint(context.Background(), ""); err == nil { - t.Fatal("Checkpoint() error = nil, want validation error") - } -} diff --git a/internal/service/common.go b/internal/service/common.go index 3e18d22..0f7caa5 100644 --- a/internal/service/common.go +++ b/internal/service/common.go @@ -1,7 +1,7 @@ package service import ( - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" ) type clientProvider interface { diff --git a/internal/service/demo.go b/internal/service/demo.go deleted file mode 100644 index eba5394..0000000 --- a/internal/service/demo.go +++ /dev/null @@ -1,254 +0,0 @@ -package service - -import ( - "context" - "sort" - "strings" - - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" -) - -// DemoGuidance describes the next recommended action for a guided flow. -type DemoGuidance struct { - NextAction string - Headline string - Description string - SyncPending bool -} - -// DemoOverview captures the landing-page view of the demo state. -type DemoOverview struct { - Health nitrolite.Health - WalletAddress string - HomeBlockchains map[string]uint64 - SelectedAsset string - Assets []core.Asset - Balances []core.BalanceEntry - Channel *core.Channel - LatestState *core.State - LatestActivity *core.Transaction - Apps []app.AppInfoV1 - Sessions []app.AppSessionInfoV1 - ChannelGuidance DemoGuidance - AppGuidance DemoGuidance -} - -// DemoService provides aggregated, UI-oriented reads for the guided surface. -type DemoService struct { - provider clientProvider - health func() nitrolite.Health - homeBlockchains map[string]uint64 -} - -// NewDemoService constructs a DemoService. -func NewDemoService(provider clientProvider, health func() nitrolite.Health, homeBlockchains map[string]uint64) *DemoService { - normalized := make(map[string]uint64, len(homeBlockchains)) - for asset, chainID := range homeBlockchains { - normalized[strings.ToLower(strings.TrimSpace(asset))] = chainID - } - return &DemoService{ - provider: provider, - health: health, - homeBlockchains: normalized, - } -} - -// GetOverview aggregates the current demo state for the guided landing page. -func (s *DemoService) GetOverview(ctx context.Context, requestedAsset string) (*DemoOverview, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - assets, err := client.GetAssets(ctx, nil) - if err != nil { - return nil, err - } - balances, err := client.GetBalances(ctx, wallet) - if err != nil { - return nil, err - } - selectedAsset := chooseSelectedAsset(requestedAsset, balances, assets, s.homeBlockchains) - - var channel *core.Channel - if selectedAsset != "" { - channel, _ = client.GetHomeChannel(ctx, wallet, selectedAsset) - } - - var latestState *core.State - if selectedAsset != "" { - latestState, _ = client.GetLatestState(ctx, wallet, selectedAsset, true) - } - - var latestActivity *core.Transaction - offset := uint32(0) - limit := uint32(5) - if transactions, _, err := client.GetTransactions(ctx, wallet, &sdk.GetTransactionsOptions{ - Pagination: &core.PaginationParams{Offset: &offset, Limit: &limit}, - }); err == nil && len(transactions) > 0 { - latestActivity = &transactions[0] - } - - apps, _, _ := client.GetApps(ctx, &sdk.GetAppsOptions{ - Pagination: &core.PaginationParams{Offset: &offset, Limit: &limit}, - }) - sessions, _, _ := client.GetAppSessions(ctx, &sdk.GetAppSessionsOptions{ - Participant: &wallet, - Pagination: &core.PaginationParams{Offset: &offset, Limit: &limit}, - }) - - overview := &DemoOverview{ - Health: s.health(), - WalletAddress: wallet, - HomeBlockchains: cloneHomeBlockchains(s.homeBlockchains), - SelectedAsset: selectedAsset, - Assets: assets, - Balances: balances, - Channel: channel, - LatestState: latestState, - LatestActivity: latestActivity, - Apps: apps, - Sessions: sessions, - } - overview.ChannelGuidance = buildChannelGuidance(overview) - overview.AppGuidance = buildAppGuidance(overview) - return overview, nil -} - -func chooseSelectedAsset(requested string, balances []core.BalanceEntry, assets []core.Asset, homeBlockchains map[string]uint64) string { - requested = strings.ToLower(strings.TrimSpace(requested)) - if requested != "" { - for _, asset := range assets { - if strings.EqualFold(asset.Symbol, requested) { - return strings.ToLower(asset.Symbol) - } - } - } - - for _, balance := range balances { - if strings.TrimSpace(balance.Asset) != "" { - return strings.ToLower(balance.Asset) - } - } - - homeAssets := make([]string, 0, len(homeBlockchains)) - for asset := range homeBlockchains { - homeAssets = append(homeAssets, asset) - } - sort.Strings(homeAssets) - if len(homeAssets) > 0 { - return homeAssets[0] - } - - available := make([]string, 0, len(assets)) - for _, asset := range assets { - if strings.TrimSpace(asset.Symbol) != "" { - available = append(available, strings.ToLower(asset.Symbol)) - } - } - sort.Strings(available) - if len(available) > 0 { - return available[0] - } - - return "" -} - -func cloneHomeBlockchains(values map[string]uint64) map[string]uint64 { - out := make(map[string]uint64, len(values)) - for asset, chainID := range values { - out[asset] = chainID - } - return out -} - -func buildChannelGuidance(overview *DemoOverview) DemoGuidance { - if overview.SelectedAsset == "" { - return DemoGuidance{ - NextAction: "review_supported_assets", - Headline: "No supported asset selected", - Description: "Pick a supported asset to inspect the live channel flow.", - } - } - - if overview.Channel != nil && overview.LatestState != nil && overview.LatestState.Version > overview.Channel.StateVersion { - if isCheckpointableTransition(overview.LatestState.Transition.Type) { - return DemoGuidance{ - NextAction: "checkpoint", - Headline: "Latest signed channel transition is ready to checkpoint", - Description: "Checkpoint the pending home deposit or withdrawal before starting the next channel transition.", - SyncPending: true, - } - } - return DemoGuidance{ - NextAction: "wait_for_sync", - Headline: "Latest signed state is ahead of clearnode channel state", - Description: "Waiting for clearnode sync before the next channel transition. The pending signed state comes from app-session activity, so this guided flow should wait instead of checkpointing manually.", - SyncPending: true, - } - } - - balance := balanceForAsset(overview.Balances, overview.SelectedAsset) - if balance == "0" { - return DemoGuidance{ - NextAction: "approve_and_deposit", - Headline: "Fund the home channel", - Description: "Approve the asset and deposit into the home channel to start the live channel flow.", - } - } - - return DemoGuidance{ - NextAction: "transfer_or_withdraw", - Headline: "Channel is synced and ready", - Description: "Run a deposit, transfer, withdraw, or app-session flow using the live backend signer.", - } -} - -func buildAppGuidance(overview *DemoOverview) DemoGuidance { - for _, session := range overview.Sessions { - if !session.IsClosed { - return DemoGuidance{ - NextAction: "operate_or_close_session", - Headline: "Open app session available", - Description: "Continue the single-signer app flow with deposit, operate, or close.", - } - } - } - - for _, appInfo := range overview.Apps { - if strings.EqualFold(appInfo.App.ID, "default") { - return DemoGuidance{ - NextAction: "create_session", - Headline: "Ready to create a demo app session", - Description: "Use the default app to create a single-signer session, then deposit, operate, and close it.", - } - } - } - - return DemoGuidance{ - NextAction: "review_apps", - Headline: "No app session ready yet", - Description: "Review available apps first. Registering a new app may require staked YELLOW depending on node policy.", - } -} - -func balanceForAsset(balances []core.BalanceEntry, asset string) string { - for _, balance := range balances { - if strings.EqualFold(balance.Asset, asset) { - return balance.Balance.String() - } - } - return "0" -} - -func isCheckpointableTransition(transitionType core.TransitionType) bool { - switch transitionType { - case core.TransitionTypeHomeDeposit, core.TransitionTypeHomeWithdrawal: - return true - default: - return false - } -} diff --git a/internal/service/demo_test.go b/internal/service/demo_test.go deleted file mode 100644 index e4208eb..0000000 --- a/internal/service/demo_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package service - -import ( - "testing" - - "github.com/layer-3/nitrolite/pkg/core" -) - -func TestBuildChannelGuidanceCheckpointableTransition(t *testing.T) { - t.Parallel() - - overview := &DemoOverview{ - SelectedAsset: "yusd", - Channel: &core.Channel{ - StateVersion: 4, - }, - LatestState: &core.State{ - Version: 5, - Transition: core.Transition{ - Type: core.TransitionTypeHomeDeposit, - }, - }, - } - - got := buildChannelGuidance(overview) - if got.NextAction != "checkpoint" { - t.Fatalf("next action = %q, want checkpoint", got.NextAction) - } - if !got.SyncPending { - t.Fatal("expected sync pending guidance") - } -} - -func TestBuildChannelGuidanceCommitTransitionWaitsForSync(t *testing.T) { - t.Parallel() - - overview := &DemoOverview{ - SelectedAsset: "yusd", - Channel: &core.Channel{ - StateVersion: 4, - }, - LatestState: &core.State{ - Version: 6, - Transition: core.Transition{ - Type: core.TransitionTypeCommit, - }, - }, - } - - got := buildChannelGuidance(overview) - if got.NextAction != "wait_for_sync" { - t.Fatalf("next action = %q, want wait_for_sync", got.NextAction) - } - if !got.SyncPending { - t.Fatal("expected sync pending guidance") - } -} diff --git a/internal/service/errors.go b/internal/service/errors.go index 8a4d555..d49b480 100644 --- a/internal/service/errors.go +++ b/internal/service/errors.go @@ -6,39 +6,87 @@ import ( ) // ErrUnavailable indicates the SDK client is not currently usable. -var ErrUnavailable = errors.New("clearnode not reachable") +var ErrUnavailable = errors.New("nitronode not reachable") // ValidationError represents invalid client-supplied input after request decoding. type ValidationError struct { message string + code string } func (e ValidationError) Error() string { return e.message } +func (e ValidationError) Code() string { + if e.code == "" { + return "invalid_request" + } + return e.code +} + // NotFoundError represents a missing logical resource. type NotFoundError struct { message string + code string } func (e NotFoundError) Error() string { return e.message } +func (e NotFoundError) Code() string { + if e.code == "" { + return "not_found" + } + return e.code +} + // ConflictError represents a write that conflicts with current state. type ConflictError struct { message string + code string } func (e ConflictError) Error() string { return e.message } +func (e ConflictError) Code() string { + if e.code == "" { + return "conflict" + } + return e.code +} + +// UpstreamError represents a Nitronode operation failure. +type UpstreamError struct { + message string + err error +} + +func (e UpstreamError) Error() string { + if e.err != nil && e.message != "" { + return fmt.Sprintf("%s: %v", e.message, e.err) + } + if e.err != nil { + return e.err.Error() + } + return e.message +} + +func (e UpstreamError) Unwrap() error { + return e.err +} + func invalidf(format string, args ...any) error { return ValidationError{message: fmt.Sprintf(format, args...)} } +func invalidCodef(code string, format string, args ...any) error { + return ValidationError{message: fmt.Sprintf(format, args...), code: code} +} + func notFoundf(format string, args ...any) error { return NotFoundError{message: fmt.Sprintf(format, args...)} } @@ -46,3 +94,11 @@ func notFoundf(format string, args ...any) error { func conflictf(format string, args ...any) error { return ConflictError{message: fmt.Sprintf(format, args...)} } + +func conflictCodef(code string, format string, args ...any) error { + return ConflictError{message: fmt.Sprintf(format, args...), code: code} +} + +func upstreamf(err error, format string, args ...any) error { + return UpstreamError{message: fmt.Sprintf(format, args...), err: err} +} diff --git a/internal/service/merchant.go b/internal/service/merchant.go deleted file mode 100644 index 3524f6b..0000000 --- a/internal/service/merchant.go +++ /dev/null @@ -1,576 +0,0 @@ -package service - -import ( - "context" - "fmt" - "net/url" - "sort" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/google/uuid" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" - "github.com/shopspring/decimal" -) - -const ( - operationTypeCapture = "capture" - operationTypeSettle = "settle" - operationTypeRefund = "refund" - operationTypePayout = "payout" -) - -type CreatePaymentRequestRequest struct { - Title string - Description string - Asset string - Amount decimal.Decimal -} - -type CreatePaymentRequestResult struct { - PaymentRequest store.PaymentRequest - PayURL string -} - -type PayoutRequest struct { - Asset string - Amount decimal.Decimal - DestinationWallet string -} - -type OperationDispatchResult struct { - Operation store.Operation - ResourceID string - Created bool -} - -type PaymentRequestPage struct { - MerchantName string - PaymentRequest store.PaymentRequest - Order *store.Order - Operation *store.Operation -} - -type DashboardSummary struct { - AvailableBalance string - ReservedBalance string - PendingCount int - OpenOrders int -} - -type MerchantDashboardOverview struct { - MerchantName string - SelectedAsset string - WalletAddress string - HomeBlockchains map[string]uint64 - Health nitrolite.Health - Assets []core.Asset - Balances []core.BalanceEntry - Channel *core.Channel - LatestState *core.State - LatestActivity *core.Transaction - Lease *store.OperatorLease - PaymentRequests []store.PaymentRequest - Orders []store.Order - Payouts []store.Payout - Operations []store.Operation - Summary DashboardSummary -} - -type MerchantService struct { - store *store.Store - merchantName string - merchantAppID string - homeBlockchains map[string]uint64 - now func() time.Time -} - -func NewMerchantService(store *store.Store, merchantName string, merchantAppID string, homeBlockchains map[string]uint64) *MerchantService { - normalized := make(map[string]uint64, len(homeBlockchains)) - for asset, chainID := range homeBlockchains { - normalized[strings.ToLower(strings.TrimSpace(asset))] = chainID - } - return &MerchantService{ - store: store, - merchantName: merchantName, - merchantAppID: strings.TrimSpace(merchantAppID), - homeBlockchains: normalized, - now: time.Now, - } -} - -func (s *MerchantService) CreatePaymentRequest(ctx context.Context, req CreatePaymentRequestRequest, baseURL string) (*CreatePaymentRequestResult, error) { - title := strings.TrimSpace(req.Title) - description := strings.TrimSpace(req.Description) - asset, err := normalizeAsset(req.Asset) - if err != nil { - return nil, err - } - if title == "" { - return nil, invalidf("title is required") - } - if !req.Amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - if _, ok := s.homeBlockchains[asset]; !ok { - return nil, invalidf("asset %s is not configured in HOME_BLOCKCHAINS", asset) - } - - now := s.now().UTC() - slug, err := newSlug() - if err != nil { - return nil, fmt.Errorf("failed to create payment slug: %w", err) - } - paymentRequest := store.PaymentRequest{ - ID: uuid.NewString(), - Slug: slug, - Title: title, - Description: description, - Asset: asset, - Amount: req.Amount.String(), - Status: "pending", - CreatedAt: now, - UpdatedAt: now, - } - if err := s.store.CreatePaymentRequest(ctx, paymentRequest); err != nil { - return nil, fmt.Errorf("failed to create payment request: %w", err) - } - payURL, err := paymentURL(baseURL, slug) - if err != nil { - return nil, err - } - return &CreatePaymentRequestResult{ - PaymentRequest: paymentRequest, - PayURL: payURL, - }, nil -} - -func (s *MerchantService) GetPaymentRequestPage(ctx context.Context, slug string) (*PaymentRequestPage, error) { - paymentRequest, err := s.store.GetPaymentRequestBySlug(ctx, strings.TrimSpace(slug)) - if err != nil { - if err == store.ErrNotFound { - return nil, notFoundf("payment request not found") - } - return nil, fmt.Errorf("failed to load payment request: %w", err) - } - - var order *store.Order - if paymentRequest.OrderID != "" { - order, err = s.store.GetOrder(ctx, paymentRequest.OrderID) - if err != nil && err != store.ErrNotFound { - return nil, fmt.Errorf("failed to load order: %w", err) - } - if err == store.ErrNotFound { - order = nil - } - } - - var operation *store.Operation - if paymentRequest.OperationID != "" { - operation, err = s.store.GetOperation(ctx, paymentRequest.OperationID) - if err != nil && err != store.ErrNotFound { - return nil, fmt.Errorf("failed to load operation: %w", err) - } - if err == store.ErrNotFound { - operation = nil - } - } - - return &PaymentRequestPage{ - MerchantName: s.merchantName, - PaymentRequest: *paymentRequest, - Order: order, - Operation: operation, - }, nil -} - -func (s *MerchantService) PayPaymentRequest(ctx context.Context, slug string) (*OperationDispatchResult, error) { - now := s.now().UTC() - order := store.Order{ - ID: uuid.NewString(), - PaymentRequestID: "", - OperationID: uuid.NewString(), - AppSessionID: "", - Status: "capturing", - CreatedAt: now, - UpdatedAt: now, - } - op := store.Operation{ - ID: order.OperationID, - Type: operationTypeCapture, - ResourceID: order.ID, - Status: "queued", - Payload: "{}", - QueuedAt: now, - StartedAt: nil, - CompletedAt: nil, - } - - paymentRequest, existingOrder, existingOp, created, err := s.store.BeginPaymentRequestProcessing(ctx, strings.TrimSpace(slug), order, op) - if err != nil { - switch err { - case store.ErrNotFound: - return nil, notFoundf("payment request not found") - case store.ErrConflict: - return nil, conflictf("payment request is no longer payable") - default: - return nil, fmt.Errorf("failed to start payment processing: %w", err) - } - } - - if !created { - result := &OperationDispatchResult{Created: false} - if existingOp != nil { - result.Operation = *existingOp - } - if existingOrder != nil { - result.ResourceID = existingOrder.ID - } - return result, nil - } - - order.PaymentRequestID = paymentRequest.ID - order.Title = paymentRequest.Title - order.Description = paymentRequest.Description - order.Asset = paymentRequest.Asset - order.Amount = paymentRequest.Amount - - payload, err := marshalOperationPayload(operationPayload{ - PaymentRequestID: paymentRequest.ID, - OrderID: order.ID, - Asset: paymentRequest.Asset, - Amount: paymentRequest.Amount, - Step: "deposit_pending", - }) - if err != nil { - return nil, err - } - op.Payload = payload - if err := s.store.UpdateOperation(ctx, op); err != nil { - return nil, fmt.Errorf("failed to persist operation payload: %w", err) - } - - return &OperationDispatchResult{ - Operation: op, - ResourceID: order.ID, - Created: true, - }, nil -} - -func (s *MerchantService) QueueOrderResolution(ctx context.Context, orderID string, operationType string) (*OperationDispatchResult, error) { - order, err := s.store.GetOrder(ctx, strings.TrimSpace(orderID)) - if err != nil { - if err == store.ErrNotFound { - return nil, notFoundf("order not found") - } - return nil, fmt.Errorf("failed to load order: %w", err) - } - if order.AppSessionID == "" { - return nil, conflictf("order has no settlement session") - } - if order.Status != "reserved" { - return nil, conflictf("order must be reserved before it can be %s", operationType) - } - - now := s.now().UTC() - op := store.Operation{ - ID: uuid.NewString(), - Type: operationType, - ResourceID: order.ID, - Status: "queued", - Payload: "{}", - QueuedAt: now, - } - payload, err := marshalOperationPayload(operationPayload{ - OrderID: order.ID, - SessionID: order.AppSessionID, - Asset: order.Asset, - Amount: order.Amount, - Step: "session_close_pending", - }) - if err != nil { - return nil, err - } - op.Payload = payload - if err := s.store.CreateOperation(ctx, op); err != nil { - return nil, fmt.Errorf("failed to create %s operation: %w", operationType, err) - } - - order.OperationID = op.ID - order.Status = map[string]string{ - operationTypeSettle: "settling", - operationTypeRefund: "refunding", - }[operationType] - order.UpdatedAt = now - if err := s.store.UpdateOrder(ctx, *order); err != nil { - return nil, fmt.Errorf("failed to update order: %w", err) - } - - return &OperationDispatchResult{ - Operation: op, - ResourceID: order.ID, - Created: true, - }, nil -} - -func (s *MerchantService) QueuePayout(ctx context.Context, req PayoutRequest) (*OperationDispatchResult, error) { - asset, err := normalizeAsset(req.Asset) - if err != nil { - return nil, err - } - if _, ok := s.homeBlockchains[asset]; !ok { - return nil, invalidf("asset %s is not configured in HOME_BLOCKCHAINS", asset) - } - if !req.Amount.IsPositive() { - return nil, invalidf("amount must be positive") - } - destination := strings.TrimSpace(req.DestinationWallet) - if !common.IsHexAddress(destination) { - return nil, invalidf("invalid destination_wallet") - } - - now := s.now().UTC() - payout := store.Payout{ - ID: uuid.NewString(), - OperationID: uuid.NewString(), - Asset: asset, - Amount: req.Amount.String(), - DestinationWallet: destination, - Status: "pending", - CreatedAt: now, - UpdatedAt: now, - } - payload, err := marshalOperationPayload(operationPayload{ - PayoutID: payout.ID, - Asset: asset, - Amount: payout.Amount, - DestinationWallet: destination, - Step: "withdraw_pending", - }) - if err != nil { - return nil, err - } - op := store.Operation{ - ID: payout.OperationID, - Type: operationTypePayout, - ResourceID: payout.ID, - Status: "queued", - Payload: payload, - QueuedAt: now, - } - if err := s.store.CreatePayoutWithOperation(ctx, payout, op); err != nil { - return nil, fmt.Errorf("failed to create payout: %w", err) - } - - return &OperationDispatchResult{ - Operation: op, - ResourceID: payout.ID, - Created: true, - }, nil -} - -func (s *MerchantService) GetOperation(ctx context.Context, operationID string) (*store.Operation, error) { - op, err := s.store.GetOperation(ctx, strings.TrimSpace(operationID)) - if err != nil { - if err == store.ErrNotFound { - return nil, notFoundf("operation not found") - } - return nil, fmt.Errorf("failed to load operation: %w", err) - } - return op, nil -} - -type MerchantDashboardService struct { - provider clientProvider - store *store.Store - merchantName string - homeBlockchains map[string]uint64 -} - -func NewMerchantDashboardService(provider clientProvider, store *store.Store, merchantName string, homeBlockchains map[string]uint64) *MerchantDashboardService { - normalized := make(map[string]uint64, len(homeBlockchains)) - for asset, chainID := range homeBlockchains { - normalized[strings.ToLower(strings.TrimSpace(asset))] = chainID - } - return &MerchantDashboardService{ - provider: provider, - store: store, - merchantName: merchantName, - homeBlockchains: normalized, - } -} - -func (s *MerchantDashboardService) GetOverview(ctx context.Context, requestedAsset string) (*MerchantDashboardOverview, error) { - client, wallet, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - assets, err := client.GetAssets(ctx, nil) - if err != nil { - return nil, ErrUnavailable - } - balances, err := client.GetBalances(ctx, wallet) - if err != nil { - return nil, ErrUnavailable - } - selectedAsset := chooseSelectedAsset(requestedAsset, balances, assets, s.homeBlockchains) - - var channel *core.Channel - if selectedAsset != "" { - channel, err = client.GetHomeChannel(ctx, wallet, selectedAsset) - if err != nil { - return nil, ErrUnavailable - } - } - - var latestState *core.State - if selectedAsset != "" { - latestState, err = client.GetLatestState(ctx, wallet, selectedAsset, true) - if err != nil { - return nil, ErrUnavailable - } - } - - var latestActivity *core.Transaction - offset := uint32(0) - limit := uint32(10) - transactions, _, err := client.GetTransactions(ctx, wallet, &sdk.GetTransactionsOptions{ - Pagination: &core.PaginationParams{Offset: &offset, Limit: &limit}, - }) - if err != nil { - return nil, ErrUnavailable - } - if len(transactions) > 0 { - latestActivity = &transactions[0] - } - - paymentRequests, err := s.store.ListPaymentRequests(ctx, 8) - if err != nil { - return nil, fmt.Errorf("failed to list payment requests: %w", err) - } - orders, err := s.store.ListOrders(ctx, 12) - if err != nil { - return nil, fmt.Errorf("failed to list orders: %w", err) - } - payouts, err := s.store.ListPayouts(ctx, 8) - if err != nil { - return nil, fmt.Errorf("failed to list payouts: %w", err) - } - operations, err := s.store.ListOperations(ctx, 12) - if err != nil { - return nil, fmt.Errorf("failed to list operations: %w", err) - } - lease, err := s.store.GetLease(ctx) - if err != nil && err != store.ErrNotFound { - return nil, fmt.Errorf("failed to load lease: %w", err) - } - if err == store.ErrNotFound { - lease = nil - } - - summary := DashboardSummary{ - AvailableBalance: balanceString(balances, selectedAsset), - ReservedBalance: reservedBalance(orders, selectedAsset), - PendingCount: pendingOperationCount(operations), - OpenOrders: openOrderCount(orders), - } - - return &MerchantDashboardOverview{ - MerchantName: s.merchantName, - SelectedAsset: selectedAsset, - WalletAddress: wallet, - HomeBlockchains: cloneHomeBlockchains(s.homeBlockchains), - Health: s.provider.Health(), - Assets: assets, - Balances: balances, - Channel: channel, - LatestState: latestState, - LatestActivity: latestActivity, - Lease: lease, - PaymentRequests: paymentRequests, - Orders: orders, - Payouts: payouts, - Operations: operations, - Summary: summary, - }, nil -} - -func paymentURL(baseURL string, slug string) (string, error) { - parsed, err := url.Parse(strings.TrimSpace(baseURL)) - if err != nil { - return "", invalidf("invalid base url") - } - parsed.Path = "/pay/" + slug - parsed.RawQuery = "" - parsed.Fragment = "" - return parsed.String(), nil -} - -func reservedBalance(orders []store.Order, asset string) string { - total := decimal.Zero - for _, order := range orders { - if !strings.EqualFold(order.Asset, asset) { - continue - } - switch order.Status { - case "reserved", "settling", "refunding": - value, err := decimal.NewFromString(order.Amount) - if err == nil { - total = total.Add(value) - } - } - } - return total.String() -} - -func balanceString(balances []core.BalanceEntry, asset string) string { - for _, balance := range balances { - if strings.EqualFold(balance.Asset, asset) { - return balance.Balance.String() - } - } - return "0" -} - -func pendingOperationCount(ops []store.Operation) int { - count := 0 - for _, op := range ops { - if op.Status != "completed" && op.Status != "failed" { - count++ - } - } - return count -} - -func openOrderCount(orders []store.Order) int { - count := 0 - for _, order := range orders { - if order.Status == "reserved" || order.Status == "capturing" || order.Status == "settling" || order.Status == "refunding" { - count++ - } - } - return count -} - -func newSlug() (string, error) { - id := strings.ReplaceAll(uuid.NewString(), "-", "") - if len(id) < 12 { - return "", fmt.Errorf("failed to generate slug") - } - return strings.ToLower(id[:12]), nil -} - -type byQueuedAt []store.Operation - -func (s byQueuedAt) Len() int { return len(s) } -func (s byQueuedAt) Less(i, j int) bool { return s[i].QueuedAt.Before(s[j].QueuedAt) } -func (s byQueuedAt) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func sortOperationsByQueuedAt(ops []store.Operation) { - sort.Sort(byQueuedAt(ops)) -} diff --git a/internal/service/merchant_runner.go b/internal/service/merchant_runner.go deleted file mode 100644 index f1b8ea6..0000000 --- a/internal/service/merchant_runner.go +++ /dev/null @@ -1,552 +0,0 @@ -package service - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log/slog" - "strconv" - "strings" - "sync" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/layer-3/nitrolite-go-example/internal/config" - "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/shopspring/decimal" -) - -type operationPayload struct { - PaymentRequestID string `json:"payment_request_id,omitempty"` - OrderID string `json:"order_id,omitempty"` - PayoutID string `json:"payout_id,omitempty"` - SessionID string `json:"session_id,omitempty"` - Asset string `json:"asset,omitempty"` - Amount string `json:"amount,omitempty"` - DestinationWallet string `json:"destination_wallet,omitempty"` - TxHash string `json:"tx_hash,omitempty"` - ChainID uint64 `json:"chain_id,omitempty"` - TargetVersion uint64 `json:"target_version,omitempty"` - Step string `json:"step,omitempty"` -} - -type receiptStatus string - -const ( - receiptPending receiptStatus = "pending" - receiptConfirmed receiptStatus = "confirmed" - receiptFailed receiptStatus = "failed" -) - -type chainReceiptReader interface { - ReceiptStatus(ctx context.Context, chainID uint64, txHash string) (receiptStatus, error) -} - -type MerchantOperationRunner struct { - store *store.Store - manager clientProvider - mutations *MutationService - appSessions *AppSessionService - receipts chainReceiptReader - merchantAppID string - logger *slog.Logger - pollInterval time.Duration - now func() time.Time -} - -func NewMerchantOperationRunner(cfg *config.Config, store *store.Store, manager clientProvider, signer signing.Signer, logger *slog.Logger) *MerchantOperationRunner { - return &MerchantOperationRunner{ - store: store, - manager: manager, - mutations: NewMutationService(manager, cfg.HomeBlockchains), - appSessions: NewAppSessionService(manager, signer, nil), - receipts: newRPCReceiptReader(cfg.BlockchainRPCURLs), - merchantAppID: strings.TrimSpace(cfg.MerchantAppID), - logger: logger, - pollInterval: time.Second, - now: time.Now, - } -} - -func (r *MerchantOperationRunner) Run(ctx context.Context) { - if err := r.store.MarkRunningOperationsInterrupted(ctx); err != nil && r.logger != nil { - r.logger.Error("failed to mark interrupted operations", "error", err) - } - - ticker := time.NewTicker(r.pollInterval) - defer ticker.Stop() - - for { - processed, err := r.processNext(ctx) - if err != nil && r.logger != nil { - r.logger.Error("merchant runner iteration failed", "error", err) - } - if processed { - continue - } - - select { - case <-ctx.Done(): - return - case <-ticker.C: - } - } -} - -func (r *MerchantOperationRunner) processNext(ctx context.Context) (bool, error) { - ops, err := r.store.ListOperationsByStatuses(ctx, 1, "queued", "waiting_chain", "waiting_sync") - if err != nil { - return false, err - } - if len(ops) == 0 { - return false, nil - } - return true, r.handleOperation(ctx, ops[0]) -} - -func (r *MerchantOperationRunner) handleOperation(ctx context.Context, op store.Operation) error { - payload, err := unmarshalOperationPayload(op.Payload) - if err != nil { - return r.failOperation(ctx, op, payload, fmt.Sprintf("invalid operation payload: %v", err)) - } - if op.Status == "queued" { - now := r.now().UTC() - op.Status = "running" - op.StartedAt = &now - op.ErrorMessage = "" - if err := r.saveOperation(ctx, &op, payload); err != nil { - return err - } - } - - switch op.Type { - case operationTypeCapture: - return r.runCapture(ctx, &op, payload) - case operationTypeSettle, operationTypeRefund: - return r.runResolution(ctx, &op, payload) - case operationTypePayout: - return r.runPayout(ctx, &op, payload) - default: - return r.failOperation(ctx, op, payload, "unsupported operation type") - } -} - -func (r *MerchantOperationRunner) runCapture(ctx context.Context, op *store.Operation, payload operationPayload) error { - for { - switch payload.Step { - case "", "deposit_pending": - chainID, err := r.homeChainForAsset(payload.Asset) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - amount, err := decimal.NewFromString(payload.Amount) - if err != nil { - return r.failOperation(ctx, *op, payload, "invalid amount in capture payload") - } - state, err := r.mutations.Deposit(ctx, chainID, payload.Asset, amount) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.ChainID = chainID - payload.TargetVersion = state.Version - payload.Step = "checkpoint_pending" - if err := r.saveOperation(ctx, op, payload); err != nil { - return err - } - - case "checkpoint_pending": - txHash, err := r.mutations.Checkpoint(ctx, payload.Asset) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.TxHash = txHash - payload.Step = "checkpoint_submitted" - op.Status = "waiting_chain" - return r.saveOperation(ctx, op, payload) - - case "checkpoint_submitted": - status, err := r.receipts.ReceiptStatus(ctx, payload.ChainID, payload.TxHash) - if err != nil { - return err - } - if status == receiptPending { - return nil - } - if status == receiptFailed { - return r.failOperation(ctx, *op, payload, "checkpoint transaction reverted") - } - payload.Step = "channel_sync_pending" - op.Status = "waiting_sync" - return r.saveOperation(ctx, op, payload) - - case "channel_sync_pending": - synced, err := r.channelReachedVersion(ctx, payload.Asset, payload.TargetVersion) - if err != nil { - return err - } - if !synced { - return nil - } - payload.Step = "session_create_pending" - op.Status = "running" - if err := r.saveOperation(ctx, op, payload); err != nil { - return err - } - - case "session_create_pending": - created, err := r.appSessions.CreateEmptySession(ctx, r.merchantAppID, fmt.Sprintf(`{"order_id":"%s"}`, payload.OrderID)) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.SessionID = created.SessionID - payload.Step = "session_deposit_pending" - - order, err := r.store.GetOrder(ctx, payload.OrderID) - if err != nil { - return err - } - order.AppSessionID = created.SessionID - order.UpdatedAt = r.now().UTC() - if err := r.store.UpdateOrder(ctx, *order); err != nil { - return fmt.Errorf("failed to persist order session: %w", err) - } - if err := r.saveOperation(ctx, op, payload); err != nil { - return err - } - - case "session_deposit_pending": - amount, err := decimal.NewFromString(payload.Amount) - if err != nil { - return r.failOperation(ctx, *op, payload, "invalid amount in capture payload") - } - result, err := r.appSessions.DepositSession(ctx, payload.SessionID, DepositAppSessionRequest{ - Asset: payload.Asset, - Amount: amount, - }) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.TargetVersion = result.Version - payload.Step = "session_sync_pending" - op.Status = "waiting_sync" - return r.saveOperation(ctx, op, payload) - - case "session_sync_pending": - synced, err := r.sessionReachedVersion(ctx, payload.SessionID, payload.TargetVersion, false) - if err != nil { - return err - } - if !synced { - return nil - } - - order, err := r.store.GetOrder(ctx, payload.OrderID) - if err != nil { - return err - } - order.Status = "reserved" - order.UpdatedAt = r.now().UTC() - if err := r.store.UpdateOrder(ctx, *order); err != nil { - return err - } - if err := r.store.UpdatePaymentRequestState(ctx, payload.PaymentRequestID, "completed", order.ID, op.ID); err != nil { - return err - } - return r.completeOperation(ctx, op, payload) - - default: - return r.failOperation(ctx, *op, payload, "unsupported capture step") - } - } -} - -func (r *MerchantOperationRunner) runResolution(ctx context.Context, op *store.Operation, payload operationPayload) error { - for { - switch payload.Step { - case "", "session_close_pending": - result, err := r.appSessions.CloseSession(ctx, payload.SessionID) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.TargetVersion = result.Version - payload.Step = "session_close_sync_pending" - op.Status = "waiting_sync" - return r.saveOperation(ctx, op, payload) - - case "session_close_sync_pending": - synced, err := r.sessionReachedVersion(ctx, payload.SessionID, payload.TargetVersion, true) - if err != nil { - return err - } - if !synced { - return nil - } - - order, err := r.store.GetOrder(ctx, payload.OrderID) - if err != nil { - return err - } - if op.Type == operationTypeSettle { - order.Status = "settled" - } else { - order.Status = "refunded" - } - order.UpdatedAt = r.now().UTC() - if err := r.store.UpdateOrder(ctx, *order); err != nil { - return err - } - return r.completeOperation(ctx, op, payload) - - default: - return r.failOperation(ctx, *op, payload, "unsupported resolution step") - } - } -} - -func (r *MerchantOperationRunner) runPayout(ctx context.Context, op *store.Operation, payload operationPayload) error { - for { - switch payload.Step { - case "", "withdraw_pending": - chainID, err := r.homeChainForAsset(payload.Asset) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - amount, err := decimal.NewFromString(payload.Amount) - if err != nil { - return r.failOperation(ctx, *op, payload, "invalid payout amount") - } - state, err := r.mutations.Withdraw(ctx, chainID, payload.Asset, amount) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.ChainID = chainID - payload.TargetVersion = state.Version - payload.Step = "payout_checkpoint_pending" - if err := r.saveOperation(ctx, op, payload); err != nil { - return err - } - - case "payout_checkpoint_pending": - txHash, err := r.mutations.Checkpoint(ctx, payload.Asset) - if err != nil { - return r.failOperation(ctx, *op, payload, err.Error()) - } - payload.TxHash = txHash - payload.Step = "payout_checkpoint_submitted" - op.Status = "waiting_chain" - return r.saveOperation(ctx, op, payload) - - case "payout_checkpoint_submitted": - status, err := r.receipts.ReceiptStatus(ctx, payload.ChainID, payload.TxHash) - if err != nil { - return err - } - if status == receiptPending { - return nil - } - if status == receiptFailed { - return r.failOperation(ctx, *op, payload, "payout checkpoint transaction reverted") - } - payload.Step = "payout_sync_pending" - op.Status = "waiting_sync" - return r.saveOperation(ctx, op, payload) - - case "payout_sync_pending": - synced, err := r.channelReachedVersion(ctx, payload.Asset, payload.TargetVersion) - if err != nil { - return err - } - if !synced { - return nil - } - - payout, err := r.store.GetPayout(ctx, payload.PayoutID) - if err != nil { - return err - } - payout.Status = "completed" - payout.UpdatedAt = r.now().UTC() - if err := r.store.UpdatePayout(ctx, *payout); err != nil { - return err - } - return r.completeOperation(ctx, op, payload) - - default: - return r.failOperation(ctx, *op, payload, "unsupported payout step") - } - } -} - -func (r *MerchantOperationRunner) failOperation(ctx context.Context, op store.Operation, payload operationPayload, message string) error { - now := r.now().UTC() - op.Status = "failed" - op.ErrorMessage = message - op.CompletedAt = &now - if err := r.saveOperation(ctx, &op, payload); err != nil { - return err - } - - switch op.Type { - case operationTypeCapture: - if payload.OrderID != "" { - if order, err := r.store.GetOrder(ctx, payload.OrderID); err == nil { - order.Status = "failed" - order.UpdatedAt = now - _ = r.store.UpdateOrder(ctx, *order) - } - } - if payload.PaymentRequestID != "" { - _ = r.store.UpdatePaymentRequestState(ctx, payload.PaymentRequestID, "failed", payload.OrderID, op.ID) - } - case operationTypeSettle, operationTypeRefund: - if payload.OrderID != "" { - if order, err := r.store.GetOrder(ctx, payload.OrderID); err == nil { - order.Status = "reserved" - order.UpdatedAt = now - _ = r.store.UpdateOrder(ctx, *order) - } - } - case operationTypePayout: - if payload.PayoutID != "" { - if payout, err := r.store.GetPayout(ctx, payload.PayoutID); err == nil { - payout.Status = "failed" - payout.UpdatedAt = now - _ = r.store.UpdatePayout(ctx, *payout) - } - } - } - return nil -} - -func (r *MerchantOperationRunner) completeOperation(ctx context.Context, op *store.Operation, payload operationPayload) error { - now := r.now().UTC() - op.Status = "completed" - op.CompletedAt = &now - op.ErrorMessage = "" - return r.saveOperation(ctx, op, payload) -} - -func (r *MerchantOperationRunner) saveOperation(ctx context.Context, op *store.Operation, payload operationPayload) error { - encoded, err := marshalOperationPayload(payload) - if err != nil { - return err - } - op.Payload = encoded - return r.store.UpdateOperation(ctx, *op) -} - -func (r *MerchantOperationRunner) channelReachedVersion(ctx context.Context, asset string, version uint64) (bool, error) { - client, wallet, err := activeClient(r.manager) - if err != nil { - return false, err - } - channel, err := client.GetHomeChannel(ctx, wallet, strings.ToLower(strings.TrimSpace(asset))) - if err != nil { - return false, nil - } - return channel != nil && channel.StateVersion >= version, nil -} - -func (r *MerchantOperationRunner) sessionReachedVersion(ctx context.Context, sessionID string, version uint64, closed bool) (bool, error) { - session, err := r.appSessions.GetSession(ctx, sessionID) - if err != nil { - return false, nil - } - if closed && !session.Session.IsClosed { - return false, nil - } - return session.Session.Version >= version, nil -} - -func (r *MerchantOperationRunner) homeChainForAsset(asset string) (uint64, error) { - normalized, err := normalizeAsset(asset) - if err != nil { - return 0, err - } - chainID, ok := r.mutations.homeBlockchains[normalized] - if !ok { - return 0, invalidf("asset %s is not configured in HOME_BLOCKCHAINS", normalized) - } - return chainID, nil -} - -func marshalOperationPayload(payload operationPayload) (string, error) { - raw, err := json.Marshal(payload) - if err != nil { - return "", fmt.Errorf("marshal operation payload: %w", err) - } - return string(raw), nil -} - -func unmarshalOperationPayload(raw string) (operationPayload, error) { - if strings.TrimSpace(raw) == "" { - return operationPayload{}, nil - } - var payload operationPayload - if err := json.Unmarshal([]byte(raw), &payload); err != nil { - return operationPayload{}, err - } - return payload, nil -} - -type rpcReceiptReader struct { - urls map[uint64]string - clients map[uint64]*ethclient.Client - mu sync.Mutex -} - -func newRPCReceiptReader(blockchainRPCURLs map[string]string) chainReceiptReader { - urls := make(map[uint64]string, len(blockchainRPCURLs)) - for chainID, rawURL := range blockchainRPCURLs { - parsed, err := strconv.ParseUint(chainID, 10, 64) - if err != nil { - continue - } - urls[parsed] = rawURL - } - return &rpcReceiptReader{ - urls: urls, - clients: make(map[uint64]*ethclient.Client), - } -} - -func (r *rpcReceiptReader) ReceiptStatus(ctx context.Context, chainID uint64, txHash string) (receiptStatus, error) { - client, err := r.clientForChain(ctx, chainID) - if err != nil { - return receiptPending, err - } - receipt, err := client.TransactionReceipt(ctx, common.HexToHash(txHash)) - if err != nil { - if errors.Is(err, ethereum.NotFound) { - return receiptPending, nil - } - return receiptPending, err - } - if receipt.Status == 1 { - return receiptConfirmed, nil - } - return receiptFailed, nil -} - -func (r *rpcReceiptReader) clientForChain(ctx context.Context, chainID uint64) (*ethclient.Client, error) { - r.mu.Lock() - defer r.mu.Unlock() - - if client, ok := r.clients[chainID]; ok { - return client, nil - } - rawURL, ok := r.urls[chainID] - if !ok { - return nil, fmt.Errorf("no rpc configured for chain %d", chainID) - } - client, err := ethclient.DialContext(ctx, rawURL) - if err != nil { - return nil, err - } - r.clients[chainID] = client - return client, nil -} diff --git a/internal/service/node.go b/internal/service/node.go deleted file mode 100644 index a7e893f..0000000 --- a/internal/service/node.go +++ /dev/null @@ -1,60 +0,0 @@ -package service - -import ( - "context" - "fmt" - - "github.com/layer-3/nitrolite/pkg/core" -) - -// NodeService exposes read-only node metadata operations. -type NodeService struct { - provider clientProvider -} - -// NewNodeService constructs a NodeService. -func NewNodeService(provider clientProvider) *NodeService { - return &NodeService{provider: provider} -} - -// GetConfig retrieves clearnode configuration. -func (s *NodeService) GetConfig(ctx context.Context) (*core.NodeConfig, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - cfg, err := client.GetConfig(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get node config: %w", err) - } - return cfg, nil -} - -// GetBlockchains retrieves supported blockchains. -func (s *NodeService) GetBlockchains(ctx context.Context) ([]core.Blockchain, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - blockchains, err := client.GetBlockchains(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get blockchains: %w", err) - } - return blockchains, nil -} - -// GetAssets retrieves supported assets. -func (s *NodeService) GetAssets(ctx context.Context, blockchainID *uint64) ([]core.Asset, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - assets, err := client.GetAssets(ctx, blockchainID) - if err != nil { - return nil, fmt.Errorf("failed to get assets: %w", err) - } - return assets, nil -} diff --git a/internal/service/session_keys.go b/internal/service/session_keys.go deleted file mode 100644 index cda29cc..0000000 --- a/internal/service/session_keys.go +++ /dev/null @@ -1,255 +0,0 @@ -package service - -import ( - "context" - "sort" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" -) - -// NowFunc provides testable current-time injection. -type NowFunc func() time.Time - -// RegisterChannelSessionKeyRequest contains inputs for channel key registration. -type RegisterChannelSessionKeyRequest struct { - SessionKey string - Assets []string - ExpiresAt time.Time -} - -// RegisterAppSessionKeyRequest contains inputs for app key registration. -type RegisterAppSessionKeyRequest struct { - SessionKey string - ApplicationIDs []string - AppSessionIDs []string - ExpiresAt time.Time -} - -// SessionKeyService exposes session-key registration and listing. -type SessionKeyService struct { - provider clientProvider - now NowFunc -} - -// NewSessionKeyService constructs a SessionKeyService. -func NewSessionKeyService(provider clientProvider, now NowFunc) *SessionKeyService { - if now == nil { - now = time.Now - } - return &SessionKeyService{ - provider: provider, - now: now, - } -} - -// RegisterChannelKey registers a channel session key state. -func (s *SessionKeyService) RegisterChannelKey(ctx context.Context, req RegisterChannelSessionKeyRequest) (*core.ChannelSessionKeyStateV1, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - sessionKey, err := normalizeAddress(req.SessionKey) - if err != nil { - return nil, err - } - assets, err := normalizeAssets(req.Assets) - if err != nil { - return nil, err - } - if !req.ExpiresAt.After(s.now()) { - return nil, invalidf("expires_at must be in the future") - } - - existing, err := client.GetLastChannelKeyStates(ctx, signerAddress, &sdk.GetLastChannelKeyStatesOptions{ - SessionKey: &sessionKey, - }) - if err != nil { - return nil, err - } - - state := core.ChannelSessionKeyStateV1{ - UserAddress: signerAddress, - SessionKey: sessionKey, - Version: nextChannelSessionKeyVersion(existing, sessionKey), - Assets: assets, - ExpiresAt: req.ExpiresAt.UTC(), - } - sig, err := client.SignChannelSessionKeyState(state) - if err != nil { - return nil, err - } - state.UserSig = sig - if err := client.SubmitChannelSessionKeyState(ctx, state); err != nil { - return nil, err - } - return &state, nil -} - -// GetChannelKeys lists channel session key states. -func (s *SessionKeyService) GetChannelKeys(ctx context.Context, sessionKey *string) ([]core.ChannelSessionKeyStateV1, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - var opts *sdk.GetLastChannelKeyStatesOptions - if sessionKey != nil { - normalized, err := normalizeAddress(*sessionKey) - if err != nil { - return nil, err - } - opts = &sdk.GetLastChannelKeyStatesOptions{SessionKey: &normalized} - } - - states, err := client.GetLastChannelKeyStates(ctx, signerAddress, opts) - if err != nil { - return nil, err - } - return states, nil -} - -// RegisterAppKey registers an app session key state. -func (s *SessionKeyService) RegisterAppKey(ctx context.Context, req RegisterAppSessionKeyRequest) (*app.AppSessionKeyStateV1, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - sessionKey, err := normalizeAddress(req.SessionKey) - if err != nil { - return nil, err - } - applicationIDs := normalizeStringList(req.ApplicationIDs) - appSessionIDs := normalizeStringList(req.AppSessionIDs) - if len(applicationIDs) == 0 && len(appSessionIDs) == 0 { - return nil, invalidf("application_ids or app_session_ids must not be empty") - } - if !req.ExpiresAt.After(s.now()) { - return nil, invalidf("expires_at must be in the future") - } - - existing, err := client.GetLastAppKeyStates(ctx, signerAddress, &sdk.GetLastKeyStatesOptions{ - SessionKey: &sessionKey, - }) - if err != nil { - return nil, err - } - - state := app.AppSessionKeyStateV1{ - UserAddress: signerAddress, - SessionKey: sessionKey, - Version: nextAppSessionKeyVersion(existing, sessionKey), - ApplicationIDs: applicationIDs, - AppSessionIDs: appSessionIDs, - ExpiresAt: req.ExpiresAt.UTC(), - } - sig, err := client.SignSessionKeyState(state) - if err != nil { - return nil, err - } - state.UserSig = sig - if err := client.SubmitAppSessionKeyState(ctx, state); err != nil { - return nil, err - } - return &state, nil -} - -// GetAppKeys lists app session key states. -func (s *SessionKeyService) GetAppKeys(ctx context.Context, sessionKey *string) ([]app.AppSessionKeyStateV1, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return nil, err - } - - var opts *sdk.GetLastKeyStatesOptions - if sessionKey != nil { - normalized, err := normalizeAddress(*sessionKey) - if err != nil { - return nil, err - } - opts = &sdk.GetLastKeyStatesOptions{SessionKey: &normalized} - } - - states, err := client.GetLastAppKeyStates(ctx, signerAddress, opts) - if err != nil { - return nil, err - } - return states, nil -} - -func normalizeAddress(raw string) (string, error) { - trimmed := strings.TrimSpace(raw) - if trimmed == "" { - return "", invalidf("session_key is required") - } - if !common.IsHexAddress(trimmed) { - return "", invalidf("invalid session_key") - } - return strings.ToLower(trimmed), nil -} - -func normalizeAssets(assets []string) ([]string, error) { - normalized := normalizeStringList(assets) - if len(normalized) == 0 { - return nil, invalidf("assets must not be empty") - } - for i := range normalized { - normalized[i] = strings.ToLower(normalized[i]) - } - sort.Strings(normalized) - return uniqueStrings(normalized), nil -} - -func normalizeStringList(values []string) []string { - out := make([]string, 0, len(values)) - for _, value := range values { - trimmed := strings.TrimSpace(value) - if trimmed == "" { - continue - } - out = append(out, trimmed) - } - sort.Strings(out) - return uniqueStrings(out) -} - -func uniqueStrings(values []string) []string { - if len(values) == 0 { - return values - } - out := make([]string, 0, len(values)) - var prev string - for i, value := range values { - if i == 0 || value != prev { - out = append(out, value) - } - prev = value - } - return out -} - -func nextChannelSessionKeyVersion(existing []core.ChannelSessionKeyStateV1, sessionKey string) uint64 { - var max uint64 - for _, state := range existing { - if strings.EqualFold(state.SessionKey, sessionKey) && state.Version > max { - max = state.Version - } - } - return max + 1 -} - -func nextAppSessionKeyVersion(existing []app.AppSessionKeyStateV1, sessionKey string) uint64 { - var max uint64 - for _, state := range existing { - if strings.EqualFold(state.SessionKey, sessionKey) && state.Version > max { - max = state.Version - } - } - return max + 1 -} diff --git a/internal/service/session_keys_test.go b/internal/service/session_keys_test.go deleted file mode 100644 index 2cfdb0d..0000000 --- a/internal/service/session_keys_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package service - -import ( - "context" - "log/slog" - "testing" - "time" - - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" - "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" - sdk "github.com/layer-3/nitrolite/sdk/go" -) - -func TestSessionKeyHelpers(t *testing.T) { - t.Parallel() - - assets, err := normalizeAssets([]string{"weth", "usdc", "weth"}) - if err != nil { - t.Fatalf("normalizeAssets() error = %v", err) - } - if len(assets) != 2 || assets[0] != "usdc" || assets[1] != "weth" { - t.Fatalf("assets = %#v", assets) - } - - if got := nextChannelSessionKeyVersion([]core.ChannelSessionKeyStateV1{ - {SessionKey: "0x1", Version: 1}, - {SessionKey: "0x1", Version: 3}, - }, "0x1"); got != 4 { - t.Fatalf("nextChannelSessionKeyVersion() = %d, want 4", got) - } - if got := nextAppSessionKeyVersion([]app.AppSessionKeyStateV1{ - {SessionKey: "0x1", Version: 2}, - }, "0x1"); got != 3 { - t.Fatalf("nextAppSessionKeyVersion() = %d, want 3", got) - } -} - -func TestSessionKeyService_RegisterAndList(t *testing.T) { - t.Parallel() - - now := time.Date(2026, 4, 14, 12, 0, 0, 0, time.UTC) - sessionKey := "0x1111111111111111111111111111111111111111" - client := &testsupport.FakeClient{ - GetUserAddressFunc: func() string { return serviceTestAddress }, - GetLastChannelKeyStatesFunc: func(ctx context.Context, userAddress string, opts *sdk.GetLastChannelKeyStatesOptions) ([]core.ChannelSessionKeyStateV1, error) { - return []core.ChannelSessionKeyStateV1{{SessionKey: sessionKey, Version: 1}}, nil - }, - SignChannelSessionKeyStateFunc: func(state core.ChannelSessionKeyStateV1) (string, error) { - return "0xchannelsig", nil - }, - SubmitChannelSessionKeyStateFunc: func(ctx context.Context, state core.ChannelSessionKeyStateV1) error { - return nil - }, - GetLastAppKeyStatesFunc: func(ctx context.Context, userAddress string, opts *sdk.GetLastKeyStatesOptions) ([]app.AppSessionKeyStateV1, error) { - return []app.AppSessionKeyStateV1{{SessionKey: sessionKey, Version: 2}}, nil - }, - SignSessionKeyStateFunc: func(state app.AppSessionKeyStateV1) (string, error) { - return "0xappsig", nil - }, - SubmitAppSessionKeyStateFunc: func(ctx context.Context, state app.AppSessionKeyStateV1) error { - return nil - }, - } - manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ - Connected: true, - Ready: true, - SignerAddress: serviceTestAddress, - }, slog.Default()) - svc := NewSessionKeyService(manager, func() time.Time { return now }) - - channelState, err := svc.RegisterChannelKey(context.Background(), RegisterChannelSessionKeyRequest{ - SessionKey: sessionKey, - Assets: []string{"weth", "usdc", "weth"}, - ExpiresAt: now.Add(time.Hour), - }) - if err != nil { - t.Fatalf("RegisterChannelKey() error = %v", err) - } - if channelState.Version != 2 || channelState.UserSig != "0xchannelsig" { - t.Fatalf("channelState = %#v", channelState) - } - - appState, err := svc.RegisterAppKey(context.Background(), RegisterAppSessionKeyRequest{ - SessionKey: sessionKey, - ApplicationIDs: []string{"demo-app", "demo-app"}, - ExpiresAt: now.Add(time.Hour), - }) - if err != nil { - t.Fatalf("RegisterAppKey() error = %v", err) - } - if appState.Version != 3 || appState.UserSig != "0xappsig" { - t.Fatalf("appState = %#v", appState) - } -} diff --git a/internal/service/store_app.go b/internal/service/store_app.go deleted file mode 100644 index 18339f8..0000000 --- a/internal/service/store_app.go +++ /dev/null @@ -1,741 +0,0 @@ -package service - -import ( - "context" - "encoding/json" - "fmt" - "sort" - "strings" - "time" - - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/layer-3/nitrolite/pkg/app" - sdk "github.com/layer-3/nitrolite/sdk/go" - "github.com/shopspring/decimal" -) - -const ( - storeActionDeposit = "deposit" - storeActionPurchase = "purchase" - storeActionUserWithdraw = "user_withdraw" - storeActionAppWithdraw = "app_withdraw" -) - -type StoreCatalogItem struct { - ID string `json:"id"` - Title string `json:"title"` - Description string `json:"description"` - Type string `json:"type"` - Prices map[string]string `json:"prices"` - Content string `json:"content,omitempty"` -} - -type StoreAction string - -const ( - ActionDeposit StoreAction = "deposit" - ActionPurchase StoreAction = "purchase" - ActionUserWithdraw StoreAction = "user_withdraw" - ActionAppWithdraw StoreAction = "app_withdraw" -) - -type StoreSessionData struct { - Action StoreAction `json:"action"` - Amount string `json:"amount,omitempty"` - ItemID string `json:"item_id,omitempty"` - Price string `json:"price,omitempty"` -} - -type StoreConfigResponse struct { - StoreName string `json:"store_name"` - AppID string `json:"app_id"` - AppSigner string `json:"app_signer"` - UserSigner string `json:"user_signer"` - DefaultAsset string `json:"default_asset"` - SupportedAssets []string `json:"supported_assets"` - Catalog []StoreCatalogItem `json:"catalog"` -} - -type StoreSessionSummary struct { - BrowserSessionID string `json:"-"` - Asset string `json:"asset"` - AppSessionID string `json:"app_session_id"` - Status string `json:"status"` - Version uint64 `json:"version"` - UserAllocation string `json:"user_allocation"` - AppAllocation string `json:"app_allocation"` - SessionData string `json:"session_data"` - AvailableBalance string `json:"available_balance"` - Purchases []store.Purchase `json:"purchases"` -} - -type StoreStateRequest struct { - SessionID string `json:"session_id"` - Asset string `json:"asset"` - SessionData string `json:"session_data"` -} - -type StorefrontService struct { - provider clientProvider - store *store.Store - userSigner appsigning.Signer - appSigner appsigning.Signer - storeName string - appID string - supportedAssets []string - defaultAsset string - catalog []StoreCatalogItem - now func() time.Time -} - -func NewStorefrontService(provider clientProvider, appStore *store.Store, userSigner appsigning.Signer, appSigner appsigning.Signer, storeName string, appID string, homeBlockchains map[string]uint64) *StorefrontService { - assets := sortedAssets(homeBlockchains) - defaultAsset := "yusd" - if len(assets) > 0 { - defaultAsset = assets[0] - for _, asset := range assets { - if asset == "yusd" { - defaultAsset = asset - break - } - } - } - - return &StorefrontService{ - provider: provider, - store: appStore, - userSigner: userSigner, - appSigner: appSigner, - storeName: strings.TrimSpace(storeName), - appID: strings.TrimSpace(appID), - supportedAssets: assets, - defaultAsset: defaultAsset, - catalog: seededCatalog(), - now: time.Now, - } -} - -func (s *StorefrontService) Config() StoreConfigResponse { - return StoreConfigResponse{ - StoreName: s.storeName, - AppID: s.appID, - AppSigner: s.appSigner.Address(), - UserSigner: s.userSigner.Address(), - DefaultAsset: s.defaultAsset, - SupportedAssets: append([]string(nil), s.supportedAssets...), - Catalog: cloneCatalogForAPI(s.catalog), - } -} - -func (s *StorefrontService) Catalog(asset string) ([]StoreCatalogItem, error) { - asset, err := s.normalizeAsset(asset) - if err != nil { - return nil, err - } - - out := make([]StoreCatalogItem, 0, len(s.catalog)) - for _, item := range s.catalog { - if _, ok := item.Prices[asset]; ok { - copyItem := item - copyItem.Prices = map[string]string{asset: item.Prices[asset]} - copyItem.Content = "" - out = append(out, copyItem) - } - } - return out, nil -} - -func (s *StorefrontService) CatalogItem(asset string, id string) (*StoreCatalogItem, error) { - asset, err := s.normalizeAsset(asset) - if err != nil { - return nil, err - } - - item := s.catalogItem(id) - if item == nil { - return nil, notFoundf("catalog item not found") - } - price, ok := item.Prices[asset] - if !ok { - return nil, invalidf("asset not supported for item") - } - copyItem := *item - copyItem.Prices = map[string]string{asset: price} - copyItem.Content = "" - return ©Item, nil -} - -func (s *StorefrontService) Content(ctx context.Context, browserSessionID string, asset string, id string) (*StoreCatalogItem, error) { - asset, err := s.normalizeAsset(asset) - if err != nil { - return nil, err - } - item := s.catalogItem(id) - if item == nil { - return nil, notFoundf("catalog item not found") - } - owned, err := s.store.HasPurchase(ctx, browserSessionID, id, asset) - if err != nil { - return nil, fmt.Errorf("failed to check purchase: %w", err) - } - if !owned { - return nil, conflictf("item not purchased") - } - copyItem := *item - copyItem.Prices = map[string]string{asset: item.Prices[asset]} - return ©Item, nil -} - -func (s *StorefrontService) GetSession(ctx context.Context, browserSessionID string, asset string) (*StoreSessionSummary, error) { - asset, err := s.normalizeAsset(asset) - if err != nil { - return nil, err - } - - stored, err := s.store.GetStoreSession(ctx, browserSessionID, asset) - if err != nil { - if err == store.ErrNotFound { - balance, balErr := s.availableBalance(ctx, asset) - if balErr != nil { - return nil, balErr - } - return &StoreSessionSummary{ - BrowserSessionID: browserSessionID, - Asset: asset, - Status: "missing", - AvailableBalance: balance, - }, nil - } - return nil, fmt.Errorf("failed to load store session: %w", err) - } - - current, err := s.lookupSession(ctx, stored.AppSessionID) - if err != nil { - return nil, err - } - summary, err := s.summaryFromAppSession(ctx, browserSessionID, asset, *current) - if err != nil { - return nil, err - } - return summary, nil -} - -func (s *StorefrontService) CreateSession(ctx context.Context, browserSessionID string, asset string) (*StoreSessionSummary, error) { - asset, err := s.normalizeAsset(asset) - if err != nil { - return nil, err - } - - existing, err := s.store.GetStoreSession(ctx, browserSessionID, asset) - if err == nil && existing != nil { - return s.GetSession(ctx, browserSessionID, asset) - } - if err != nil && err != store.ErrNotFound { - return nil, fmt.Errorf("failed to check store session: %w", err) - } - - if err := s.ensureApp(ctx); err != nil { - return nil, err - } - - definition := app.AppDefinitionV1{ - ApplicationID: s.appID, - Participants: []app.AppParticipantV1{ - {WalletAddress: s.userSigner.Address(), SignatureWeight: 1}, - {WalletAddress: s.appSigner.Address(), SignatureWeight: 1}, - }, - Quorum: 2, - Nonce: uint64(s.now().UTC().UnixNano()), - } - sessionData := mustJSONString(map[string]string{"action": "deposit", "amount": "0", "asset": asset}) - - userSig, err := signCreateAppSessionRequest(definition, sessionData, s.userSigner) - if err != nil { - return nil, err - } - appSig, err := signCreateAppSessionRequest(definition, sessionData, s.appSigner) - if err != nil { - return nil, err - } - - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - sessionID, versionRaw, status, err := client.CreateAppSession(ctx, definition, sessionData, []string{userSig, appSig}) - if err != nil { - return nil, fmt.Errorf("failed to create app session: %w", err) - } - version, err := parseDecimalVersion(versionRaw) - if err != nil { - return nil, err - } - - now := s.now().UTC() - record := store.StoreSession{ - BrowserSessionID: browserSessionID, - Asset: asset, - AppSessionID: sessionID, - Status: status, - Version: version, - UserAllocation: "0", - AppAllocation: "0", - SessionData: sessionData, - CreatedAt: now, - UpdatedAt: now, - } - if err := s.store.UpsertStoreSession(ctx, record); err != nil { - return nil, fmt.Errorf("failed to persist store session: %w", err) - } - - return s.GetSession(ctx, browserSessionID, asset) -} - -func (s *StorefrontService) SubmitState(ctx context.Context, browserSessionID string, req StoreStateRequest, allowAppWithdraw bool) (*StoreSessionSummary, error) { - asset, err := s.normalizeAsset(req.Asset) - if err != nil { - return nil, err - } - stored, err := s.store.GetStoreSession(ctx, browserSessionID, asset) - if err != nil { - if err == store.ErrNotFound { - return nil, notFoundf("store session not found") - } - return nil, fmt.Errorf("failed to load store session: %w", err) - } - if strings.TrimSpace(req.SessionID) != "" && !strings.EqualFold(strings.TrimSpace(req.SessionID), stored.AppSessionID) { - return nil, conflictf("session_id does not match active store session") - } - var sessionData StoreSessionData - if err := json.Unmarshal([]byte(strings.TrimSpace(req.SessionData)), &sessionData); err != nil { - return nil, invalidf("invalid session_data") - } - - current, err := s.lookupSession(ctx, stored.AppSessionID) - if err != nil { - return nil, err - } - - switch sessionData.Action { - case ActionDeposit: - return s.handleDeposit(ctx, browserSessionID, asset, *current, sessionData) - case ActionPurchase: - return s.handlePurchase(ctx, browserSessionID, asset, *current, sessionData) - case ActionUserWithdraw: - return s.handleWithdraw(ctx, browserSessionID, asset, *current, sessionData, false) - case ActionAppWithdraw: - if !allowAppWithdraw { - return nil, conflictf("app_withdraw is only available from hidden developer controls") - } - return s.handleWithdraw(ctx, browserSessionID, asset, *current, sessionData, true) - default: - return nil, invalidf("invalid action") - } -} - -func (s *StorefrontService) handleDeposit(ctx context.Context, browserSessionID string, asset string, current app.AppSessionInfoV1, sessionData StoreSessionData) (*StoreSessionSummary, error) { - amount, err := parsePositiveAmount(sessionData.Amount) - if err != nil { - return nil, err - } - update, err := buildDepositUpdate(current, s.userSigner.Address(), asset, amount) - if err != nil { - return nil, err - } - update.SessionData = mustJSONString(StoreSessionData{ - Action: ActionDeposit, - Amount: amount.StringFixedBank(2), - }) - - sigs, err := s.signQuorumUpdate(update) - if err != nil { - return nil, err - } - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - if _, err := client.SubmitAppSessionDeposit(ctx, update, sigs, asset, amount); err != nil { - return nil, fmt.Errorf("failed to submit deposit state: %w", err) - } - return s.persistAndSummarize(ctx, browserSessionID, asset, update) -} - -func (s *StorefrontService) handlePurchase(ctx context.Context, browserSessionID string, asset string, current app.AppSessionInfoV1, sessionData StoreSessionData) (*StoreSessionSummary, error) { - item := s.catalogItem(sessionData.ItemID) - if item == nil { - return nil, notFoundf("catalog item not found") - } - priceRaw, ok := item.Prices[asset] - if !ok { - return nil, invalidf("asset not supported for item") - } - price, err := decimal.NewFromString(priceRaw) - if err != nil { - return nil, invalidf("invalid catalog price") - } - if strings.TrimSpace(sessionData.Price) != "" && sessionData.Price != price.StringFixedBank(2) { - return nil, conflictf("session_data price does not match catalog price") - } - owned, err := s.store.HasPurchase(ctx, browserSessionID, item.ID, asset) - if err != nil { - return nil, fmt.Errorf("failed to check duplicate purchase: %w", err) - } - if owned { - return nil, conflictf("item already purchased") - } - - userAmount, appAmount := balancesForAsset(current.Allocations, s.userSigner.Address(), s.appSigner.Address(), asset) - if userAmount.LessThan(price) { - return nil, conflictf("insufficient store balance") - } - - update := app.AppStateUpdateV1{ - AppSessionID: current.AppSessionID, - Intent: app.AppStateUpdateIntentOperate, - Version: current.Version + 1, - Allocations: []app.AppAllocationV1{ - {Participant: s.appSigner.Address(), Asset: asset, Amount: appAmount.Add(price)}, - {Participant: s.userSigner.Address(), Asset: asset, Amount: userAmount.Sub(price)}, - }, - SessionData: mustJSONString(StoreSessionData{ - Action: ActionPurchase, - ItemID: item.ID, - Price: price.StringFixedBank(2), - }), - } - sortAppAllocations(update.Allocations) - - sigs, err := s.signQuorumUpdate(update) - if err != nil { - return nil, err - } - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - if err := client.SubmitAppState(ctx, update, sigs); err != nil { - return nil, fmt.Errorf("failed to submit purchase state: %w", err) - } - if err := s.store.RecordPurchase(ctx, store.Purchase{ - ID: fmt.Sprintf("%s:%s:%s", browserSessionID, asset, item.ID), - BrowserSessionID: browserSessionID, - ItemID: item.ID, - Asset: asset, - AppSessionID: current.AppSessionID, - Version: update.Version, - PurchasedAt: s.now().UTC(), - }); err != nil { - if err == store.ErrConflict { - return nil, conflictf("item already purchased") - } - return nil, fmt.Errorf("failed to record purchase: %w", err) - } - return s.persistAndSummarize(ctx, browserSessionID, asset, update) -} - -func (s *StorefrontService) handleWithdraw(ctx context.Context, browserSessionID string, asset string, current app.AppSessionInfoV1, sessionData StoreSessionData, appWithdraw bool) (*StoreSessionSummary, error) { - amount, err := parsePositiveAmount(sessionData.Amount) - if err != nil { - return nil, err - } - userAmount, appAmount := balancesForAsset(current.Allocations, s.userSigner.Address(), s.appSigner.Address(), asset) - - intent := ActionUserWithdraw - allocations := []app.AppAllocationV1{ - {Participant: s.appSigner.Address(), Asset: asset, Amount: appAmount}, - {Participant: s.userSigner.Address(), Asset: asset, Amount: userAmount}, - } - if appWithdraw { - intent = ActionAppWithdraw - if appAmount.LessThan(amount) { - return nil, conflictf("app allocation is too low") - } - allocations[0].Amount = appAmount.Sub(amount) - } else { - if userAmount.LessThan(amount) { - return nil, conflictf("user allocation is too low") - } - allocations[1].Amount = userAmount.Sub(amount) - } - - update := app.AppStateUpdateV1{ - AppSessionID: current.AppSessionID, - Intent: app.AppStateUpdateIntentWithdraw, - Version: current.Version + 1, - Allocations: allocations, - SessionData: mustJSONString(StoreSessionData{ - Action: intent, - Amount: amount.StringFixedBank(2), - }), - } - sortAppAllocations(update.Allocations) - - sigs, err := s.signQuorumUpdate(update) - if err != nil { - return nil, err - } - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - if err := client.SubmitAppState(ctx, update, sigs); err != nil { - return nil, fmt.Errorf("failed to submit withdraw state: %w", err) - } - return s.persistAndSummarize(ctx, browserSessionID, asset, update) -} - -func (s *StorefrontService) persistAndSummarize(ctx context.Context, browserSessionID string, asset string, update app.AppStateUpdateV1) (*StoreSessionSummary, error) { - userAmount, appAmount := balancesForAsset(update.Allocations, s.userSigner.Address(), s.appSigner.Address(), asset) - now := s.now().UTC() - record := store.StoreSession{ - BrowserSessionID: browserSessionID, - Asset: asset, - AppSessionID: update.AppSessionID, - Status: "open", - Version: update.Version, - UserAllocation: userAmount.String(), - AppAllocation: appAmount.String(), - SessionData: update.SessionData, - CreatedAt: now, - UpdatedAt: now, - } - if err := s.store.UpsertStoreSession(ctx, record); err != nil { - return nil, fmt.Errorf("failed to update store session: %w", err) - } - return s.GetSession(ctx, browserSessionID, asset) -} - -func (s *StorefrontService) summaryFromAppSession(ctx context.Context, browserSessionID string, asset string, current app.AppSessionInfoV1) (*StoreSessionSummary, error) { - userAmount, appAmount := balancesForAsset(current.Allocations, s.userSigner.Address(), s.appSigner.Address(), asset) - now := s.now().UTC() - record := store.StoreSession{ - BrowserSessionID: browserSessionID, - Asset: asset, - AppSessionID: current.AppSessionID, - Status: openClosedStatus(current.IsClosed), - Version: current.Version, - UserAllocation: userAmount.String(), - AppAllocation: appAmount.String(), - SessionData: current.SessionData, - CreatedAt: now, - UpdatedAt: now, - } - if err := s.store.UpsertStoreSession(ctx, record); err != nil { - return nil, fmt.Errorf("failed to sync store session: %w", err) - } - availableBalance, err := s.availableBalance(ctx, asset) - if err != nil { - return nil, err - } - purchases, err := s.store.ListPurchasesByBrowser(ctx, browserSessionID, asset) - if err != nil { - return nil, fmt.Errorf("failed to list purchases: %w", err) - } - return &StoreSessionSummary{ - BrowserSessionID: browserSessionID, - Asset: asset, - AppSessionID: current.AppSessionID, - Status: openClosedStatus(current.IsClosed), - Version: current.Version, - UserAllocation: userAmount.String(), - AppAllocation: appAmount.String(), - SessionData: current.SessionData, - AvailableBalance: availableBalance, - Purchases: purchases, - }, nil -} - -func (s *StorefrontService) availableBalance(ctx context.Context, asset string) (string, error) { - client, signerAddress, err := activeClient(s.provider) - if err != nil { - return "", err - } - balances, err := client.GetBalances(ctx, signerAddress) - if err != nil { - return "", fmt.Errorf("failed to get balances: %w", err) - } - for _, entry := range balances { - if strings.EqualFold(entry.Asset, asset) { - return entry.Balance.String(), nil - } - } - return "0", nil -} - -func (s *StorefrontService) lookupSession(ctx context.Context, sessionID string) (*app.AppSessionInfoV1, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - opts := &sdk.GetAppSessionsOptions{AppSessionID: &sessionID} - sessions, _, err := client.GetAppSessions(ctx, opts) - if err != nil { - return nil, fmt.Errorf("failed to get app sessions: %w", err) - } - for _, session := range sessions { - if session.AppSessionID == sessionID { - return &session, nil - } - } - return nil, notFoundf("session not found") -} - -func (s *StorefrontService) ensureApp(ctx context.Context) error { - client, _, err := activeClient(s.provider) - if err != nil { - return err - } - opts := &sdk.GetAppsOptions{AppID: &s.appID} - apps, _, err := client.GetApps(ctx, opts) - if err != nil { - return fmt.Errorf("failed to get apps: %w", err) - } - for _, info := range apps { - if info.App.ID == s.appID { - return nil - } - } - if err := client.RegisterApp(ctx, s.appID, `{"product":"store"}`, true); err != nil { - return fmt.Errorf("failed to register store app: %w", err) - } - return nil -} - -func (s *StorefrontService) signQuorumUpdate(update app.AppStateUpdateV1) ([]string, error) { - userSig, err := signAppStateUpdate(update, s.userSigner) - if err != nil { - return nil, err - } - appSig, err := signAppStateUpdate(update, s.appSigner) - if err != nil { - return nil, err - } - return []string{userSig, appSig}, nil -} - -func (s *StorefrontService) normalizeAsset(raw string) (string, error) { - asset := strings.ToLower(strings.TrimSpace(raw)) - if asset == "" { - asset = s.defaultAsset - } - for _, supported := range s.supportedAssets { - if asset == supported { - return asset, nil - } - } - return "", invalidf("unsupported asset") -} - -func (s *StorefrontService) catalogItem(id string) *StoreCatalogItem { - id = strings.TrimSpace(id) - for i := range s.catalog { - if s.catalog[i].ID == id { - return &s.catalog[i] - } - } - return nil -} - -func cloneCatalogForAPI(in []StoreCatalogItem) []StoreCatalogItem { - out := make([]StoreCatalogItem, 0, len(in)) - for _, item := range in { - copyItem := item - copyItem.Content = "" - priceMap := make(map[string]string, len(item.Prices)) - for asset, price := range item.Prices { - priceMap[asset] = price - } - copyItem.Prices = priceMap - out = append(out, copyItem) - } - return out -} - -func sortedAssets(homeBlockchains map[string]uint64) []string { - out := make([]string, 0, len(homeBlockchains)) - for asset := range homeBlockchains { - out = append(out, strings.ToLower(strings.TrimSpace(asset))) - } - sort.Strings(out) - return out -} - -func parsePositiveAmount(raw string) (decimal.Decimal, error) { - amount, err := decimal.NewFromString(strings.TrimSpace(raw)) - if err != nil { - return decimal.Decimal{}, invalidf("invalid amount") - } - if !amount.IsPositive() { - return decimal.Decimal{}, invalidf("amount must be positive") - } - return amount, nil -} - -func balancesForAsset(allocations []app.AppAllocationV1, userAddress string, appAddress string, asset string) (decimal.Decimal, decimal.Decimal) { - userAmount := decimal.Zero - appAmount := decimal.Zero - for _, allocation := range allocations { - if !strings.EqualFold(allocation.Asset, asset) { - continue - } - switch { - case strings.EqualFold(allocation.Participant, userAddress): - userAmount = allocation.Amount - case strings.EqualFold(allocation.Participant, appAddress): - appAmount = allocation.Amount - } - } - return userAmount, appAmount -} - -func openClosedStatus(isClosed bool) string { - if isClosed { - return "closed" - } - return "open" -} - -func mustJSONString(value any) string { - payload, _ := json.Marshal(value) - return string(payload) -} - -func seededCatalog() []StoreCatalogItem { - return []StoreCatalogItem{ - { - ID: "book-go-101", - Title: "Go Systems Handbook", - Description: "A practical field guide to Go services, interfaces, and runtime behavior.", - Type: "book", - Prices: map[string]string{ - "yellow": "4.50", - "yusd": "2.50", - }, - Content: "Go Systems Handbook\n\nThis sample chapter walks through interfaces, runtime lifecycles, and debugging patterns for long-running services.", - }, - { - ID: "magazine-state-channels", - Title: "State Channel Monthly", - Description: "A lightweight magazine issue about channels, signatures, and settlement UX.", - Type: "magazine", - Prices: map[string]string{ - "yellow": "2.00", - "yusd": "1.00", - }, - Content: "State Channel Monthly\n\nFeature stories on settlement rails, app sessions, and why product UX should hide protocol noise.", - }, - { - ID: "article-micropayments", - Title: "Designing Instant Micropayments", - Description: "Short-form reading on instant purchases and content gating with app sessions.", - Type: "article", - Prices: map[string]string{ - "yellow": "0.75", - "yusd": "0.50", - }, - Content: "Designing Instant Micropayments\n\nMicropayment UX succeeds when top-level product actions stay simple and settlement details remain observable but hidden.", - }, - } -} diff --git a/internal/service/store_catalog.go b/internal/service/store_catalog.go new file mode 100644 index 0000000..1c9a240 --- /dev/null +++ b/internal/service/store_catalog.go @@ -0,0 +1,278 @@ +package service + +import ( + "encoding/json" + "sort" + "strings" + + "github.com/layer-3/nitrolite/pkg/app" + "github.com/shopspring/decimal" +) + +type StoreCatalogItem struct { + ID string `json:"id"` + Title string `json:"title"` + Description string `json:"description"` + Type string `json:"type"` + Prices map[string]string `json:"prices"` + Content string `json:"content,omitempty"` +} + +type StoreSessionIntent string + +const ( + StoreIntentUserDeposit StoreSessionIntent = "user_deposit" + StoreIntentPurchase StoreSessionIntent = "purchase" + StoreIntentUserWithdraw StoreSessionIntent = "user_withdraw" +) + +type StoreSessionData struct { + Intent StoreSessionIntent `json:"intent"` + Amount string `json:"amount,omitempty"` + ItemID json.RawMessage `json:"item_id,omitempty"` + ItemPrice string `json:"item_price,omitempty"` +} + +func sortedAssets(homeBlockchains map[string]uint64) []string { + out := make([]string, 0, len(homeBlockchains)) + for asset := range homeBlockchains { + out = append(out, strings.ToLower(strings.TrimSpace(asset))) + } + sort.Strings(out) + return out +} + +func supportedStoreAssets(homeBlockchains map[string]uint64) []string { + configured := make(map[string]struct{}, len(homeBlockchains)) + for _, asset := range sortedAssets(homeBlockchains) { + configured[asset] = struct{}{} + } + + out := make([]string, 0, 2) + for _, asset := range []string{"yusd", "yellow"} { + if _, ok := configured[asset]; ok { + out = append(out, asset) + } + } + if len(out) == 0 { + out = append(out, "yusd") + } + return out +} + +func normalizeHomeBlockchains(homeBlockchains map[string]uint64) map[string]uint64 { + out := make(map[string]uint64, len(homeBlockchains)) + for asset, chainID := range homeBlockchains { + normalized := strings.ToLower(strings.TrimSpace(asset)) + if normalized == "" { + continue + } + out[normalized] = chainID + } + return out +} + +func defaultChannelBootstrapAmounts() map[string]string { + return map[string]string{ + "yusd": "10", + "yellow": "10", + } +} + +func normalizeChannelBootstrapAmounts(raw map[string]string) map[string]string { + out := defaultChannelBootstrapAmounts() + for asset, amount := range raw { + normalized := strings.ToLower(strings.TrimSpace(asset)) + amount = strings.TrimSpace(amount) + if normalized == "" || amount == "" { + continue + } + out[normalized] = amount + } + return out +} + +func (s *WalletStoreService) channelBootstrapAmount(asset string) string { + if amount := strings.TrimSpace(s.channelBootstrapAmounts[strings.ToLower(strings.TrimSpace(asset))]); amount != "" { + return amount + } + return "10" +} + +func strictBalancesForAsset(allocations []app.AppAllocationV1, userAddress string, appAddress string, asset string) (decimal.Decimal, decimal.Decimal, error) { + if len(allocations) != 2 { + return decimal.Zero, decimal.Zero, conflictf("app allocations must contain exactly wallet and app signer") + } + + userAmount := decimal.Zero + appAmount := decimal.Zero + seenUser := false + seenApp := false + for _, allocation := range allocations { + if !strings.EqualFold(allocation.Asset, asset) { + return decimal.Zero, decimal.Zero, conflictf("app allocation asset does not match selected asset") + } + if allocation.Amount.IsNegative() { + return decimal.Zero, decimal.Zero, conflictf("app allocation amount cannot be negative") + } + switch { + case strings.EqualFold(allocation.Participant, userAddress): + if seenUser { + return decimal.Zero, decimal.Zero, conflictf("duplicate wallet allocation") + } + seenUser = true + userAmount = allocation.Amount + case strings.EqualFold(allocation.Participant, appAddress): + if seenApp { + return decimal.Zero, decimal.Zero, conflictf("duplicate app signer allocation") + } + seenApp = true + appAmount = allocation.Amount + default: + return decimal.Zero, decimal.Zero, conflictf("unexpected app allocation participant") + } + } + if !seenUser || !seenApp { + return decimal.Zero, decimal.Zero, conflictf("app allocations must include wallet and app signer") + } + return userAmount, appAmount, nil +} + +func displayBalancesForAsset(allocations []app.AppAllocationV1, userAddress string, appAddress string, asset string) (decimal.Decimal, decimal.Decimal) { + userAmount := decimal.Zero + appAmount := decimal.Zero + for _, allocation := range allocations { + if !strings.EqualFold(allocation.Asset, asset) || allocation.Amount.IsNegative() { + continue + } + switch { + case strings.EqualFold(allocation.Participant, userAddress): + userAmount = userAmount.Add(allocation.Amount) + case strings.EqualFold(allocation.Participant, appAddress): + appAmount = appAmount.Add(allocation.Amount) + } + } + return userAmount, appAmount +} + +func currentBalancesForAsset(allocations []app.AppAllocationV1, userAddress string, appAddress string, asset string) (decimal.Decimal, decimal.Decimal, error) { + userAmount := decimal.Zero + appAmount := decimal.Zero + seenUser := false + seenApp := false + for _, allocation := range allocations { + if !strings.EqualFold(allocation.Asset, asset) { + continue + } + if allocation.Amount.IsNegative() { + return decimal.Zero, decimal.Zero, conflictf("app allocation amount cannot be negative") + } + switch { + case strings.EqualFold(allocation.Participant, userAddress): + if seenUser { + return decimal.Zero, decimal.Zero, conflictf("duplicate wallet allocation") + } + seenUser = true + userAmount = allocation.Amount + case strings.EqualFold(allocation.Participant, appAddress): + if seenApp { + return decimal.Zero, decimal.Zero, conflictf("duplicate app signer allocation") + } + seenApp = true + appAmount = allocation.Amount + default: + return decimal.Zero, decimal.Zero, conflictf("unexpected app allocation participant") + } + } + return userAmount, appAmount, nil +} + +func openClosedStatus(isClosed bool) string { + if isClosed { + return "closed" + } + return "open" +} + +func sessionDataItemID(raw json.RawMessage) (string, error) { + trimmed := strings.TrimSpace(string(raw)) + if trimmed == "" { + return "", invalidf("purchase session_data.item_id is required") + } + + var asString string + if err := json.Unmarshal(raw, &asString); err == nil { + asString = strings.TrimSpace(asString) + if asString == "" { + return "", invalidf("purchase session_data.item_id is required") + } + return asString, nil + } + + var asNumber json.Number + if err := json.Unmarshal(raw, &asNumber); err == nil { + return asNumber.String(), nil + } + + return "", invalidf("purchase session_data.item_id must be a string or number") +} + +func seededCatalog() []StoreCatalogItem { + return []StoreCatalogItem{ + { + ID: "1", + Title: "Designing Instant Micropayments", + Description: "Short-form reading on instant purchases and content gating with app sessions.", + Type: "article", + Prices: map[string]string{ + "yellow": "1.35", + "yusd": "0.9", + }, + Content: "Designing Instant Micropayments\n\nMicropayment UX succeeds when top-level product actions stay simple and settlement details remain observable but hidden.", + }, + { + ID: "2", + Title: "State Channel Monthly", + Description: "A lightweight issue about channels, signatures, and settlement UX.", + Type: "magazine", + Prices: map[string]string{ + "yellow": "2.00", + "yusd": "1.00", + }, + Content: "State Channel Monthly\n\nFeature stories on settlement rails, app sessions, and why product UX should hide protocol noise.", + }, + { + ID: "3", + Title: "Nitronode Field Guide", + Description: "A practical guide to following app-session state from wallet signature to Nitronode submission.", + Type: "guide", + Prices: map[string]string{ + "yellow": "1.80", + "yusd": "1.25", + }, + Content: "Nitronode Field Guide\n\nA good store flow lets operators trace app-session versions, signatures, and allocation deltas without exposing that complexity to shoppers.", + }, + { + ID: "4", + Title: "Wallet UX Patterns", + Description: "Small interface patterns for keeping wallet prompts understandable and recoverable.", + Type: "playbook", + Prices: map[string]string{ + "yellow": "1.10", + "yusd": "0.75", + }, + Content: "Wallet UX Patterns\n\nWallet UX works best when each signature has a clear product reason, visible state changes, and a straightforward recovery path.", + }, + { + ID: "5", + Title: "Channel Recovery Checklist", + Description: "A concise checklist for reconciling local state with the latest channel state.", + Type: "checklist", + Prices: map[string]string{ + "yellow": "2.25", + "yusd": "1.50", + }, + Content: "Channel Recovery Checklist\n\nConfirm the app session, compare the expected version, verify session data, reconcile pending purchases, then expose owned content only after ownership is submitted.", + }, + } +} diff --git a/internal/service/storefront_wallet.go b/internal/service/storefront_wallet.go index 44f6b15..88e3ee9 100644 --- a/internal/service/storefront_wallet.go +++ b/internal/service/storefront_wallet.go @@ -3,12 +3,13 @@ package service import ( "context" "encoding/json" + "errors" "fmt" "strings" "time" - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" + appsigning "github.com/layer-3/nitrolite-store-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/store" "github.com/layer-3/nitrolite/pkg/app" "github.com/layer-3/nitrolite/pkg/core" "github.com/layer-3/nitrolite/pkg/rpc" @@ -16,24 +17,20 @@ import ( "github.com/shopspring/decimal" ) -const ( - storeUpdateKindCreateSession = "create_session" - storeUpdateKindDeposit = "submit_deposit_state" - storeUpdateKindAppState = "submit_app_state" -) - type StoreBootstrapResponse struct { - StoreName string `json:"store_name"` - AppID string `json:"app_id"` - AppSigner string `json:"app_signer"` - WalletAddress string `json:"wallet_address"` - SelectedAsset string `json:"selected_asset"` - DefaultAsset string `json:"default_asset"` - SupportedAssets []string `json:"supported_assets"` - AvailableBalance string `json:"available_balance"` - Catalog []StoreCatalogItem `json:"catalog"` - Session StoreShopperSession `json:"session"` - Library []StoreLibraryItem `json:"library"` + StoreName string `json:"store_name"` + AppID string `json:"app_id"` + AppSigner string `json:"app_signer"` + WalletAddress string `json:"wallet_address"` + SelectedAsset string `json:"selected_asset"` + DefaultAsset string `json:"default_asset"` + SupportedAssets []string `json:"supported_assets"` + AvailableBalance string `json:"available_balance"` + ChannelReadiness StoreChannelReadiness `json:"channel_readiness"` + Catalog []StoreCatalogItem `json:"catalog"` + Session StoreShopperSession `json:"session"` + Library []StoreLibraryItem `json:"library"` + PendingAction *StorePendingAction `json:"pending_action,omitempty"` } type StoreShopperSession struct { @@ -56,37 +53,84 @@ type StoreLibraryItem struct { } type StoreUpdateRequest struct { - Asset string `json:"asset"` - Kind string `json:"kind"` - Definition *rpc.AppDefinitionV1 `json:"definition,omitempty"` - SessionData string `json:"session_data,omitempty"` + WalletAddress string `json:"wallet_address,omitempty"` + Asset string `json:"asset"` AppStateUpdate *rpc.AppStateUpdateV1 `json:"app_state_update,omitempty"` - UserSignature string `json:"user_signature,omitempty"` - UserState *rpc.StateV1 `json:"user_state,omitempty"` + UserSignature string `json:"user_signature,omitempty"` +} + +type StoreInitRequest struct { + WalletAddress string `json:"wallet_address,omitempty"` + Asset string `json:"asset"` + Definition rpc.AppDefinitionV1 `json:"definition"` + SessionData string `json:"session_data,omitempty"` + UserSignature string `json:"user_signature"` +} + +type StoreContentRequest struct { + WalletAddress string + Asset string +} + +type StorePendingAction struct { + Type string `json:"type"` + Status string `json:"status"` + Asset string `json:"asset"` + AppSessionID string `json:"app_session_id"` + Version uint64 `json:"version"` + Amount string `json:"amount"` + AppStateUpdate rpc.AppStateUpdateV1 `json:"app_state_update"` + UserSignature string `json:"user_signature"` + AppSignature string `json:"app_signature"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type StoreChannelReadiness struct { + Status string `json:"status"` + Message string `json:"message"` + HomeBlockchainID uint64 `json:"home_blockchain_id"` + BootstrapAmount string `json:"bootstrap_amount"` + AvailableBalance string `json:"available_balance"` + PendingBalance string `json:"pending_balance"` + RequiresChannelCreation bool `json:"requires_channel_creation"` + PendingTransition string `json:"pending_transition,omitempty"` + PendingAmount string `json:"pending_amount,omitempty"` + OnChainBalance string `json:"on_chain_balance"` +} + +type StoreUpdateResponse struct { + Status string `json:"status"` + Intent string `json:"intent"` + Asset string `json:"asset"` + AppSessionID string `json:"app_session_id"` + AppSignature string `json:"app_signature,omitempty"` + PendingAction *StorePendingAction `json:"pending_action,omitempty"` + Bootstrap *StoreBootstrapResponse `json:"bootstrap,omitempty"` } -type submitDepositFunc func(ctx context.Context, wsURL string, req rpc.AppSessionsV1SubmitDepositStateRequest) (string, error) type submitAppStateFunc func(ctx context.Context, wsURL string, req rpc.AppSessionsV1SubmitAppStateRequest) error type createAppSessionFunc func(ctx context.Context, wsURL string, req rpc.AppSessionsV1CreateAppSessionRequest) (*rpc.AppSessionsV1CreateAppSessionResponse, error) type WalletStoreService struct { - provider clientProvider - store *store.Store - appSigner appsigning.Signer - storeName string - appID string - defaultAsset string - supportedAssets []string - catalog []StoreCatalogItem - wsURL string - now func() time.Time - submitDepositRPC submitDepositFunc - submitAppStateRPC submitAppStateFunc - createAppSessionRPC createAppSessionFunc -} - -func NewWalletStoreService(provider clientProvider, appStore *store.Store, appSigner appsigning.Signer, storeName string, appID string, homeBlockchains map[string]uint64, wsURL string) *WalletStoreService { - assets := sortedAssets(homeBlockchains) + provider clientProvider + store *store.Store + appSigner appsigning.Signer + storeName string + appID string + defaultAsset string + supportedAssets []string + catalog []StoreCatalogItem + wsURL string + homeBlockchains map[string]uint64 + channelBootstrapAmounts map[string]string + now func() time.Time + submitAppStateRPC submitAppStateFunc + createAppSessionRPC createAppSessionFunc +} + +func NewWalletStoreService(provider clientProvider, appStore *store.Store, appSigner appsigning.Signer, storeName string, appID string, homeBlockchains map[string]uint64, wsURL string, channelBootstrapAmounts ...map[string]string) *WalletStoreService { + assets := supportedStoreAssets(homeBlockchains) defaultAsset := "yusd" if len(assets) > 0 { defaultAsset = assets[0] @@ -97,21 +141,26 @@ func NewWalletStoreService(provider clientProvider, appStore *store.Store, appSi } } } + amounts := defaultChannelBootstrapAmounts() + if len(channelBootstrapAmounts) > 0 { + amounts = normalizeChannelBootstrapAmounts(channelBootstrapAmounts[0]) + } return &WalletStoreService{ - provider: provider, - store: appStore, - appSigner: appSigner, - storeName: strings.TrimSpace(storeName), - appID: strings.TrimSpace(appID), - defaultAsset: defaultAsset, - supportedAssets: assets, - catalog: seededCatalog(), - wsURL: strings.TrimSpace(wsURL), - now: time.Now, - submitDepositRPC: submitDepositStateRPC, - submitAppStateRPC: submitAppStateRPC, - createAppSessionRPC: createAppSessionRPC, + provider: provider, + store: appStore, + appSigner: appSigner, + storeName: strings.TrimSpace(storeName), + appID: strings.TrimSpace(appID), + defaultAsset: defaultAsset, + supportedAssets: assets, + catalog: seededCatalog(), + wsURL: strings.TrimSpace(wsURL), + homeBlockchains: normalizeHomeBlockchains(homeBlockchains), + channelBootstrapAmounts: amounts, + now: time.Now, + submitAppStateRPC: submitAppStateRPC, + createAppSessionRPC: createAppSessionRPC, } } @@ -125,21 +174,15 @@ func (s *WalletStoreService) Bootstrap(ctx context.Context, walletAddress string if err != nil { return nil, err } - availableBalance, err := s.availableBalance(ctx, walletAddress, asset) - if err != nil { - return nil, err - } - library, err := s.library(ctx, walletAddress, asset) - if err != nil { - return nil, err - } - + readiness := s.channelReadiness(ctx, walletAddress, asset) + availableBalance := readiness.AvailableBalance session := StoreShopperSession{ Asset: asset, Status: "missing", UserAllocation: "0", AppAllocation: "0", } + var pendingAction *StorePendingAction stored, err := s.store.GetWalletSession(ctx, walletAddress, asset) if err != nil && err != store.ErrNotFound { @@ -153,9 +196,31 @@ func (s *WalletStoreService) Bootstrap(ctx context.Context, walletAddress string return nil, syncErr } session = *summary + if err := s.reconcilePendingPurchases(ctx, walletAddress, asset, *current); err != nil { + return nil, err + } + pendingAction, err = s.reconcileDepositCheckpoint(ctx, walletAddress, asset, *current) + if err != nil { + return nil, err + } + } else { + session = StoreShopperSession{ + Asset: asset, + AppSessionID: stored.AppSessionID, + Status: "sync_failed", + Version: stored.Version, + UserAllocation: stored.UserAllocation, + AppAllocation: stored.AppAllocation, + SessionData: stored.SessionData, + } } } + library, err := s.library(ctx, walletAddress, asset) + if err != nil { + return nil, err + } + return &StoreBootstrapResponse{ StoreName: s.storeName, AppID: s.appID, @@ -165,21 +230,49 @@ func (s *WalletStoreService) Bootstrap(ctx context.Context, walletAddress string DefaultAsset: s.defaultAsset, SupportedAssets: append([]string(nil), s.supportedAssets...), AvailableBalance: availableBalance, + ChannelReadiness: readiness, Catalog: catalog, Session: session, Library: library, + PendingAction: pendingAction, }, nil } -func (s *WalletStoreService) Content(ctx context.Context, walletAddress string, asset string, id string) (*StoreCatalogItem, error) { - asset, err := s.normalizeAsset(asset) +func (s *WalletStoreService) Content(ctx context.Context, id string, req StoreContentRequest) (*StoreCatalogItem, error) { + walletAddress := strings.TrimSpace(req.WalletAddress) + if walletAddress == "" { + return nil, invalidf("wallet_address is required") + } + + asset, err := s.normalizeAsset(req.Asset) if err != nil { return nil, err } + item := s.catalogItem(id) if item == nil { return nil, notFoundf("catalog item not found") } + + stored, err := s.store.GetWalletSession(ctx, walletAddress, asset) + if err != nil { + if err == store.ErrNotFound { + return nil, notFoundf("store session not found") + } + return nil, fmt.Errorf("failed to load wallet session: %w", err) + } + + current, err := s.lookupSession(ctx, stored.AppSessionID) + if err != nil { + return nil, err + } + if err := s.validateSessionParticipants(current, walletAddress); err != nil { + return nil, err + } + if err := s.reconcilePendingPurchases(ctx, walletAddress, asset, *current); err != nil { + return nil, err + } + owned, err := s.store.HasWalletPurchase(ctx, walletAddress, id, asset) if err != nil { return nil, fmt.Errorf("failed to check purchase: %w", err) @@ -194,28 +287,12 @@ func (s *WalletStoreService) Content(ctx context.Context, walletAddress string, return ©Item, nil } -func (s *WalletStoreService) SubmitUpdate(ctx context.Context, walletAddress string, req StoreUpdateRequest) (*StoreBootstrapResponse, error) { +func (s *WalletStoreService) CreateSession(ctx context.Context, req StoreInitRequest) (*StoreBootstrapResponse, error) { asset, err := s.normalizeAsset(req.Asset) if err != nil { return nil, err } - switch strings.TrimSpace(req.Kind) { - case storeUpdateKindCreateSession: - return s.createSession(ctx, walletAddress, asset, req) - case storeUpdateKindDeposit: - return s.submitDeposit(ctx, walletAddress, asset, req) - case storeUpdateKindAppState: - return s.submitAppStateUpdate(ctx, walletAddress, asset, req) - default: - return nil, invalidf("unsupported update kind") - } -} - -func (s *WalletStoreService) createSession(ctx context.Context, walletAddress string, asset string, req StoreUpdateRequest) (*StoreBootstrapResponse, error) { - if req.Definition == nil { - return nil, invalidf("definition is required") - } if strings.TrimSpace(req.UserSignature) == "" { return nil, invalidf("user_signature is required") } @@ -223,7 +300,11 @@ func (s *WalletStoreService) createSession(ctx context.Context, walletAddress st return nil, err } - definition, err := appDefinitionFromRPC(*req.Definition) + definition, err := appDefinitionFromRPC(req.Definition) + if err != nil { + return nil, err + } + walletAddress, err := s.walletFromDefinition(definition, req.WalletAddress) if err != nil { return nil, err } @@ -233,6 +314,9 @@ func (s *WalletStoreService) createSession(ctx context.Context, walletAddress st if err := verifyCreateSessionSignature(walletAddress, definition, req.SessionData, req.UserSignature); err != nil { return nil, err } + if err := s.requireFundedHomeChannel(ctx, walletAddress, asset); err != nil { + return nil, err + } appSig, err := signCreateAppSessionRequest(definition, req.SessionData, s.appSigner) if err != nil { @@ -240,13 +324,13 @@ func (s *WalletStoreService) createSession(ctx context.Context, walletAddress st } createReq := rpc.AppSessionsV1CreateAppSessionRequest{ - Definition: *req.Definition, - SessionData: req.SessionData, - QuorumSigs: []string{req.UserSignature, appSig}, + Definition: req.Definition, + SessionData: req.SessionData, + QuorumSigs: []string{req.UserSignature, appSig}, } resp, err := s.createAppSessionRPC(ctx, s.wsURL, createReq) if err != nil { - return nil, fmt.Errorf("failed to create app session: %w", err) + return nil, upstreamf(err, "failed to create app session") } now := s.now().UTC() @@ -268,30 +352,45 @@ func (s *WalletStoreService) createSession(ctx context.Context, walletAddress st return s.Bootstrap(ctx, walletAddress, asset) } -func (s *WalletStoreService) submitDeposit(ctx context.Context, walletAddress string, asset string, req StoreUpdateRequest) (*StoreBootstrapResponse, error) { +func (s *WalletStoreService) SubmitUpdate(ctx context.Context, req StoreUpdateRequest) (*StoreUpdateResponse, error) { + asset, err := s.normalizeAsset(req.Asset) + if err != nil { + return nil, err + } if req.AppStateUpdate == nil { return nil, invalidf("app_state_update is required") } - if req.UserState == nil { - return nil, invalidf("user_state is required") - } - if strings.TrimSpace(req.UserSignature) == "" { - return nil, invalidf("user_signature is required") - } update, err := appStateUpdateFromRPC(*req.AppStateUpdate) if err != nil { return nil, err } - userState, err := stateFromRPC(*req.UserState) - if err != nil { - return nil, err + + switch update.Intent { + case app.AppStateUpdateIntentDeposit: + return s.submitDeposit(ctx, asset, req, update) + case app.AppStateUpdateIntentWithdraw, app.AppStateUpdateIntentOperate: + return s.submitAppStateUpdate(ctx, asset, req, update) + default: + return nil, invalidf("unsupported app update intent") + } +} + +func (s *WalletStoreService) submitDeposit(ctx context.Context, asset string, req StoreUpdateRequest, update app.AppStateUpdateV1) (*StoreUpdateResponse, error) { + if req.AppStateUpdate == nil { + return nil, invalidf("app_state_update is required") + } + if strings.TrimSpace(req.UserSignature) == "" { + return nil, invalidf("user_signature is required") } - current, err := s.currentWalletSession(ctx, walletAddress, asset) + current, walletAddress, err := s.currentWalletSessionByAppSessionID(ctx, update.AppSessionID, asset) if err != nil { return nil, err } + if req.WalletAddress != "" && !strings.EqualFold(req.WalletAddress, walletAddress) { + return nil, conflictf("wallet_address does not match app session owner") + } if err := s.validateSessionParticipants(current, walletAddress); err != nil { return nil, err } @@ -299,30 +398,61 @@ func (s *WalletStoreService) submitDeposit(ctx context.Context, walletAddress st return nil, err } - depositAmount, err := s.validateDeposit(ctx, walletAddress, asset, current, update, userState) + if err := s.validateDeposit(walletAddress, asset, current, update); err != nil { + return nil, err + } + + amount, err := depositAmountForState(walletAddress, s.appSigner.Address(), asset, current, update) if err != nil { return nil, err } + if err := s.ensureDepositAvailable(ctx, walletAddress, asset, amount); err != nil { + return nil, err + } appSig, err := signAppStateUpdate(update, s.appSigner) if err != nil { return nil, err } - - _, err = s.submitDepositRPC(ctx, s.wsURL, rpc.AppSessionsV1SubmitDepositStateRequest{ - AppStateUpdate: *req.AppStateUpdate, - QuorumSigs: []string{req.UserSignature, appSig}, - UserState: *req.UserState, - }) + updateJSON, err := json.Marshal(req.AppStateUpdate) + if err != nil { + return nil, fmt.Errorf("failed to encode deposit checkpoint: %w", err) + } + now := s.now().UTC() + checkpoint := store.WalletDepositCheckpoint{ + ID: store.WalletDepositCheckpointID(walletAddress, asset), + WalletAddress: walletAddress, + Asset: asset, + AppSessionID: update.AppSessionID, + Version: update.Version, + Amount: amount, + Status: store.WalletDepositCheckpointStatusAppSigned, + AppStateUpdate: string(updateJSON), + UserSignature: req.UserSignature, + AppSignature: appSig, + SessionData: update.SessionData, + CreatedAt: now, + UpdatedAt: now, + } + if err := s.store.UpsertDepositCheckpoint(ctx, checkpoint); err != nil { + return nil, fmt.Errorf("failed to persist deposit checkpoint: %w", err) + } + pendingAction, err := depositCheckpointAction(checkpoint) if err != nil { - return nil, fmt.Errorf("failed to submit deposit state: %w", err) + return nil, err } - _ = depositAmount - return s.Bootstrap(ctx, walletAddress, asset) + return &StoreUpdateResponse{ + Status: "signed", + Intent: string(StoreIntentUserDeposit), + Asset: asset, + AppSessionID: update.AppSessionID, + AppSignature: appSig, + PendingAction: pendingAction, + }, nil } -func (s *WalletStoreService) submitAppStateUpdate(ctx context.Context, walletAddress string, asset string, req StoreUpdateRequest) (*StoreBootstrapResponse, error) { +func (s *WalletStoreService) submitAppStateUpdate(ctx context.Context, asset string, req StoreUpdateRequest, update app.AppStateUpdateV1) (*StoreUpdateResponse, error) { if req.AppStateUpdate == nil { return nil, invalidf("app_state_update is required") } @@ -330,14 +460,12 @@ func (s *WalletStoreService) submitAppStateUpdate(ctx context.Context, walletAdd return nil, invalidf("user_signature is required") } - update, err := appStateUpdateFromRPC(*req.AppStateUpdate) + current, walletAddress, err := s.currentWalletSessionByAppSessionID(ctx, update.AppSessionID, asset) if err != nil { return nil, err } - - current, err := s.currentWalletSession(ctx, walletAddress, asset) - if err != nil { - return nil, err + if req.WalletAddress != "" && !strings.EqualFold(req.WalletAddress, walletAddress) { + return nil, conflictf("wallet_address does not match app session owner") } if err := s.validateSessionParticipants(current, walletAddress); err != nil { return nil, err @@ -347,12 +475,17 @@ func (s *WalletStoreService) submitAppStateUpdate(ctx context.Context, walletAdd } purchaseItemID := "" + responseIntent := string(StoreIntentUserWithdraw) switch update.Intent { case app.AppStateUpdateIntentOperate: + if err := s.reconcilePendingPurchases(ctx, walletAddress, asset, *current); err != nil { + return nil, err + } purchaseItemID, err = s.validatePurchase(ctx, walletAddress, asset, current, update) if err != nil { return nil, err } + responseIntent = string(StoreIntentPurchase) case app.AppStateUpdateIntentWithdraw: if err := s.validateWithdraw(walletAddress, asset, current, update); err != nil { return nil, err @@ -365,28 +498,58 @@ func (s *WalletStoreService) submitAppStateUpdate(ctx context.Context, walletAdd if err != nil { return nil, err } - if err := s.submitAppStateRPC(ctx, s.wsURL, rpc.AppSessionsV1SubmitAppStateRequest{ - AppStateUpdate: *req.AppStateUpdate, - QuorumSigs: []string{req.UserSignature, appSig}, - }); err != nil { - return nil, fmt.Errorf("failed to submit app state: %w", err) - } + purchaseID := "" if purchaseItemID != "" { - if err := s.store.RecordWalletPurchase(ctx, store.WalletPurchase{ - ID: store.WalletPurchaseID(walletAddress, asset, purchaseItemID), + purchaseID = store.WalletPurchaseID(walletAddress, asset, purchaseItemID) + now := s.now().UTC() + if err := s.store.UpsertPendingWalletPurchase(ctx, store.WalletPurchase{ + ID: purchaseID, WalletAddress: walletAddress, ItemID: purchaseItemID, Asset: asset, AppSessionID: current.AppSessionID, Version: update.Version, - PurchasedAt: s.now().UTC(), + Status: store.WalletPurchaseStatusPending, + SessionData: update.SessionData, + CreatedAt: now, + UpdatedAt: now, + PurchasedAt: now, }); err != nil { - return nil, fmt.Errorf("failed to record purchase: %w", err) + if errors.Is(err, store.ErrConflict) { + return nil, conflictCodef("duplicate_purchase", "item already purchased") + } + return nil, fmt.Errorf("failed to prepare purchase: %w", err) } } - return s.Bootstrap(ctx, walletAddress, asset) + if err := s.submitAppStateRPC(ctx, s.wsURL, rpc.AppSessionsV1SubmitAppStateRequest{ + AppStateUpdate: *req.AppStateUpdate, + QuorumSigs: []string{req.UserSignature, appSig}, + }); err != nil { + if purchaseID != "" { + _ = s.store.MarkWalletPurchaseFailed(ctx, purchaseID, s.now().UTC()) + } + return nil, upstreamf(err, "failed to submit app state") + } + + if purchaseID != "" { + if err := s.store.MarkWalletPurchaseSubmitted(ctx, purchaseID, s.now().UTC()); err != nil { + return nil, fmt.Errorf("failed to mark purchase submitted: %w", err) + } + } + + bootstrap, err := s.Bootstrap(ctx, walletAddress, asset) + if err != nil { + return nil, err + } + return &StoreUpdateResponse{ + Status: "submitted", + Intent: responseIntent, + Asset: asset, + AppSessionID: update.AppSessionID, + Bootstrap: bootstrap, + }, nil } func (s *WalletStoreService) catalogForAsset(asset string) ([]StoreCatalogItem, error) { @@ -418,20 +581,112 @@ func (s *WalletStoreService) normalizeAsset(raw string) (string, error) { } func (s *WalletStoreService) availableBalance(ctx context.Context, walletAddress string, asset string) (string, error) { + return s.channelReadiness(ctx, walletAddress, asset).AvailableBalance, nil +} + +func (s *WalletStoreService) requireFundedHomeChannel(ctx context.Context, walletAddress string, asset string) error { + readiness := s.channelReadiness(ctx, walletAddress, asset) + if readiness.Status != "ready" { + return conflictCodef("channel_"+readiness.Status, "%s", readiness.Message) + } + return nil +} + +func (s *WalletStoreService) channelReadiness(ctx context.Context, walletAddress string, asset string) StoreChannelReadiness { + chainID := s.homeBlockchains[asset] + bootstrapAmount := s.channelBootstrapAmount(asset) + readiness := StoreChannelReadiness{ + Status: "unavailable", + Message: "channel readiness is unavailable", + HomeBlockchainID: chainID, + BootstrapAmount: bootstrapAmount, + AvailableBalance: "0", + PendingBalance: "0", + OnChainBalance: "0", + } + client, _, err := activeClient(s.provider) if err != nil { - return "", err + readiness.Message = "nitronode is not reachable" + return readiness + } + + signedState, signedErr := client.GetLatestState(ctx, walletAddress, asset, true) + signedReady := false + if signedErr == nil && signedState != nil { + readiness.PendingBalance = signedState.HomeLedger.UserBalance.String() + if signedState.HomeChannelID != nil && signedState.HomeLedger.UserBalance.IsPositive() { + readiness.AvailableBalance = signedState.HomeLedger.UserBalance.String() + signedReady = true + } else if signedState.HomeLedger.UserBalance.IsPositive() { + readiness.RequiresChannelCreation = true + } } - balances, err := client.GetBalances(ctx, walletAddress) + + latestState, latestErr := client.GetLatestState(ctx, walletAddress, asset, false) + if latestErr == nil && latestState != nil { + readiness.PendingBalance = latestState.HomeLedger.UserBalance.String() + latestHasFunds := latestState.HomeLedger.UserBalance.IsPositive() + latestHasOpenChannel := latestState.HomeChannelID != nil + latestMatchesSigned := signedState != nil && latestState.ID == signedState.ID && latestState.Version == signedState.Version + if latestHasFunds && latestHasOpenChannel && (latestState.UserSig != nil || latestMatchesSigned) { + readiness.Status = "ready" + readiness.Message = "home channel is ready" + readiness.AvailableBalance = latestState.HomeLedger.UserBalance.String() + return readiness + } + if latestHasFunds { + if !latestHasOpenChannel { + readiness.RequiresChannelCreation = true + } + if latestState.Transition.Type != core.TransitionTypeVoid || !latestState.Transition.Amount.IsZero() { + readiness.PendingTransition = latestState.Transition.Type.String() + readiness.PendingAmount = latestState.Transition.Amount.String() + } + readiness.Status = "ack_required" + if readiness.RequiresChannelCreation { + readiness.Message = "acknowledge received off-chain funds to open a home channel" + } else { + readiness.Message = "acknowledge pending channel funds before starting the store session" + } + return readiness + } + } + + if readiness.RequiresChannelCreation { + readiness.Status = "ack_required" + readiness.Message = "complete channel setup for received off-chain funds" + return readiness + } + + if signedReady { + readiness.Status = "ready" + readiness.Message = "home channel is ready" + return readiness + } + + if chainID == 0 { + readiness.Status = "unavailable" + readiness.Message = "home blockchain is not configured for this asset" + return readiness + } + + onChainBalance, err := client.GetOnChainBalance(ctx, chainID, asset, walletAddress) if err != nil { - return "", fmt.Errorf("failed to get balances: %w", err) + readiness.Status = "unavailable" + readiness.Message = "on-chain balance lookup failed" + return readiness } - for _, entry := range balances { - if strings.EqualFold(entry.Asset, asset) { - return entry.Balance.String(), nil - } + readiness.OnChainBalance = onChainBalance.String() + if onChainBalance.IsPositive() { + readiness.Status = "deposit_required" + readiness.Message = "prepare a funded home channel before starting the store session" + return readiness } - return "0", nil + + readiness.Status = "funds_required" + readiness.Message = "add test funds before preparing a home channel" + return readiness } func (s *WalletStoreService) lookupSession(ctx context.Context, sessionID string) (*app.AppSessionInfoV1, error) { @@ -442,7 +697,7 @@ func (s *WalletStoreService) lookupSession(ctx context.Context, sessionID string opts := &sdk.GetAppSessionsOptions{AppSessionID: &sessionID} sessions, _, err := client.GetAppSessions(ctx, opts) if err != nil { - return nil, fmt.Errorf("failed to get app sessions: %w", err) + return nil, upstreamf(err, "failed to get app sessions") } for _, session := range sessions { if session.AppSessionID == sessionID { @@ -463,8 +718,23 @@ func (s *WalletStoreService) currentWalletSession(ctx context.Context, walletAdd return s.lookupSession(ctx, stored.AppSessionID) } +func (s *WalletStoreService) currentWalletSessionByAppSessionID(ctx context.Context, appSessionID string, asset string) (*app.AppSessionInfoV1, string, error) { + stored, err := s.store.GetWalletSessionByAppSessionID(ctx, appSessionID, asset) + if err != nil { + if err == store.ErrNotFound { + return nil, "", notFoundf("store session not found") + } + return nil, "", fmt.Errorf("failed to load wallet session: %w", err) + } + current, err := s.lookupSession(ctx, stored.AppSessionID) + if err != nil { + return nil, "", err + } + return current, stored.WalletAddress, nil +} + func (s *WalletStoreService) sessionSummary(ctx context.Context, walletAddress string, asset string, current app.AppSessionInfoV1) (*StoreShopperSession, error) { - userAmount, appAmount := balancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) + userAmount, appAmount := displayBalancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) now := s.now().UTC() if err := s.store.UpsertWalletSession(ctx, store.WalletStoreSession{ WalletAddress: walletAddress, @@ -514,6 +784,98 @@ func (s *WalletStoreService) library(ctx context.Context, walletAddress string, return items, nil } +func (s *WalletStoreService) reconcilePendingPurchases(ctx context.Context, walletAddress string, asset string, current app.AppSessionInfoV1) error { + pending, err := s.store.ListPendingWalletPurchases(ctx, walletAddress, asset) + if err != nil { + return fmt.Errorf("failed to list pending purchases: %w", err) + } + if len(pending) == 0 { + return nil + } + + for _, purchase := range pending { + if purchase.AppSessionID != current.AppSessionID { + continue + } + if current.Version < purchase.Version { + continue + } + if strings.TrimSpace(current.SessionData) != strings.TrimSpace(purchase.SessionData) { + continue + } + if err := s.store.MarkWalletPurchaseSubmitted(ctx, purchase.ID, s.now().UTC()); err != nil && !errors.Is(err, store.ErrNotFound) { + return fmt.Errorf("failed to reconcile purchase: %w", err) + } + } + return nil +} + +func (s *WalletStoreService) reconcileDepositCheckpoint(ctx context.Context, walletAddress string, asset string, current app.AppSessionInfoV1) (*StorePendingAction, error) { + checkpoint, err := s.store.GetActiveDepositCheckpoint(ctx, walletAddress, asset) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil, nil + } + return nil, fmt.Errorf("failed to load deposit checkpoint: %w", err) + } + if checkpoint.AppSessionID != current.AppSessionID { + if err := s.store.MarkDepositCheckpointFailed(ctx, checkpoint.ID, s.now().UTC()); err != nil && !errors.Is(err, store.ErrNotFound) { + return nil, fmt.Errorf("failed to retire deposit checkpoint: %w", err) + } + return nil, nil + } + if current.Version >= checkpoint.Version { + if strings.TrimSpace(current.SessionData) == strings.TrimSpace(checkpoint.SessionData) { + if err := s.store.MarkDepositCheckpointSubmitted(ctx, checkpoint.ID, s.now().UTC()); err != nil && !errors.Is(err, store.ErrNotFound) { + return nil, fmt.Errorf("failed to reconcile deposit checkpoint: %w", err) + } + return nil, nil + } + if err := s.store.MarkDepositCheckpointFailed(ctx, checkpoint.ID, s.now().UTC()); err != nil && !errors.Is(err, store.ErrNotFound) { + return nil, fmt.Errorf("failed to retire stale deposit checkpoint: %w", err) + } + return nil, nil + } + return depositCheckpointAction(*checkpoint) +} + +func depositCheckpointAction(checkpoint store.WalletDepositCheckpoint) (*StorePendingAction, error) { + var update rpc.AppStateUpdateV1 + if err := json.Unmarshal([]byte(checkpoint.AppStateUpdate), &update); err != nil { + return nil, fmt.Errorf("failed to decode deposit checkpoint: %w", err) + } + return &StorePendingAction{ + Type: string(StoreIntentUserDeposit), + Status: checkpoint.Status, + Asset: checkpoint.Asset, + AppSessionID: checkpoint.AppSessionID, + Version: checkpoint.Version, + Amount: checkpoint.Amount, + AppStateUpdate: update, + UserSignature: checkpoint.UserSignature, + AppSignature: checkpoint.AppSignature, + CreatedAt: checkpoint.CreatedAt.Format(time.RFC3339), + UpdatedAt: checkpoint.UpdatedAt.Format(time.RFC3339), + }, nil +} + +func (s *WalletStoreService) walletFromDefinition(definition app.AppDefinitionV1, requestedWallet string) (string, error) { + walletAddress := strings.TrimSpace(requestedWallet) + for _, participant := range definition.Participants { + if strings.EqualFold(participant.WalletAddress, s.appSigner.Address()) { + continue + } + if walletAddress != "" && !strings.EqualFold(walletAddress, participant.WalletAddress) { + return "", conflictf("wallet_address does not match app session participant") + } + walletAddress = strings.TrimSpace(participant.WalletAddress) + } + if walletAddress == "" { + return "", invalidf("wallet participant is required") + } + return walletAddress, nil +} + func (s *WalletStoreService) validateCreateDefinition(definition app.AppDefinitionV1, walletAddress string) error { if strings.TrimSpace(definition.ApplicationID) != s.appID { return invalidf("application_id does not match configured app") @@ -530,9 +892,9 @@ func (s *WalletStoreService) validateCreateDefinition(definition app.AppDefiniti for _, participant := range definition.Participants { switch { case strings.EqualFold(participant.WalletAddress, walletAddress): - seenWallet = participant.SignatureWeight > 0 + seenWallet = participant.SignatureWeight == 1 case strings.EqualFold(participant.WalletAddress, s.appSigner.Address()): - seenApp = participant.SignatureWeight > 0 + seenApp = participant.SignatureWeight == 1 default: return invalidf("unexpected app session participant") } @@ -556,15 +918,18 @@ func (s *WalletStoreService) validateSessionParticipants(current *app.AppSession if len(current.AppDefinition.Participants) != 2 { return conflictf("unexpected app session participant set") } + if current.AppDefinition.Quorum != 2 { + return conflictf("unexpected app session quorum") + } seenWallet := false seenApp := false for _, participant := range current.AppDefinition.Participants { switch { case strings.EqualFold(participant.WalletAddress, walletAddress): - seenWallet = true + seenWallet = participant.SignatureWeight == 1 case strings.EqualFold(participant.WalletAddress, s.appSigner.Address()): - seenApp = true + seenApp = participant.SignatureWeight == 1 } } if !seenWallet || !seenApp { @@ -581,17 +946,21 @@ func (s *WalletStoreService) validatePurchase(ctx context.Context, walletAddress return "", conflictf("app_session_id does not match active store session") } if update.Version != current.Version+1 { - return "", conflictf("app session version is stale") + return "", conflictCodef("stale_version", "app session version is stale") } var sessionData StoreSessionData if err := json.Unmarshal([]byte(strings.TrimSpace(update.SessionData)), &sessionData); err != nil { return "", invalidf("invalid session_data") } - if sessionData.Action != ActionPurchase { - return "", invalidf("purchase session_data.action must be purchase") + if sessionData.Intent != StoreIntentPurchase { + return "", invalidf("purchase session_data.intent must be purchase") + } + itemID, err := sessionDataItemID(sessionData.ItemID) + if err != nil { + return "", err } - item := s.catalogItem(sessionData.ItemID) + item := s.catalogItem(itemID) if item == nil { return "", notFoundf("catalog item not found") } @@ -600,7 +969,7 @@ func (s *WalletStoreService) validatePurchase(ctx context.Context, walletAddress if err != nil { return "", fmt.Errorf("invalid catalog price for %s: %w", item.ID, err) } - sessionAmount, err := parsePositiveAmount(sessionData.Price) + sessionAmount, err := parsePositiveAmount(sessionData.ItemPrice) if err != nil { return "", err } @@ -612,12 +981,18 @@ func (s *WalletStoreService) validatePurchase(ctx context.Context, walletAddress return "", fmt.Errorf("failed to check purchase: %w", err) } if alreadyOwned { - return "", conflictf("item already purchased") + return "", conflictCodef("duplicate_purchase", "item already purchased") } price := sessionAmount - currentUser, currentApp := balancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) - nextUser, nextApp := balancesForAsset(update.Allocations, walletAddress, s.appSigner.Address(), asset) + currentUser, currentApp, err := currentBalancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) + if err != nil { + return "", err + } + nextUser, nextApp, err := strictBalancesForAsset(update.Allocations, walletAddress, s.appSigner.Address(), asset) + if err != nil { + return "", err + } if !nextUser.Equal(currentUser.Sub(price)) { return "", conflictf("purchase user allocation delta is invalid") } @@ -628,7 +1003,7 @@ func (s *WalletStoreService) validatePurchase(ctx context.Context, walletAddress return "", conflictf("purchase allocations must conserve total balance") } if nextUser.IsNegative() { - return "", conflictf("purchase would overdraw user allocation") + return "", conflictCodef("insufficient_balance", "purchase would overdraw user allocation") } return item.ID, nil } @@ -641,23 +1016,37 @@ func (s *WalletStoreService) validateWithdraw(walletAddress string, asset string return conflictf("app_session_id does not match active store session") } if update.Version != current.Version+1 { - return conflictf("app session version is stale") + return conflictCodef("stale_version", "app session version is stale") } var sessionData StoreSessionData if err := json.Unmarshal([]byte(strings.TrimSpace(update.SessionData)), &sessionData); err != nil { return invalidf("invalid session_data") } - if sessionData.Action != ActionUserWithdraw { - return invalidf("withdraw session_data.action must be user_withdraw") + if sessionData.Intent != StoreIntentUserWithdraw { + return invalidf("withdraw session_data.intent must be user_withdraw") } - - amount, err := parsePositiveAmount(sessionData.Amount) + currentUser, currentApp, err := currentBalancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) if err != nil { return err } - currentUser, currentApp := balancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) - nextUser, nextApp := balancesForAsset(update.Allocations, walletAddress, s.appSigner.Address(), asset) + nextUser, nextApp, err := strictBalancesForAsset(update.Allocations, walletAddress, s.appSigner.Address(), asset) + if err != nil { + return err + } + amount := currentUser.Sub(nextUser) + if !amount.IsPositive() { + return conflictf("withdraw amount must be positive") + } + if strings.TrimSpace(sessionData.Amount) != "" { + sessionAmount, err := parsePositiveAmount(sessionData.Amount) + if err != nil { + return err + } + if !sessionAmount.Equal(amount) { + return conflictf("withdraw session_data amount does not match allocation delta") + } + } if !nextUser.Equal(currentUser.Sub(amount)) { return conflictf("withdraw user allocation delta is invalid") } @@ -665,82 +1054,94 @@ func (s *WalletStoreService) validateWithdraw(walletAddress string, asset string return conflictf("withdraw cannot change app allocation") } if nextUser.IsNegative() { - return conflictf("withdraw would overdraw user allocation") + return conflictCodef("insufficient_balance", "withdraw would overdraw user allocation") } return nil } -func (s *WalletStoreService) validateDeposit(ctx context.Context, walletAddress string, asset string, current *app.AppSessionInfoV1, update app.AppStateUpdateV1, userState core.State) (decimal.Decimal, error) { +func (s *WalletStoreService) validateDeposit(walletAddress string, asset string, current *app.AppSessionInfoV1, update app.AppStateUpdateV1) error { if update.Intent != app.AppStateUpdateIntentDeposit { - return decimal.Zero, invalidf("deposit must use deposit intent") + return invalidf("deposit must use deposit intent") } if update.AppSessionID != current.AppSessionID { - return decimal.Zero, conflictf("app_session_id does not match active store session") + return conflictf("app_session_id does not match active store session") } if update.Version != current.Version+1 { - return decimal.Zero, conflictf("app session version is stale") + return conflictCodef("stale_version", "app session version is stale") } var sessionData StoreSessionData if err := json.Unmarshal([]byte(strings.TrimSpace(update.SessionData)), &sessionData); err != nil { - return decimal.Zero, invalidf("invalid session_data") + return invalidf("invalid session_data") } - if sessionData.Action != ActionDeposit { - return decimal.Zero, invalidf("deposit session_data.action must be deposit") + if sessionData.Intent != StoreIntentUserDeposit { + return invalidf("deposit session_data.intent must be user_deposit") } - amount, err := parsePositiveAmount(sessionData.Amount) + currentUser, currentApp, err := currentBalancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) if err != nil { - return decimal.Zero, err + return err + } + nextUser, nextApp, err := strictBalancesForAsset(update.Allocations, walletAddress, s.appSigner.Address(), asset) + if err != nil { + return err + } + amount := nextUser.Sub(currentUser) + if !amount.IsPositive() { + return conflictf("deposit amount must be positive") + } + if strings.TrimSpace(sessionData.Amount) != "" { + sessionAmount, err := parsePositiveAmount(sessionData.Amount) + if err != nil { + return err + } + if !sessionAmount.Equal(amount) { + return conflictf("deposit session_data amount does not match allocation delta") + } } - - currentUser, currentApp := balancesForAsset(current.Allocations, walletAddress, s.appSigner.Address(), asset) - nextUser, nextApp := balancesForAsset(update.Allocations, walletAddress, s.appSigner.Address(), asset) if !nextUser.Equal(currentUser.Add(amount)) { - return decimal.Zero, conflictf("deposit user allocation delta is invalid") + return conflictf("deposit user allocation delta is invalid") } if !nextApp.Equal(currentApp) { - return decimal.Zero, conflictf("deposit cannot change app allocation") + return conflictf("deposit cannot change app allocation") } + return nil +} - assetStore, err := s.assetStore(ctx) +func (s *WalletStoreService) ensureDepositAvailable(ctx context.Context, walletAddress string, asset string, amount string) error { + depositAmount, err := decimal.NewFromString(strings.TrimSpace(amount)) if err != nil { - return decimal.Zero, err + return fmt.Errorf("failed to parse deposit amount: %w", err) } - client, _, err := activeClient(s.provider) + + availableRaw, err := s.availableBalance(ctx, walletAddress, asset) if err != nil { - return decimal.Zero, err + return err } - currentState, err := client.GetLatestState(ctx, walletAddress, asset, false) + availableAmount, err := decimal.NewFromString(strings.TrimSpace(availableRaw)) if err != nil { - return decimal.Zero, fmt.Errorf("failed to get latest state: %w", err) - } - advancer := core.NewStateAdvancerV1(assetStore) - if err := advancer.ValidateAdvancement(*currentState, userState); err != nil { - return decimal.Zero, conflictf("user_state is not a valid next state: %v", err) - } - if userState.Transition.Type != core.TransitionTypeCommit { - return decimal.Zero, conflictf("deposit user_state transition must be commit") - } - if !strings.EqualFold(userState.Transition.AccountID, update.AppSessionID) { - return decimal.Zero, conflictf("deposit user_state account_id must equal app_session_id") + return fmt.Errorf("failed to parse available balance: %w", err) } - if !userState.Transition.Amount.Equal(amount) { - return decimal.Zero, conflictf("deposit user_state amount must match session_data amount") + if depositAmount.GreaterThan(availableAmount) { + return conflictCodef("insufficient_balance", "deposit exceeds available balance") } - if !strings.EqualFold(userState.Asset, asset) { - return decimal.Zero, conflictf("deposit user_state asset mismatch") - } - if !strings.EqualFold(userState.UserWallet, walletAddress) { - return decimal.Zero, conflictf("deposit user_state wallet mismatch") + return nil +} + +func depositAmountForState(walletAddress string, appSignerAddress string, asset string, current *app.AppSessionInfoV1, update app.AppStateUpdateV1) (string, error) { + currentUser, _, err := currentBalancesForAsset(current.Allocations, walletAddress, appSignerAddress, asset) + if err != nil { + return "", err } - if userState.UserSig == nil || strings.TrimSpace(*userState.UserSig) == "" { - return decimal.Zero, conflictf("deposit user_state is missing user_sig") + nextUser, _, err := strictBalancesForAsset(update.Allocations, walletAddress, appSignerAddress, asset) + if err != nil { + return "", err } - if err := verifyChannelStateSignature(walletAddress, userState, assetStore); err != nil { - return decimal.Zero, err + amount := nextUser.Sub(currentUser) + if !amount.IsPositive() { + return "", conflictf("deposit amount must be positive") } - return amount, nil + return amount.String(), nil } func (s *WalletStoreService) ensureApp(ctx context.Context) error { @@ -751,7 +1152,10 @@ func (s *WalletStoreService) ensureApp(ctx context.Context) error { opts := &sdk.GetAppsOptions{AppID: &s.appID} apps, _, err := client.GetApps(ctx, opts) if err != nil { - return fmt.Errorf("failed to get apps: %w", err) + if isAppRegistryDisabledError(err) { + return nil + } + return upstreamf(err, "failed to get apps") } for _, info := range apps { if info.App.ID == s.appID { @@ -759,11 +1163,15 @@ func (s *WalletStoreService) ensureApp(ctx context.Context) error { } } if err := client.RegisterApp(ctx, s.appID, `{"product":"store"}`, true); err != nil { - return fmt.Errorf("failed to register store app: %w", err) + return upstreamf(err, "failed to register store app") } return nil } +func isAppRegistryDisabledError(err error) bool { + return err != nil && strings.Contains(err.Error(), "apps.v1 group is disabled") +} + func (s *WalletStoreService) catalogItem(id string) *StoreCatalogItem { id = strings.TrimSpace(id) for i := range s.catalog { diff --git a/internal/service/storefront_wallet_helpers.go b/internal/service/storefront_wallet_helpers.go index 70f4d00..3d7841d 100644 --- a/internal/service/storefront_wallet_helpers.go +++ b/internal/service/storefront_wallet_helpers.go @@ -1,14 +1,12 @@ package service import ( - "context" "fmt" "strconv" "strings" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/layer-3/nitrolite/pkg/app" - "github.com/layer-3/nitrolite/pkg/core" "github.com/layer-3/nitrolite/pkg/rpc" "github.com/shopspring/decimal" ) @@ -63,83 +61,6 @@ func appStateUpdateFromRPC(update rpc.AppStateUpdateV1) (app.AppStateUpdateV1, e }, nil } -func stateFromRPC(state rpc.StateV1) (core.State, error) { - epoch, err := strconv.ParseUint(state.Epoch, 10, 64) - if err != nil { - return core.State{}, invalidf("invalid user_state.epoch") - } - version, err := strconv.ParseUint(state.Version, 10, 64) - if err != nil { - return core.State{}, invalidf("invalid user_state.version") - } - - homeLedger, err := ledgerFromRPC(state.HomeLedger) - if err != nil { - return core.State{}, err - } - - var escrowLedger *core.Ledger - if state.EscrowLedger != nil { - ledger, err := ledgerFromRPC(*state.EscrowLedger) - if err != nil { - return core.State{}, err - } - escrowLedger = &ledger - } - - amount, err := decimal.NewFromString(strings.TrimSpace(state.Transition.Amount)) - if err != nil { - return core.State{}, invalidf("invalid user_state.transition.amount") - } - - return core.State{ - ID: state.ID, - Transition: core.Transition{Type: state.Transition.Type, TxID: state.Transition.TxID, AccountID: state.Transition.AccountID, Amount: amount}, - Asset: strings.ToLower(strings.TrimSpace(state.Asset)), - UserWallet: strings.TrimSpace(state.UserWallet), - Epoch: epoch, - Version: version, - HomeChannelID: state.HomeChannelID, - EscrowChannelID: state.EscrowChannelID, - HomeLedger: homeLedger, - EscrowLedger: escrowLedger, - UserSig: state.UserSig, - NodeSig: state.NodeSig, - }, nil -} - -func ledgerFromRPC(ledger rpc.LedgerV1) (core.Ledger, error) { - blockchainID, err := strconv.ParseUint(strings.TrimSpace(ledger.BlockchainID), 10, 64) - if err != nil { - return core.Ledger{}, invalidf("invalid user_state ledger blockchain_id") - } - userBalance, err := decimal.NewFromString(strings.TrimSpace(ledger.UserBalance)) - if err != nil { - return core.Ledger{}, invalidf("invalid user_state ledger user_balance") - } - userNetFlow, err := decimal.NewFromString(strings.TrimSpace(ledger.UserNetFlow)) - if err != nil { - return core.Ledger{}, invalidf("invalid user_state ledger user_net_flow") - } - nodeBalance, err := decimal.NewFromString(strings.TrimSpace(ledger.NodeBalance)) - if err != nil { - return core.Ledger{}, invalidf("invalid user_state ledger node_balance") - } - nodeNetFlow, err := decimal.NewFromString(strings.TrimSpace(ledger.NodeNetFlow)) - if err != nil { - return core.Ledger{}, invalidf("invalid user_state ledger node_net_flow") - } - - return core.Ledger{ - TokenAddress: ledger.TokenAddress, - BlockchainID: blockchainID, - UserBalance: userBalance, - UserNetFlow: userNetFlow, - NodeBalance: nodeBalance, - NodeNetFlow: nodeNetFlow, - }, nil -} - func verifyCreateSessionSignature(walletAddress string, definition app.AppDefinitionV1, sessionData string, signatureHex string) error { payload, err := app.PackCreateAppSessionRequestV1(definition, sessionData) if err != nil { @@ -159,78 +80,13 @@ func verifyAppStateSignature(walletAddress string, update app.AppStateUpdateV1, func verifyWalletAppPayloadSignature(walletAddress string, payload []byte, signatureHex string) error { sigBytes, err := hexutil.Decode(strings.TrimSpace(signatureHex)) if err != nil { - return invalidf("invalid user_signature") + return invalidCodef("invalid_signature", "invalid user_signature") } validator := app.NewAppSessionKeySigValidatorV1(func(string) (string, error) { return "", conflictf("session keys are not enabled") }) if err := validator.Verify(walletAddress, payload, sigBytes); err != nil { - return conflictf("invalid app session signature") + return conflictCodef("invalid_signature", "invalid app session signature") } return nil } - -func verifyChannelStateSignature(walletAddress string, state core.State, assetStore core.AssetStore) error { - if state.UserSig == nil { - return conflictf("user_state is missing user_sig") - } - sigBytes, err := hexutil.Decode(strings.TrimSpace(*state.UserSig)) - if err != nil { - return invalidf("invalid user_state.user_sig") - } - packedState, err := core.PackState(state, assetStore) - if err != nil { - return fmt.Errorf("failed to pack user_state: %w", err) - } - validator := core.NewChannelSigValidator(func(string, string, string) (bool, error) { - return false, nil - }) - if err := validator.Verify(walletAddress, packedState, sigBytes); err != nil { - return conflictf("invalid user_state signature") - } - return nil -} - -type staticAssetStore struct { - assetDecimals map[string]uint8 - tokenDecimals map[string]uint8 -} - -func (s staticAssetStore) GetAssetDecimals(asset string) (uint8, error) { - if decimals, ok := s.assetDecimals[strings.ToLower(strings.TrimSpace(asset))]; ok { - return decimals, nil - } - return 0, fmt.Errorf("asset decimals not found") -} - -func (s staticAssetStore) GetTokenDecimals(blockchainID uint64, tokenAddress string) (uint8, error) { - key := fmt.Sprintf("%d::%s", blockchainID, strings.ToLower(strings.TrimSpace(tokenAddress))) - if decimals, ok := s.tokenDecimals[key]; ok { - return decimals, nil - } - return 0, fmt.Errorf("token decimals not found") -} - -func (s *WalletStoreService) assetStore(ctx context.Context) (core.AssetStore, error) { - client, _, err := activeClient(s.provider) - if err != nil { - return nil, err - } - assets, err := client.GetAssets(ctx, nil) - if err != nil { - return nil, fmt.Errorf("failed to load asset metadata: %w", err) - } - - store := staticAssetStore{ - assetDecimals: make(map[string]uint8, len(assets)), - tokenDecimals: make(map[string]uint8), - } - for _, asset := range assets { - store.assetDecimals[strings.ToLower(asset.Symbol)] = asset.Decimals - for _, token := range asset.Tokens { - key := fmt.Sprintf("%d::%s", token.BlockchainID, strings.ToLower(token.Address)) - store.tokenDecimals[key] = token.Decimals - } - } - return store, nil -} diff --git a/internal/service/storefront_wallet_rpc.go b/internal/service/storefront_wallet_rpc.go index 99a1435..d07a088 100644 --- a/internal/service/storefront_wallet_rpc.go +++ b/internal/service/storefront_wallet_rpc.go @@ -30,22 +30,6 @@ func submitAppStateRPC(ctx context.Context, wsURL string, req rpc.AppSessionsV1S }) } -func submitDepositStateRPC(ctx context.Context, wsURL string, req rpc.AppSessionsV1SubmitDepositStateRequest) (string, error) { - var signature string - err := withRPCClient(ctx, wsURL, func(client *rpc.Client) error { - resp, err := client.AppSessionsV1SubmitDepositState(ctx, req) - if err != nil { - return err - } - signature = resp.StateNodeSig - return nil - }) - if err != nil { - return "", err - } - return signature, nil -} - func withRPCClient(ctx context.Context, wsURL string, fn func(*rpc.Client) error) error { dialer := rpc.NewWebsocketDialer(rpc.DefaultWebsocketDialerConfig) client := rpc.NewClient(dialer) diff --git a/internal/service/storefront_wallet_test.go b/internal/service/storefront_wallet_test.go index ee3cf79..7357181 100644 --- a/internal/service/storefront_wallet_test.go +++ b/internal/service/storefront_wallet_test.go @@ -2,16 +2,20 @@ package service import ( "context" + "encoding/json" + "errors" "log/slog" "path/filepath" "reflect" + "strings" "testing" "time" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - appsigning "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" + appsigning "github.com/layer-3/nitrolite-store-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/store" + "github.com/layer-3/nitrolite-store-example/internal/testsupport" "github.com/layer-3/nitrolite/pkg/app" "github.com/layer-3/nitrolite/pkg/core" "github.com/layer-3/nitrolite/pkg/rpc" @@ -19,6 +23,41 @@ import ( "github.com/shopspring/decimal" ) +const ( + serviceTestPrivateKey = "0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318" + serviceUserPrivateKey = "0x59c6995e998f97a5a0044976f094538fcb963c90d6f9fbfc7f3a6fcd45d9c25" +) + +func fundedHomeState(wallet string, asset string, balance string) *core.State { + homeChannelID := "0xhome" + return &core.State{ + ID: "0xstate", + Asset: asset, + UserWallet: wallet, + HomeChannelID: &homeChannelID, + HomeLedger: core.Ledger{ + UserBalance: decimal.RequireFromString(balance), + UserNetFlow: decimal.RequireFromString(balance), + NodeBalance: decimal.Zero, + NodeNetFlow: decimal.Zero, + }, + } +} + +func receivedOffchainState(wallet string, asset string, balance string) *core.State { + return &core.State{ + ID: "0xreceived", + Asset: asset, + UserWallet: wallet, + HomeLedger: core.Ledger{ + UserBalance: decimal.RequireFromString(balance), + UserNetFlow: decimal.RequireFromString(balance), + NodeBalance: decimal.Zero, + NodeNetFlow: decimal.Zero, + }, + } +} + func TestWalletStoreServiceCreateSessionForwardsExactPayload(t *testing.T) { t.Parallel() @@ -28,8 +67,8 @@ func TestWalletStoreServiceCreateSessionForwardsExactPayload(t *testing.T) { GetAppsFunc: func(context.Context, *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) { return []app.AppInfoV1{{App: app.AppV1{ID: "store"}}}, core.PaginationMetadata{}, nil }, - GetBalancesFunc: func(context.Context, string) ([]core.BalanceEntry, error) { - return []core.BalanceEntry{{Asset: "yusd", Balance: decimal.RequireFromString("7")}}, nil + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "7"), nil }, } manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ @@ -71,14 +110,10 @@ func TestWalletStoreServiceCreateSessionForwardsExactPayload(t *testing.T) { Nonce: "1", } currentSession := app.AppSessionInfoV1{ - AppSessionID: "0xsession", + AppSessionID: "0xsession", AppDefinition: definition, - Version: 1, - SessionData: sessionData, - Allocations: []app.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, - }, + Version: 1, + SessionData: sessionData, } client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil @@ -94,11 +129,10 @@ func TestWalletStoreServiceCreateSessionForwardsExactPayload(t *testing.T) { }, nil } - resp, err := service.SubmitUpdate(context.Background(), userSigner.Address(), StoreUpdateRequest{ - Asset: "yusd", - Kind: storeUpdateKindCreateSession, - Definition: &rpcDefinition, - SessionData: sessionData, + resp, err := service.CreateSession(context.Background(), StoreInitRequest{ + Asset: "yusd", + Definition: rpcDefinition, + SessionData: sessionData, UserSignature: userSig, }) if err != nil { @@ -119,14 +153,17 @@ func TestWalletStoreServiceCreateSessionForwardsExactPayload(t *testing.T) { } } -func TestWalletStoreServiceSubmitAppStateForwardsExactPayload(t *testing.T) { +func TestWalletStoreServiceCreateSessionRequiresFundedHomeChannel(t *testing.T) { t.Parallel() userSigner := mustTestSigner(t) appSigner := mustStoreAppSigner(t) client := &testsupport.FakeClient{ - GetBalancesFunc: func(context.Context, string) ([]core.BalanceEntry, error) { - return []core.BalanceEntry{{Asset: "yusd", Balance: decimal.RequireFromString("7")}}, nil + GetAppsFunc: func(context.Context, *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) { + return []app.AppInfoV1{{App: app.AppV1{ID: "store"}}}, core.PaginationMetadata{}, nil + }, + GetLatestStateFunc: func(context.Context, string, string, bool) (*core.State, error) { + return nil, nil }, } manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ @@ -141,107 +178,143 @@ func TestWalletStoreServiceSubmitAppStateForwardsExactPayload(t *testing.T) { t.Cleanup(func() { _ = appStore.Close() }) service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") - service.now = func() time.Time { return time.Unix(1_700_000_000, 0).UTC() } + service.createAppSessionRPC = func(context.Context, string, rpc.AppSessionsV1CreateAppSessionRequest) (*rpc.AppSessionsV1CreateAppSessionResponse, error) { + t.Fatal("createAppSessionRPC must not be called without a funded home channel") + return nil, nil + } - currentSession := app.AppSessionInfoV1{ - AppSessionID: "0xsession", - AppDefinition: app.AppDefinitionV1{ - ApplicationID: "store", - Participants: []app.AppParticipantV1{ + definition := app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + } + sessionData := `{"intent":"init"}` + userSig, err := signCreateAppSessionRequest(definition, sessionData, userSigner) + if err != nil { + t.Fatalf("signCreateAppSessionRequest() error = %v", err) + } + + _, err = service.CreateSession(context.Background(), StoreInitRequest{ + Asset: "yusd", + Definition: rpc.AppDefinitionV1{ + Application: "store", + Participants: []rpc.AppParticipantV1{ {WalletAddress: userSigner.Address(), SignatureWeight: 1}, {WalletAddress: appSigner.Address(), SignatureWeight: 1}, }, Quorum: 2, - Nonce: 1, - }, - Version: 1, - SessionData: `{"action":"deposit","amount":"1.00"}`, - Allocations: []app.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + Nonce: "1", }, + SessionData: sessionData, + UserSignature: userSig, + }) + if err == nil { + t.Fatal("CreateSession() accepted a wallet without a funded home channel") } - client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { - return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil - } - if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ - WalletAddress: userSigner.Address(), - Asset: "yusd", - AppSessionID: currentSession.AppSessionID, - Status: "open", - Version: currentSession.Version, - UserAllocation: "1", - AppAllocation: "0", - SessionData: currentSession.SessionData, - CreatedAt: time.Unix(1_700_000_000, 0).UTC(), - UpdatedAt: time.Unix(1_700_000_000, 0).UTC(), - }); err != nil { - t.Fatalf("UpsertWalletSession() error = %v", err) + var conflict ConflictError + if !errors.As(err, &conflict) || conflict.Code() != "channel_funds_required" { + t.Fatalf("CreateSession() error = %#v, want channel_funds_required conflict", err) } +} - update := app.AppStateUpdateV1{ - AppSessionID: currentSession.AppSessionID, - Intent: app.AppStateUpdateIntentWithdraw, - Version: 2, - Allocations: []app.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.5")}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, +func TestWalletStoreServiceBootstrapReportsAckRequiredChannel(t *testing.T) { + t.Parallel() + + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, signed bool) (*core.State, error) { + if signed { + return nil, errors.New("signed state not found") + } + return fundedHomeState(wallet, asset, "5"), nil }, - SessionData: `{"action":"user_withdraw","amount":"0.50"}`, } - userSig, err := signAppStateUpdate(update, userSigner) + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) if err != nil { - t.Fatalf("signAppStateUpdate() error = %v", err) - } - rpcUpdate := rpc.AppStateUpdateV1{ - AppSessionID: update.AppSessionID, - Intent: update.Intent, - Version: "2", - Allocations: []rpc.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: "0.5"}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, - }, - SessionData: update.SessionData, + t.Fatalf("store.New() error = %v", err) } + t.Cleanup(func() { _ = appStore.Close() }) - var captured rpc.AppSessionsV1SubmitAppStateRequest - service.submitAppStateRPC = func(ctx context.Context, wsURL string, req rpc.AppSessionsV1SubmitAppStateRequest) error { - captured = req - currentSession.Version = update.Version - currentSession.SessionData = update.SessionData - currentSession.Allocations = update.Allocations - return nil + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + resp, err := service.Bootstrap(context.Background(), "0x1111111111111111111111111111111111111111", "yusd") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) + } + if resp.ChannelReadiness.Status != "ack_required" { + t.Fatalf("channel_readiness.status = %q, want ack_required", resp.ChannelReadiness.Status) } + if resp.AvailableBalance != "0" { + t.Fatalf("available_balance = %q, want 0", resp.AvailableBalance) + } + if resp.ChannelReadiness.PendingBalance != "5" { + t.Fatalf("pending_balance = %q, want 5", resp.ChannelReadiness.PendingBalance) + } + if resp.ChannelReadiness.RequiresChannelCreation { + t.Fatal("requires_channel_creation = true, want false") + } +} - resp, err := service.SubmitUpdate(context.Background(), userSigner.Address(), StoreUpdateRequest{ - Asset: "yusd", - Kind: storeUpdateKindAppState, - AppStateUpdate: &rpcUpdate, - UserSignature: userSig, - }) +func TestWalletStoreServiceBootstrapReportsAckRequiredForReceivedFundsWithoutHomeChannel(t *testing.T) { + t.Parallel() + + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, signed bool) (*core.State, error) { + if signed { + return nil, errors.New("signed state not found") + } + return receivedOffchainState(wallet, asset, "5"), nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) if err != nil { - t.Fatalf("SubmitUpdate() error = %v", err) + t.Fatalf("store.New() error = %v", err) } + t.Cleanup(func() { _ = appStore.Close() }) - if !reflect.DeepEqual(captured.AppStateUpdate, rpcUpdate) { - t.Fatalf("app_state_update mismatch\n got: %#v\nwant: %#v", captured.AppStateUpdate, rpcUpdate) + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + resp, err := service.Bootstrap(context.Background(), "0x1111111111111111111111111111111111111111", "yusd") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) } - if len(captured.QuorumSigs) != 2 || captured.QuorumSigs[0] != userSig || captured.QuorumSigs[1] == "" { - t.Fatalf("unexpected quorum signatures = %#v", captured.QuorumSigs) + if resp.ChannelReadiness.Status != "ack_required" { + t.Fatalf("channel_readiness.status = %q, want ack_required", resp.ChannelReadiness.Status) } - if resp.Session.Version != 2 || resp.Session.UserAllocation != "0.5" { - t.Fatalf("unexpected response session = %#v", resp.Session) + if !resp.ChannelReadiness.RequiresChannelCreation { + t.Fatal("requires_channel_creation = false, want true") + } + if resp.AvailableBalance != "0" { + t.Fatalf("available_balance = %q, want 0", resp.AvailableBalance) + } + if resp.ChannelReadiness.PendingBalance != "5" { + t.Fatalf("pending_balance = %q, want 5", resp.ChannelReadiness.PendingBalance) } } -func TestWalletStoreServiceSubmitPurchaseAcceptsNormalizedPriceString(t *testing.T) { +func TestWalletStoreServiceBootstrapKeepsSignedNoHomeChannelStateInSetup(t *testing.T) { t.Parallel() - userSigner := mustTestSigner(t) appSigner := mustStoreAppSigner(t) + userSig := "0xsigned" client := &testsupport.FakeClient{ - GetBalancesFunc: func(context.Context, string) ([]core.BalanceEntry, error) { - return []core.BalanceEntry{{Asset: "yusd", Balance: decimal.RequireFromString("7")}}, nil + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + state := receivedOffchainState(wallet, asset, "5") + state.UserSig = &userSig + return state, nil }, } manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ @@ -256,97 +329,1563 @@ func TestWalletStoreServiceSubmitPurchaseAcceptsNormalizedPriceString(t *testing t.Cleanup(func() { _ = appStore.Close() }) service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") - service.now = func() time.Time { return time.Unix(1_700_000_000, 0).UTC() } - - currentSession := app.AppSessionInfoV1{ - AppSessionID: "0xsession", - AppDefinition: app.AppDefinitionV1{ - ApplicationID: "store", - Participants: []app.AppParticipantV1{ - {WalletAddress: userSigner.Address(), SignatureWeight: 1}, - {WalletAddress: appSigner.Address(), SignatureWeight: 1}, - }, - Quorum: 2, - Nonce: 1, - }, - Version: 1, - SessionData: `{"action":"deposit","amount":"1.00"}`, - Allocations: []app.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, - }, + resp, err := service.Bootstrap(context.Background(), "0x1111111111111111111111111111111111111111", "yusd") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) } - client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { - return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil + if resp.ChannelReadiness.Status != "ack_required" { + t.Fatalf("channel_readiness.status = %q, want ack_required", resp.ChannelReadiness.Status) } - if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ - WalletAddress: userSigner.Address(), - Asset: "yusd", - AppSessionID: currentSession.AppSessionID, - Status: "open", - Version: currentSession.Version, - UserAllocation: "1", - AppAllocation: "0", - SessionData: currentSession.SessionData, - CreatedAt: time.Unix(1_700_000_000, 0).UTC(), - UpdatedAt: time.Unix(1_700_000_000, 0).UTC(), - }); err != nil { - t.Fatalf("UpsertWalletSession() error = %v", err) + if !resp.ChannelReadiness.RequiresChannelCreation { + t.Fatal("requires_channel_creation = false, want true") } + if resp.AvailableBalance != "0" { + t.Fatalf("available_balance = %q, want 0", resp.AvailableBalance) + } +} - update := app.AppStateUpdateV1{ - AppSessionID: currentSession.AppSessionID, - Intent: app.AppStateUpdateIntentOperate, - Version: 2, - Allocations: []app.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.5")}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.5")}, +func TestWalletStoreServiceBootstrapReportsAckRequiredWhenPendingReleaseIsNewer(t *testing.T) { + t.Parallel() + + appSigner := mustStoreAppSigner(t) + userSig := "0xsigned" + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, signed bool) (*core.State, error) { + if signed { + state := fundedHomeState(wallet, asset, "0.5") + state.ID = "0xsignedstate" + state.Version = 4 + state.UserSig = &userSig + return state, nil + } + state := fundedHomeState(wallet, asset, "10") + state.ID = "0xpendingrelease" + state.Version = 5 + state.Transition.Type = core.TransitionTypeRelease + state.Transition.Amount = decimal.RequireFromString("9.5") + return state, nil }, - SessionData: `{"action":"purchase","item_id":"article-micropayments","price":"0.5"}`, } - userSig, err := signAppStateUpdate(update, userSigner) + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) if err != nil { - t.Fatalf("signAppStateUpdate() error = %v", err) - } - rpcUpdate := rpc.AppStateUpdateV1{ - AppSessionID: update.AppSessionID, - Intent: update.Intent, - Version: "2", - Allocations: []rpc.AppAllocationV1{ - {Participant: userSigner.Address(), Asset: "yusd", Amount: "0.5"}, - {Participant: appSigner.Address(), Asset: "yusd", Amount: "0.5"}, - }, - SessionData: update.SessionData, + t.Fatalf("store.New() error = %v", err) } + t.Cleanup(func() { _ = appStore.Close() }) - service.submitAppStateRPC = func(context.Context, string, rpc.AppSessionsV1SubmitAppStateRequest) error { - currentSession.Version = update.Version - currentSession.SessionData = update.SessionData - currentSession.Allocations = update.Allocations - return nil + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yellow": 11155111}, "wss://example.invalid") + resp, err := service.Bootstrap(context.Background(), "0x1111111111111111111111111111111111111111", "yellow") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) + } + if resp.ChannelReadiness.Status != "ack_required" { + t.Fatalf("channel_readiness.status = %q, want ack_required", resp.ChannelReadiness.Status) + } + if resp.AvailableBalance != "0.5" { + t.Fatalf("available_balance = %q, want 0.5", resp.AvailableBalance) + } + if resp.ChannelReadiness.PendingBalance != "10" { + t.Fatalf("pending_balance = %q, want 10", resp.ChannelReadiness.PendingBalance) } + if resp.ChannelReadiness.PendingTransition != "release" { + t.Fatalf("pending_transition = %q, want release", resp.ChannelReadiness.PendingTransition) + } + if resp.ChannelReadiness.PendingAmount != "9.5" { + t.Fatalf("pending_amount = %q, want 9.5", resp.ChannelReadiness.PendingAmount) + } + if resp.ChannelReadiness.RequiresChannelCreation { + t.Fatal("requires_channel_creation = true, want false") + } +} - resp, err := service.SubmitUpdate(context.Background(), userSigner.Address(), StoreUpdateRequest{ - Asset: "yusd", - Kind: storeUpdateKindAppState, - AppStateUpdate: &rpcUpdate, - UserSignature: userSig, - }) +func TestWalletStoreServiceBootstrapReportsDepositRequiredChannel(t *testing.T) { + t.Parallel() + + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(context.Context, string, string, bool) (*core.State, error) { + return nil, errors.New("state not found") + }, + GetOnChainBalanceFunc: func(_ context.Context, chainID uint64, asset string, wallet string) (decimal.Decimal, error) { + if chainID != 11155111 { + t.Fatalf("chainID = %d, want 11155111", chainID) + } + if asset != "yellow" { + t.Fatalf("asset = %q, want yellow", asset) + } + if wallet != "0x1111111111111111111111111111111111111111" { + t.Fatalf("wallet = %q, want test wallet", wallet) + } + return decimal.RequireFromString("3"), nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) if err != nil { - t.Fatalf("SubmitUpdate() error = %v", err) + t.Fatalf("store.New() error = %v", err) } + t.Cleanup(func() { _ = appStore.Close() }) - if len(resp.Library) != 1 || resp.Library[0].ID != "article-micropayments" { - t.Fatalf("unexpected library = %#v", resp.Library) + service := NewWalletStoreService( + manager, + appStore, + appSigner, + "Nitrolite App Session Store", + "store", + map[string]uint64{"yellow": 11155111, "yusd": 11155111}, + "wss://example.invalid", + map[string]string{"yellow": "12"}, + ) + resp, err := service.Bootstrap(context.Background(), "0x1111111111111111111111111111111111111111", "yellow") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) + } + if resp.ChannelReadiness.Status != "deposit_required" { + t.Fatalf("channel_readiness.status = %q, want deposit_required", resp.ChannelReadiness.Status) + } + if resp.ChannelReadiness.OnChainBalance != "3" { + t.Fatalf("on_chain_balance = %q, want 3", resp.ChannelReadiness.OnChainBalance) + } + if resp.ChannelReadiness.BootstrapAmount != "12" { + t.Fatalf("bootstrap_amount = %q, want 12", resp.ChannelReadiness.BootstrapAmount) + } + if resp.ChannelReadiness.RequiresChannelCreation { + t.Fatal("requires_channel_creation = true, want false") } } -func mustStoreAppSigner(t *testing.T) appsigning.Signer { - t.Helper() +func TestWalletStoreServiceEnsureAppSkipsDisabledRegistry(t *testing.T) { + t.Parallel() - signer, err := appsigning.NewStoreAppSigner("", serviceTestPrivateKey) - if err != nil { - t.Fatalf("NewStoreAppSigner() error = %v", err) + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetAppsFunc: func(context.Context, *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) { + return nil, core.PaginationMetadata{}, errors.New("rpc returned error: apps.v1 group is disabled") + }, + RegisterAppFunc: func(context.Context, string, string, bool) error { + t.Fatal("RegisterApp must not be called when apps.v1 is disabled") + return nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + if err := service.ensureApp(context.Background()); err != nil { + t.Fatalf("ensureApp() error = %v, want nil when apps.v1 is disabled", err) + } +} + +func TestCrossLanguagePackSignVectors(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + if !strings.EqualFold(userSigner.Address(), "0x20bcbc2e9f2ee516f2f4881cf8aa0baab49cb072") { + t.Fatalf("unexpected user signer address = %s", userSigner.Address()) + } + if !strings.EqualFold(appSigner.Address(), "0x999455567acde6d73e89f6d6c11084f866e33bbb") { + t.Fatalf("unexpected app signer address = %s", appSigner.Address()) + } + + definition := app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1_700_000_000_000_000, + } + sessionData := `{"intent":"init"}` + createPayload, err := app.PackCreateAppSessionRequestV1(definition, sessionData) + if err != nil { + t.Fatalf("PackCreateAppSessionRequestV1() error = %v", err) + } + if got, want := hexutil.Encode(createPayload), "0xa0d3febab481191730b66807bee278eba25d45431be0b408284ae27a7d897b4a"; got != want { + t.Fatalf("create payload = %s, want TypeScript vector %s", got, want) + } + createSig, err := signCreateAppSessionRequest(definition, sessionData, userSigner) + if err != nil { + t.Fatalf("signCreateAppSessionRequest() error = %v", err) + } + if err := verifyCreateSessionSignature(userSigner.Address(), definition, sessionData, createSig); err != nil { + t.Fatalf("verifyCreateSessionSignature() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: "0x0000000000000000000000000000000000000000000000000000000000000009", + Intent: app.AppStateUpdateIntentOperate, + Version: 4, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.1")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.9")}, + }, + SessionData: `{"intent":"purchase","item_id":1,"item_price":"0.9"}`, + } + updatePayload, err := app.PackAppStateUpdateV1(update) + if err != nil { + t.Fatalf("PackAppStateUpdateV1() error = %v", err) + } + if got, want := hexutil.Encode(updatePayload), "0x73fa52d896b17c36e3a4131b9dd609c627c55aac779d616dc0db821d0b75249a"; got != want { + t.Fatalf("update payload = %s, want TypeScript vector %s", got, want) + } + updateSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + if err := verifyAppStateSignature(userSigner.Address(), update, updateSig); err != nil { + t.Fatalf("verifyAppStateSignature() error = %v", err) + } +} + +func TestWalletStoreServiceCreateSessionRejectsWrongSignature(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetAppsFunc: func(context.Context, *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) { + return []app.AppInfoV1{{App: app.AppV1{ID: "store"}}}, core.PaginationMetadata{}, nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + service.createAppSessionRPC = func(context.Context, string, rpc.AppSessionsV1CreateAppSessionRequest) (*rpc.AppSessionsV1CreateAppSessionResponse, error) { + t.Fatal("createAppSessionRPC was called for an invalid signature") + return nil, nil + } + + definition := app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + } + sessionData := `{"intent":"init"}` + wrongSig, err := signCreateAppSessionRequest(definition, sessionData, appSigner) + if err != nil { + t.Fatalf("signCreateAppSessionRequest() error = %v", err) + } + + _, err = service.CreateSession(context.Background(), StoreInitRequest{ + Asset: "yusd", + Definition: rpc.AppDefinitionV1{ + Application: "store", + Participants: []rpc.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: "1", + }, + SessionData: sessionData, + UserSignature: wrongSig, + }) + if err == nil { + t.Fatal("CreateSession() accepted wrong signature") + } + var conflict ConflictError + if !errors.As(err, &conflict) || conflict.Code() != "invalid_signature" { + t.Fatalf("CreateSession() error = %#v, want invalid_signature conflict", err) + } +} + +func TestWalletStoreServiceSubmitAppStateForwardsExactPayload(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "7"), nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + service.now = func() time.Time { return time.Unix(1_700_000_000, 0).UTC() } + + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { + return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil + } + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: time.Unix(1_700_000_000, 0).UTC(), + UpdatedAt: time.Unix(1_700_000_000, 0).UTC(), + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentWithdraw, + Version: 2, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.5")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + SessionData: `{"intent":"user_withdraw","amount":"0.50"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "0.5"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, + }, + SessionData: update.SessionData, + } + + var captured rpc.AppSessionsV1SubmitAppStateRequest + service.submitAppStateRPC = func(ctx context.Context, wsURL string, req rpc.AppSessionsV1SubmitAppStateRequest) error { + captured = req + currentSession.Version = update.Version + currentSession.SessionData = update.SessionData + currentSession.Allocations = update.Allocations + return nil + } + + resp, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err != nil { + t.Fatalf("SubmitUpdate() error = %v", err) + } + + if !reflect.DeepEqual(captured.AppStateUpdate, rpcUpdate) { + t.Fatalf("app_state_update mismatch\n got: %#v\nwant: %#v", captured.AppStateUpdate, rpcUpdate) + } + if len(captured.QuorumSigs) != 2 || captured.QuorumSigs[0] != userSig || captured.QuorumSigs[1] == "" { + t.Fatalf("unexpected quorum signatures = %#v", captured.QuorumSigs) + } + if resp.Bootstrap == nil || resp.Bootstrap.Session.Version != 2 || resp.Bootstrap.Session.UserAllocation != "0.5" { + t.Fatalf("unexpected response = %#v", resp) + } +} + +func TestWalletStoreServiceSubmitWithdrawAcceptsIntentOnlySessionData(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "7"), nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + service.now = func() time.Time { return time.Unix(1_700_000_000, 0).UTC() } + + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 2, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + }, + } + client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { + return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil + } + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: time.Unix(1_700_000_000, 0).UTC(), + UpdatedAt: time.Unix(1_700_000_000, 0).UTC(), + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentWithdraw, + Version: 3, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.5")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + SessionData: `{"intent":"user_withdraw"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "3", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "0.5"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, + }, + SessionData: update.SessionData, + } + + service.submitAppStateRPC = func(ctx context.Context, wsURL string, req rpc.AppSessionsV1SubmitAppStateRequest) error { + currentSession.Version = update.Version + currentSession.SessionData = update.SessionData + currentSession.Allocations = update.Allocations + return nil + } + + resp, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err != nil { + t.Fatalf("SubmitUpdate() error = %v", err) + } + if resp.Bootstrap == nil || resp.Bootstrap.Session.Version != 3 || resp.Bootstrap.Session.UserAllocation != "0.5" { + t.Fatalf("unexpected response = %#v", resp) + } +} + +func TestWalletStoreServiceRejectsStaleUpdateVersion(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 2, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentDeposit, + Version: currentSession.Version, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("2.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + SessionData: `{"intent":"user_deposit"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "2.0"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, + }, + SessionData: update.SessionData, + } + + _, err = service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err == nil { + t.Fatal("SubmitUpdate() accepted stale version") + } + var conflict ConflictError + if !errors.As(err, &conflict) || conflict.Code() != "stale_version" { + t.Fatalf("SubmitUpdate() error = %#v, want stale_version conflict", err) + } +} + +func TestWalletStoreServiceSubmitDepositAcceptsInitialEmptyAllocations(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "7"), nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + service.now = func() time.Time { return time.Unix(1_700_000_000, 0).UTC() } + + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"init"}`, + } + client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { + return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil + } + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "0", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: time.Unix(1_700_000_000, 0).UTC(), + UpdatedAt: time.Unix(1_700_000_000, 0).UTC(), + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentDeposit, + Version: 2, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + SessionData: `{"intent":"user_deposit"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "1.0"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, + }, + SessionData: update.SessionData, + } + + resp, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err != nil { + t.Fatalf("SubmitUpdate() error = %v", err) + } + if resp.Status != "signed" || resp.Intent != string(StoreIntentUserDeposit) || resp.AppSignature == "" { + t.Fatalf("unexpected response = %#v", resp) + } + if resp.PendingAction == nil || resp.PendingAction.Type != string(StoreIntentUserDeposit) || resp.PendingAction.Amount != "1" { + t.Fatalf("unexpected pending deposit action = %#v", resp.PendingAction) + } + bootstrap, err := service.Bootstrap(context.Background(), userSigner.Address(), "yusd") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) + } + if bootstrap.PendingAction == nil || bootstrap.PendingAction.AppSignature != resp.AppSignature || bootstrap.PendingAction.AppStateUpdate.Version != "2" { + t.Fatalf("bootstrap pending action = %#v, want resumable deposit", bootstrap.PendingAction) + } +} + +func TestWalletStoreServiceSubmitDepositRejectsAmountAboveAvailableBalance(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"init"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "0.5"), nil + }, + GetAppSessionsFunc: func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { + return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + service.now = func() time.Time { return now } + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "0", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentDeposit, + Version: 2, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + SessionData: `{"intent":"user_deposit","amount":"1"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "1.0"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, + }, + SessionData: update.SessionData, + } + + _, err = service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err == nil { + t.Fatal("SubmitUpdate() accepted over-balance deposit") + } + var conflict ConflictError + if !errors.As(err, &conflict) || conflict.Code() != "insufficient_balance" { + t.Fatalf("SubmitUpdate() error = %#v, want insufficient_balance conflict", err) + } + if _, err := appStore.GetActiveDepositCheckpoint(context.Background(), userSigner.Address(), "yusd"); !errors.Is(err, store.ErrNotFound) { + t.Fatalf("active checkpoint error = %v, want ErrNotFound", err) + } +} + +func TestWalletStoreServiceBootstrapReconcilesDepositCheckpoint(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + sessionData := `{"intent":"user_deposit","amount":"1"}` + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 2, + SessionData: sessionData, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: 1, + UserAllocation: "0", + AppAllocation: "0", + SessionData: `{"intent":"init"}`, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentDeposit, + Version: currentSession.Version, + Allocations: currentSession.Allocations, + SessionData: sessionData, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + appSig, err := signAppStateUpdate(update, appSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() app error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "1.0"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0"}, + }, + SessionData: update.SessionData, + } + updateJSON, err := json.Marshal(rpcUpdate) + if err != nil { + t.Fatalf("json.Marshal() error = %v", err) + } + checkpointID := store.WalletDepositCheckpointID(userSigner.Address(), "yusd") + if err := appStore.UpsertDepositCheckpoint(context.Background(), store.WalletDepositCheckpoint{ + ID: checkpointID, + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Version: currentSession.Version, + Amount: "1", + Status: store.WalletDepositCheckpointStatusAppSigned, + AppStateUpdate: string(updateJSON), + UserSignature: userSig, + AppSignature: appSig, + SessionData: sessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertDepositCheckpoint() error = %v", err) + } + + resp, err := service.Bootstrap(context.Background(), userSigner.Address(), "yusd") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) + } + if resp.PendingAction != nil || resp.Session.Version != currentSession.Version || resp.Session.UserAllocation != "1" { + t.Fatalf("bootstrap = %#v, want reconciled deposit checkpoint", resp) + } + if _, err := appStore.GetActiveDepositCheckpoint(context.Background(), userSigner.Address(), "yusd"); !errors.Is(err, store.ErrNotFound) { + t.Fatalf("active checkpoint error = %v, want ErrNotFound", err) + } +} + +func TestWalletStoreServiceSubmitPurchaseAcceptsNormalizedPriceString(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "7"), nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111}, "wss://example.invalid") + service.now = func() time.Time { return time.Unix(1_700_000_000, 0).UTC() } + + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + client.GetAppSessionsFunc = func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { + return []app.AppSessionInfoV1{currentSession}, core.PaginationMetadata{}, nil + } + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: time.Unix(1_700_000_000, 0).UTC(), + UpdatedAt: time.Unix(1_700_000_000, 0).UTC(), + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentOperate, + Version: 2, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.1")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.9")}, + }, + SessionData: `{"intent":"purchase","item_id":1,"item_price":"0.9"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "0.1"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0.9"}, + }, + SessionData: update.SessionData, + } + + service.submitAppStateRPC = func(context.Context, string, rpc.AppSessionsV1SubmitAppStateRequest) error { + currentSession.Version = update.Version + currentSession.SessionData = update.SessionData + currentSession.Allocations = update.Allocations + return nil + } + + resp, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err != nil { + t.Fatalf("SubmitUpdate() error = %v", err) + } + + if resp.Bootstrap == nil || len(resp.Bootstrap.Library) != 1 || resp.Bootstrap.Library[0].ID != "1" { + t.Fatalf("unexpected response = %#v", resp) + } +} + +func TestWalletStoreServiceContentUsesPublicSubmittedPurchaseGate(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 2, + SessionData: `{"intent":"purchase","item_id":1,"item_price":"0.9"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.1")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.9")}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "0.1", + AppAllocation: "0.9", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + if err := appStore.UpsertPendingWalletPurchase(context.Background(), store.WalletPurchase{ + ID: store.WalletPurchaseID(userSigner.Address(), "yusd", "1"), + WalletAddress: userSigner.Address(), + ItemID: "1", + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Version: currentSession.Version, + Status: store.WalletPurchaseStatusPending, + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + PurchasedAt: now, + }); err != nil { + t.Fatalf("UpsertPendingWalletPurchase() error = %v", err) + } + if err := appStore.MarkWalletPurchaseSubmitted(context.Background(), store.WalletPurchaseID(userSigner.Address(), "yusd", "1"), now); err != nil { + t.Fatalf("MarkWalletPurchaseSubmitted() error = %v", err) + } + + if _, err := service.Content(context.Background(), "1", StoreContentRequest{Asset: "yusd"}); err == nil { + t.Fatal("Content() without wallet succeeded") + } + + otherWallet := mustSignerFromKey(t, serviceTestPrivateKey).Address() + if _, err := service.Content(context.Background(), "1", StoreContentRequest{WalletAddress: otherWallet, Asset: "yusd"}); err == nil { + t.Fatal("Content() for wallet without store session succeeded") + } + + item, err := service.Content(context.Background(), "1", StoreContentRequest{WalletAddress: userSigner.Address(), Asset: "yusd"}) + if err != nil { + t.Fatalf("Content() error = %v", err) + } + if item.ID != "1" || item.Content == "" { + t.Fatalf("unexpected content item = %#v", item) + } +} + +func TestWalletStoreServiceYellowPurchaseAndPublicRead(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xyellowsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yellow", Amount: decimal.RequireFromString("2.0")}, + {Participant: appSigner.Address(), Asset: "yellow", Amount: decimal.Zero}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yellow", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "2.0", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentOperate, + Version: 2, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yellow", Amount: decimal.RequireFromString("0.65")}, + {Participant: appSigner.Address(), Asset: "yellow", Amount: decimal.RequireFromString("1.35")}, + }, + SessionData: `{"intent":"purchase","item_id":1,"item_price":"1.35"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yellow", Amount: "0.65"}, + {Participant: appSigner.Address(), Asset: "yellow", Amount: "1.35"}, + }, + SessionData: update.SessionData, + } + + service.submitAppStateRPC = func(context.Context, string, rpc.AppSessionsV1SubmitAppStateRequest) error { + currentSession.Version = update.Version + currentSession.SessionData = update.SessionData + currentSession.Allocations = update.Allocations + return nil + } + + resp, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yellow", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err != nil { + t.Fatalf("SubmitUpdate() yellow error = %v", err) + } + if resp.Bootstrap == nil || len(resp.Bootstrap.Library) != 1 || resp.Bootstrap.Library[0].Price != "1.35" { + t.Fatalf("unexpected yellow purchase response = %#v", resp) + } + + item, err := service.Content(context.Background(), "1", StoreContentRequest{WalletAddress: userSigner.Address(), Asset: "yellow"}) + if err != nil { + t.Fatalf("Content() yellow error = %v", err) + } + if item.Prices["yellow"] != "1.35" || item.Content == "" { + t.Fatalf("unexpected yellow content item = %#v", item) + } +} + +func TestWalletStoreServiceContentRejectsUnpurchasedItem(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"init"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + if _, err := service.Content(context.Background(), "1", StoreContentRequest{WalletAddress: userSigner.Address(), Asset: "yusd"}); err == nil { + t.Fatal("Content() succeeded for unpurchased item") + } +} + +func TestWalletStoreServiceBootstrapReconcilesPendingPurchase(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + sessionData := `{"intent":"purchase","item_id":1,"item_price":"0.9"}` + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 2, + SessionData: sessionData, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.1")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.9")}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: 1, + UserAllocation: "1", + AppAllocation: "0", + SessionData: `{"intent":"user_deposit"}`, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + if err := appStore.UpsertPendingWalletPurchase(context.Background(), store.WalletPurchase{ + ID: store.WalletPurchaseID(userSigner.Address(), "yusd", "1"), + WalletAddress: userSigner.Address(), + ItemID: "1", + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Version: currentSession.Version, + Status: store.WalletPurchaseStatusPending, + SessionData: sessionData, + CreatedAt: now, + UpdatedAt: now, + PurchasedAt: now, + }); err != nil { + t.Fatalf("UpsertPendingWalletPurchase() error = %v", err) + } + + resp, err := service.Bootstrap(context.Background(), userSigner.Address(), "yusd") + if err != nil { + t.Fatalf("Bootstrap() error = %v", err) + } + if len(resp.Library) != 1 || resp.Library[0].ID != "1" { + t.Fatalf("library = %#v, want reconciled item 1", resp.Library) + } +} + +func TestWalletStoreServiceSubmitPurchaseFailureDoesNotUnlockAndCanRetry(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + + update, rpcUpdate, userSig := signedPurchaseUpdate(t, userSigner, appSigner, currentSession) + service.submitAppStateRPC = func(context.Context, string, rpc.AppSessionsV1SubmitAppStateRequest) error { + return errors.New("nitronode rejected stale app version") + } + + if _, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }); err == nil { + t.Fatal("SubmitUpdate() succeeded despite Nitronode error") + } else if got, want := err.Error(), "failed to submit app state: nitronode rejected stale app version"; got != want { + t.Fatalf("SubmitUpdate() error = %q, want %q", got, want) + } + owned, err := appStore.HasWalletPurchase(context.Background(), userSigner.Address(), "1", "yusd") + if err != nil { + t.Fatalf("HasWalletPurchase() error = %v", err) + } + if owned { + t.Fatal("failed purchase was unlocked") + } + + service.submitAppStateRPC = func(context.Context, string, rpc.AppSessionsV1SubmitAppStateRequest) error { + currentSession.Version = update.Version + currentSession.SessionData = update.SessionData + currentSession.Allocations = update.Allocations + return nil + } + resp, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }) + if err != nil { + t.Fatalf("SubmitUpdate() retry error = %v", err) + } + if resp.Bootstrap == nil || len(resp.Bootstrap.Library) != 1 { + t.Fatalf("retry did not unlock purchase: %#v", resp) + } +} + +func TestWalletStoreServiceDuplicateSubmittedPurchaseRejected(t *testing.T) { + t.Parallel() + + userSigner := mustTestSigner(t) + appSigner := mustStoreAppSigner(t) + now := time.Unix(1_700_000_000, 0).UTC() + currentSession := app.AppSessionInfoV1{ + AppSessionID: "0xsession", + AppDefinition: app.AppDefinitionV1{ + ApplicationID: "store", + Participants: []app.AppParticipantV1{ + {WalletAddress: userSigner.Address(), SignatureWeight: 1}, + {WalletAddress: appSigner.Address(), SignatureWeight: 1}, + }, + Quorum: 2, + Nonce: 1, + }, + Version: 1, + SessionData: `{"intent":"user_deposit"}`, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("1.0")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.Zero}, + }, + } + service, appStore := newWalletStoreServiceForTest(t, userSigner, appSigner, ¤tSession) + service.now = func() time.Time { return now } + + if err := appStore.UpsertWalletSession(context.Background(), store.WalletStoreSession{ + WalletAddress: userSigner.Address(), + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Status: "open", + Version: currentSession.Version, + UserAllocation: "1", + AppAllocation: "0", + SessionData: currentSession.SessionData, + CreatedAt: now, + UpdatedAt: now, + }); err != nil { + t.Fatalf("UpsertWalletSession() error = %v", err) + } + if err := appStore.UpsertPendingWalletPurchase(context.Background(), store.WalletPurchase{ + ID: store.WalletPurchaseID(userSigner.Address(), "yusd", "1"), + WalletAddress: userSigner.Address(), + ItemID: "1", + Asset: "yusd", + AppSessionID: currentSession.AppSessionID, + Version: 2, + Status: store.WalletPurchaseStatusPending, + SessionData: `{"intent":"purchase","item_id":1,"item_price":"0.9"}`, + CreatedAt: now, + UpdatedAt: now, + PurchasedAt: now, + }); err != nil { + t.Fatalf("UpsertPendingWalletPurchase() error = %v", err) + } + if err := appStore.MarkWalletPurchaseSubmitted(context.Background(), store.WalletPurchaseID(userSigner.Address(), "yusd", "1"), now); err != nil { + t.Fatalf("MarkWalletPurchaseSubmitted() error = %v", err) + } + + _, rpcUpdate, userSig := signedPurchaseUpdate(t, userSigner, appSigner, currentSession) + if _, err := service.SubmitUpdate(context.Background(), StoreUpdateRequest{ + Asset: "yusd", + AppStateUpdate: &rpcUpdate, + UserSignature: userSig, + }); err == nil { + t.Fatal("SubmitUpdate() duplicate purchase succeeded") + } else { + var conflict ConflictError + if !errors.As(err, &conflict) || conflict.Code() != "duplicate_purchase" { + t.Fatalf("SubmitUpdate() error = %#v, want duplicate_purchase conflict", err) + } + } +} + +func TestStoreCatalogIncludesYUSDAndYellowItems(t *testing.T) { + t.Parallel() + + service := NewWalletStoreService(nil, nil, mustStoreAppSigner(t), "Nitrolite App Session Store", "store", map[string]uint64{ + "yusd": 11155111, + "yellow": 11155111, + "other": 11155111, + }, "wss://example.invalid") + + if !reflect.DeepEqual(service.supportedAssets, []string{"yusd", "yellow"}) { + t.Fatalf("supportedAssets = %#v, want yusd/yellow", service.supportedAssets) + } + if len(service.catalog) != 5 { + t.Fatalf("catalog length = %d, want 5", len(service.catalog)) + } + if service.catalog[0].Prices["yusd"] != "0.9" { + t.Fatalf("item 1 yusd price = %q, want 0.9", service.catalog[0].Prices["yusd"]) + } + for _, item := range service.catalog { + if item.Prices["yusd"] == "" || item.Prices["yellow"] == "" { + t.Fatalf("catalog item missing yusd/yellow price: %#v", item) + } + } +} + +func mustTestSigner(t *testing.T) appsigning.Signer { + t.Helper() + + return mustSignerFromKey(t, serviceUserPrivateKey) +} + +func mustSignerFromKey(t *testing.T, privateKey string) appsigning.Signer { + t.Helper() + + signer, err := appsigning.NewStoreAppSigner("", privateKey) + if err != nil { + t.Fatalf("NewStoreAppSigner() error = %v", err) + } + return signer +} + +func mustStoreAppSigner(t *testing.T) appsigning.Signer { + t.Helper() + + signer, err := appsigning.NewStoreAppSigner("", serviceTestPrivateKey) + if err != nil { + t.Fatalf("NewStoreAppSigner() error = %v", err) } return signer } + +func newWalletStoreServiceForTest(t *testing.T, userSigner appsigning.Signer, appSigner appsigning.Signer, currentSession *app.AppSessionInfoV1) (*WalletStoreService, *store.Store) { + t.Helper() + + client := &testsupport.FakeClient{ + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + return fundedHomeState(wallet, asset, "7"), nil + }, + GetAppSessionsFunc: func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) { + if currentSession == nil { + return nil, core.PaginationMetadata{}, nil + } + return []app.AppSessionInfoV1{*currentSession}, core.PaginationMetadata{}, nil + }, + } + manager := nitrolite.NewManagerWithClient(client, nitrolite.Health{ + Connected: true, + Ready: true, + SignerAddress: appSigner.Address(), + }, slog.Default()) + appStore, err := store.New(filepath.Join(t.TempDir(), "store.db")) + if err != nil { + t.Fatalf("store.New() error = %v", err) + } + t.Cleanup(func() { _ = appStore.Close() }) + + service := NewWalletStoreService(manager, appStore, appSigner, "Nitrolite App Session Store", "store", map[string]uint64{"yusd": 11155111, "yellow": 11155111}, "wss://example.invalid") + _ = userSigner + return service, appStore +} + +func signedPurchaseUpdate(t *testing.T, userSigner appsigning.Signer, appSigner appsigning.Signer, currentSession app.AppSessionInfoV1) (app.AppStateUpdateV1, rpc.AppStateUpdateV1, string) { + t.Helper() + + update := app.AppStateUpdateV1{ + AppSessionID: currentSession.AppSessionID, + Intent: app.AppStateUpdateIntentOperate, + Version: currentSession.Version + 1, + Allocations: []app.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.1")}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: decimal.RequireFromString("0.9")}, + }, + SessionData: `{"intent":"purchase","item_id":1,"item_price":"0.9"}`, + } + userSig, err := signAppStateUpdate(update, userSigner) + if err != nil { + t.Fatalf("signAppStateUpdate() error = %v", err) + } + rpcUpdate := rpc.AppStateUpdateV1{ + AppSessionID: update.AppSessionID, + Intent: update.Intent, + Version: "2", + Allocations: []rpc.AppAllocationV1{ + {Participant: userSigner.Address(), Asset: "yusd", Amount: "0.1"}, + {Participant: appSigner.Address(), Asset: "yusd", Amount: "0.9"}, + }, + SessionData: update.SessionData, + } + return update, rpcUpdate, userSig +} diff --git a/internal/store/store.go b/internal/store/store.go index 4b0a2eb..165f9d1 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -7,14 +7,11 @@ import ( "fmt" "os" "path/filepath" - "strings" "time" _ "modernc.org/sqlite" ) -const operatorLeaseName = "operator" - var ( ErrNotFound = errors.New("store: not found") ErrConflict = errors.New("store: conflict") @@ -25,65 +22,6 @@ type Store struct { now func() time.Time } -type PaymentRequest struct { - ID string - Slug string - Title string - Description string - Asset string - Amount string - Status string - OrderID string - OperationID string - CreatedAt time.Time - UpdatedAt time.Time -} - -type Order struct { - ID string - PaymentRequestID string - OperationID string - AppSessionID string - Title string - Description string - Asset string - Amount string - Status string - CreatedAt time.Time - UpdatedAt time.Time -} - -type Payout struct { - ID string - OperationID string - Asset string - Amount string - DestinationWallet string - Status string - CreatedAt time.Time - UpdatedAt time.Time -} - -type Operation struct { - ID string - Type string - ResourceID string - Status string - ErrorMessage string - Payload string - QueuedAt time.Time - StartedAt *time.Time - CompletedAt *time.Time -} - -type OperatorLease struct { - LeaseName string - SessionToken string - AcquiredAt time.Time - HeartbeatAt time.Time - ExpiresAt time.Time -} - func New(path string) (*Store, error) { if path == "" { return nil, fmt.Errorf("sqlite path is required") @@ -115,62 +53,8 @@ func (s *Store) Close() error { func (s *Store) migrate(ctx context.Context) error { stmts := []string{ `PRAGMA journal_mode = WAL;`, - `CREATE TABLE IF NOT EXISTS payment_requests ( - id TEXT PRIMARY KEY, - slug TEXT NOT NULL UNIQUE, - title TEXT NOT NULL, - description TEXT NOT NULL, - asset TEXT NOT NULL, - amount TEXT NOT NULL, - status TEXT NOT NULL, - order_id TEXT NOT NULL DEFAULT '', - operation_id TEXT NOT NULL DEFAULT '', - created_at DATETIME NOT NULL, - updated_at DATETIME NOT NULL - );`, - `CREATE TABLE IF NOT EXISTS orders ( - id TEXT PRIMARY KEY, - payment_request_id TEXT NOT NULL, - operation_id TEXT NOT NULL, - app_session_id TEXT NOT NULL DEFAULT '', - title TEXT NOT NULL, - description TEXT NOT NULL, - asset TEXT NOT NULL, - amount TEXT NOT NULL, - status TEXT NOT NULL, - created_at DATETIME NOT NULL, - updated_at DATETIME NOT NULL - );`, - `CREATE TABLE IF NOT EXISTS payouts ( - id TEXT PRIMARY KEY, - operation_id TEXT NOT NULL, - asset TEXT NOT NULL, - amount TEXT NOT NULL, - destination_wallet TEXT NOT NULL, - status TEXT NOT NULL, - created_at DATETIME NOT NULL, - updated_at DATETIME NOT NULL - );`, - `CREATE TABLE IF NOT EXISTS operations ( - id TEXT PRIMARY KEY, - type TEXT NOT NULL, - resource_id TEXT NOT NULL, - status TEXT NOT NULL, - error_message TEXT NOT NULL DEFAULT '', - payload TEXT NOT NULL DEFAULT '{}', - queued_at DATETIME NOT NULL, - started_at DATETIME, - completed_at DATETIME - );`, - `CREATE TABLE IF NOT EXISTS operator_lease ( - lease_name TEXT PRIMARY KEY, - session_token TEXT NOT NULL, - acquired_at DATETIME NOT NULL, - heartbeat_at DATETIME NOT NULL, - expires_at DATETIME NOT NULL - );`, - `CREATE TABLE IF NOT EXISTS store_sessions ( - browser_session_id TEXT NOT NULL, + `CREATE TABLE IF NOT EXISTS wallet_store_sessions ( + wallet_address TEXT NOT NULL, asset TEXT NOT NULL, app_session_id TEXT NOT NULL, status TEXT NOT NULL, @@ -180,17 +64,38 @@ func (s *Store) migrate(ctx context.Context) error { session_data TEXT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, - PRIMARY KEY (browser_session_id, asset) + PRIMARY KEY (wallet_address, asset), + UNIQUE(app_session_id, asset) );`, - `CREATE TABLE IF NOT EXISTS purchases ( + `CREATE TABLE IF NOT EXISTS wallet_purchases ( id TEXT PRIMARY KEY, - browser_session_id TEXT NOT NULL, + wallet_address TEXT NOT NULL, item_id TEXT NOT NULL, asset TEXT NOT NULL, app_session_id TEXT NOT NULL, version INTEGER NOT NULL, + status TEXT NOT NULL DEFAULT 'submitted', + session_data TEXT NOT NULL DEFAULT '', + created_at DATETIME NOT NULL DEFAULT '1970-01-01T00:00:00Z', + updated_at DATETIME NOT NULL DEFAULT '1970-01-01T00:00:00Z', purchased_at DATETIME NOT NULL, - UNIQUE(browser_session_id, item_id, asset) + UNIQUE(wallet_address, item_id, asset) + );`, + `CREATE TABLE IF NOT EXISTS wallet_deposit_checkpoints ( + id TEXT PRIMARY KEY, + wallet_address TEXT NOT NULL, + asset TEXT NOT NULL, + app_session_id TEXT NOT NULL, + version INTEGER NOT NULL, + amount TEXT NOT NULL, + status TEXT NOT NULL, + app_state_update TEXT NOT NULL, + user_signature TEXT NOT NULL, + app_signature TEXT NOT NULL, + session_data TEXT NOT NULL DEFAULT '', + created_at DATETIME NOT NULL, + updated_at DATETIME NOT NULL, + UNIQUE(wallet_address, asset) );`, } for _, stmt := range stmts { @@ -198,399 +103,50 @@ func (s *Store) migrate(ctx context.Context) error { return fmt.Errorf("sqlite migrate: %w", err) } } - return nil -} - -func (s *Store) ClearLease(ctx context.Context) error { - _, err := s.db.ExecContext(ctx, `DELETE FROM operator_lease WHERE lease_name = ?`, operatorLeaseName) - return err -} - -func (s *Store) GetLease(ctx context.Context) (*OperatorLease, error) { - row := s.db.QueryRowContext(ctx, `SELECT lease_name, session_token, acquired_at, heartbeat_at, expires_at FROM operator_lease WHERE lease_name = ?`, operatorLeaseName) - lease, err := scanLease(row) - if err != nil { - return nil, err - } - return lease, nil -} - -func (s *Store) AcquireLease(ctx context.Context, sessionToken string, ttl time.Duration) (*OperatorLease, error) { - now := s.now().UTC() - tx, err := s.db.BeginTx(ctx, nil) - if err != nil { - return nil, err - } - defer rollback(tx) - - current, err := scanLease(tx.QueryRowContext(ctx, `SELECT lease_name, session_token, acquired_at, heartbeat_at, expires_at FROM operator_lease WHERE lease_name = ?`, operatorLeaseName)) - if err != nil && !errors.Is(err, ErrNotFound) { - return nil, err - } - if current != nil && current.SessionToken != sessionToken && current.ExpiresAt.After(now) { - return nil, ErrConflict - } - lease := &OperatorLease{ - LeaseName: operatorLeaseName, - SessionToken: sessionToken, - AcquiredAt: now, - HeartbeatAt: now, - ExpiresAt: now.Add(ttl), + columnDefaults := map[string]string{ + "status": "TEXT NOT NULL DEFAULT 'submitted'", + "session_data": "TEXT NOT NULL DEFAULT ''", + "created_at": "DATETIME NOT NULL DEFAULT '1970-01-01T00:00:00Z'", + "updated_at": "DATETIME NOT NULL DEFAULT '1970-01-01T00:00:00Z'", } - _, err = tx.ExecContext(ctx, ` - INSERT INTO operator_lease (lease_name, session_token, acquired_at, heartbeat_at, expires_at) - VALUES (?, ?, ?, ?, ?) - ON CONFLICT(lease_name) DO UPDATE SET - session_token = excluded.session_token, - acquired_at = excluded.acquired_at, - heartbeat_at = excluded.heartbeat_at, - expires_at = excluded.expires_at - `, lease.LeaseName, lease.SessionToken, formatTime(lease.AcquiredAt), formatTime(lease.HeartbeatAt), formatTime(lease.ExpiresAt)) - if err != nil { - return nil, err - } - - if err := tx.Commit(); err != nil { - return nil, err - } - return lease, nil -} - -func (s *Store) ReleaseLease(ctx context.Context, sessionToken string) error { - result, err := s.db.ExecContext(ctx, `DELETE FROM operator_lease WHERE lease_name = ? AND session_token = ?`, operatorLeaseName, sessionToken) - if err != nil { - return err - } - rows, err := result.RowsAffected() - if err != nil { - return err - } - if rows == 0 { - return ErrNotFound + for column, definition := range columnDefaults { + if err := s.ensureColumn(ctx, "wallet_purchases", column, definition); err != nil { + return err + } } return nil } -func (s *Store) HeartbeatLease(ctx context.Context, sessionToken string, ttl time.Duration) (*OperatorLease, error) { - now := s.now().UTC() - expiresAt := now.Add(ttl) - result, err := s.db.ExecContext(ctx, ` - UPDATE operator_lease - SET heartbeat_at = ?, expires_at = ? - WHERE lease_name = ? AND session_token = ? - `, formatTime(now), formatTime(expiresAt), operatorLeaseName, sessionToken) - if err != nil { - return nil, err - } - rows, err := result.RowsAffected() - if err != nil { - return nil, err - } - if rows == 0 { - return nil, ErrNotFound - } - return s.GetLease(ctx) -} - -func (s *Store) ActiveLeaseForSession(ctx context.Context, sessionToken string) (*OperatorLease, error) { - lease, err := s.GetLease(ctx) +func (s *Store) ensureColumn(ctx context.Context, table string, column string, definition string) error { + rows, err := s.db.QueryContext(ctx, "PRAGMA table_info("+table+")") if err != nil { - return nil, err - } - if lease.SessionToken != sessionToken || !lease.ExpiresAt.After(s.now().UTC()) { - return nil, ErrNotFound - } - return lease, nil -} - -func (s *Store) CreatePaymentRequest(ctx context.Context, pr PaymentRequest) error { - _, err := s.db.ExecContext(ctx, ` - INSERT INTO payment_requests (id, slug, title, description, asset, amount, status, order_id, operation_id, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `, pr.ID, pr.Slug, pr.Title, pr.Description, pr.Asset, pr.Amount, pr.Status, pr.OrderID, pr.OperationID, formatTime(pr.CreatedAt), formatTime(pr.UpdatedAt)) - return err -} - -func (s *Store) GetPaymentRequestBySlug(ctx context.Context, slug string) (*PaymentRequest, error) { - row := s.db.QueryRowContext(ctx, ` - SELECT id, slug, title, description, asset, amount, status, order_id, operation_id, created_at, updated_at - FROM payment_requests - WHERE slug = ? - `, slug) - return scanPaymentRequest(row) -} - -func (s *Store) ListPaymentRequests(ctx context.Context, limit int) ([]PaymentRequest, error) { - rows, err := s.db.QueryContext(ctx, ` - SELECT id, slug, title, description, asset, amount, status, order_id, operation_id, created_at, updated_at - FROM payment_requests - ORDER BY created_at DESC - LIMIT ? - `, limit) - if err != nil { - return nil, err + return fmt.Errorf("sqlite inspect %s: %w", table, err) } defer rows.Close() - return collectPaymentRequests(rows) -} - -func (s *Store) BeginPaymentRequestProcessing(ctx context.Context, slug string, order Order, op Operation) (*PaymentRequest, *Order, *Operation, bool, error) { - now := s.now().UTC() - tx, err := s.db.BeginTx(ctx, nil) - if err != nil { - return nil, nil, nil, false, err - } - defer rollback(tx) - - pr, err := scanPaymentRequest(tx.QueryRowContext(ctx, ` - SELECT id, slug, title, description, asset, amount, status, order_id, operation_id, created_at, updated_at - FROM payment_requests - WHERE slug = ? - `, slug)) - if err != nil { - return nil, nil, nil, false, err - } - - switch pr.Status { - case "pending": - order.PaymentRequestID = pr.ID - order.Title = pr.Title - order.Description = pr.Description - order.Asset = pr.Asset - order.Amount = pr.Amount - pr.Status = "processing" - pr.OrderID = order.ID - pr.OperationID = op.ID - pr.UpdatedAt = now - - if _, err := tx.ExecContext(ctx, ` - INSERT INTO orders (id, payment_request_id, operation_id, app_session_id, title, description, asset, amount, status, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `, order.ID, order.PaymentRequestID, order.OperationID, order.AppSessionID, order.Title, order.Description, order.Asset, order.Amount, order.Status, formatTime(order.CreatedAt), formatTime(order.UpdatedAt)); err != nil { - return nil, nil, nil, false, err - } - - if _, err := tx.ExecContext(ctx, ` - INSERT INTO operations (id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - `, op.ID, op.Type, op.ResourceID, op.Status, op.ErrorMessage, op.Payload, formatTime(op.QueuedAt), nullableTime(op.StartedAt), nullableTime(op.CompletedAt)); err != nil { - return nil, nil, nil, false, err - } - if _, err := tx.ExecContext(ctx, ` - UPDATE payment_requests - SET status = ?, order_id = ?, operation_id = ?, updated_at = ? - WHERE id = ? - `, pr.Status, pr.OrderID, pr.OperationID, formatTime(pr.UpdatedAt), pr.ID); err != nil { - return nil, nil, nil, false, err - } - - if err := tx.Commit(); err != nil { - return nil, nil, nil, false, err - } - return pr, &order, &op, true, nil - - case "processing", "completed": - var existingOrder *Order - if pr.OrderID != "" { - existingOrder, err = scanOrder(tx.QueryRowContext(ctx, ` - SELECT id, payment_request_id, operation_id, app_session_id, title, description, asset, amount, status, created_at, updated_at - FROM orders WHERE id = ? - `, pr.OrderID)) - if err != nil && !errors.Is(err, ErrNotFound) { - return nil, nil, nil, false, err - } - } - var existingOp *Operation - if pr.OperationID != "" { - existingOp, err = scanOperation(tx.QueryRowContext(ctx, ` - SELECT id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at - FROM operations WHERE id = ? - `, pr.OperationID)) - if err != nil && !errors.Is(err, ErrNotFound) { - return nil, nil, nil, false, err - } + for rows.Next() { + var cid int + var name string + var columnType string + var notNull int + var defaultValue sql.NullString + var pk int + if err := rows.Scan(&cid, &name, &columnType, ¬Null, &defaultValue, &pk); err != nil { + return fmt.Errorf("sqlite scan %s columns: %w", table, err) } - if err := tx.Commit(); err != nil { - return nil, nil, nil, false, err + if name == column { + return nil } - return pr, existingOrder, existingOp, false, nil - - default: - return nil, nil, nil, false, ErrConflict - } -} - -func (s *Store) UpdatePaymentRequestState(ctx context.Context, id string, status string, orderID string, operationID string) error { - _, err := s.db.ExecContext(ctx, ` - UPDATE payment_requests - SET status = ?, order_id = ?, operation_id = ?, updated_at = ? - WHERE id = ? - `, status, orderID, operationID, formatTime(s.now().UTC()), id) - return err -} - -func (s *Store) GetOrder(ctx context.Context, id string) (*Order, error) { - row := s.db.QueryRowContext(ctx, ` - SELECT id, payment_request_id, operation_id, app_session_id, title, description, asset, amount, status, created_at, updated_at - FROM orders WHERE id = ? - `, id) - return scanOrder(row) -} - -func (s *Store) ListOrders(ctx context.Context, limit int) ([]Order, error) { - rows, err := s.db.QueryContext(ctx, ` - SELECT id, payment_request_id, operation_id, app_session_id, title, description, asset, amount, status, created_at, updated_at - FROM orders - ORDER BY created_at DESC - LIMIT ? - `, limit) - if err != nil { - return nil, err } - defer rows.Close() - return collectOrders(rows) -} - -func (s *Store) UpdateOrder(ctx context.Context, order Order) error { - _, err := s.db.ExecContext(ctx, ` - UPDATE orders - SET operation_id = ?, app_session_id = ?, status = ?, updated_at = ? - WHERE id = ? - `, order.OperationID, order.AppSessionID, order.Status, formatTime(order.UpdatedAt), order.ID) - return err -} - -func (s *Store) CreatePayoutWithOperation(ctx context.Context, payout Payout, op Operation) error { - tx, err := s.db.BeginTx(ctx, nil) - if err != nil { - return err - } - defer rollback(tx) - - if _, err := tx.ExecContext(ctx, ` - INSERT INTO payouts (id, operation_id, asset, amount, destination_wallet, status, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - `, payout.ID, payout.OperationID, payout.Asset, payout.Amount, payout.DestinationWallet, payout.Status, formatTime(payout.CreatedAt), formatTime(payout.UpdatedAt)); err != nil { - return err - } - if _, err := tx.ExecContext(ctx, ` - INSERT INTO operations (id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - `, op.ID, op.Type, op.ResourceID, op.Status, op.ErrorMessage, op.Payload, formatTime(op.QueuedAt), nullableTime(op.StartedAt), nullableTime(op.CompletedAt)); err != nil { - return err - } - - return tx.Commit() -} - -func (s *Store) GetPayout(ctx context.Context, id string) (*Payout, error) { - row := s.db.QueryRowContext(ctx, ` - SELECT id, operation_id, asset, amount, destination_wallet, status, created_at, updated_at - FROM payouts WHERE id = ? - `, id) - return scanPayout(row) -} - -func (s *Store) ListPayouts(ctx context.Context, limit int) ([]Payout, error) { - rows, err := s.db.QueryContext(ctx, ` - SELECT id, operation_id, asset, amount, destination_wallet, status, created_at, updated_at - FROM payouts - ORDER BY created_at DESC - LIMIT ? - `, limit) - if err != nil { - return nil, err + if err := rows.Err(); err != nil { + return fmt.Errorf("sqlite inspect %s: %w", table, err) } - defer rows.Close() - return collectPayouts(rows) -} - -func (s *Store) UpdatePayout(ctx context.Context, payout Payout) error { - _, err := s.db.ExecContext(ctx, ` - UPDATE payouts - SET operation_id = ?, status = ?, updated_at = ? - WHERE id = ? - `, payout.OperationID, payout.Status, formatTime(payout.UpdatedAt), payout.ID) - return err -} -func (s *Store) CreateOperation(ctx context.Context, op Operation) error { - _, err := s.db.ExecContext(ctx, ` - INSERT INTO operations (id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - `, op.ID, op.Type, op.ResourceID, op.Status, op.ErrorMessage, op.Payload, formatTime(op.QueuedAt), nullableTime(op.StartedAt), nullableTime(op.CompletedAt)) - return err -} - -func (s *Store) GetOperation(ctx context.Context, id string) (*Operation, error) { - row := s.db.QueryRowContext(ctx, ` - SELECT id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at - FROM operations WHERE id = ? - `, id) - return scanOperation(row) -} - -func (s *Store) ListOperations(ctx context.Context, limit int) ([]Operation, error) { - rows, err := s.db.QueryContext(ctx, ` - SELECT id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at - FROM operations - ORDER BY queued_at DESC - LIMIT ? - `, limit) - if err != nil { - return nil, err + if _, err := s.db.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ADD COLUMN %s %s", table, column, definition)); err != nil { + return fmt.Errorf("sqlite add %s.%s: %w", table, column, err) } - defer rows.Close() - return collectOperations(rows) -} - -func (s *Store) ListOperationsByStatuses(ctx context.Context, limit int, statuses ...string) ([]Operation, error) { - if len(statuses) == 0 { - return nil, nil - } - placeholders := strings.TrimRight(strings.Repeat("?,", len(statuses)), ",") - args := make([]any, 0, len(statuses)+1) - for _, status := range statuses { - args = append(args, status) - } - args = append(args, limit) - - rows, err := s.db.QueryContext(ctx, fmt.Sprintf(` - SELECT id, type, resource_id, status, error_message, payload, queued_at, started_at, completed_at - FROM operations - WHERE status IN (%s) - ORDER BY queued_at ASC - LIMIT ? - `, placeholders), args...) - if err != nil { - return nil, err - } - defer rows.Close() - return collectOperations(rows) -} - -func (s *Store) UpdateOperation(ctx context.Context, op Operation) error { - _, err := s.db.ExecContext(ctx, ` - UPDATE operations - SET status = ?, error_message = ?, payload = ?, started_at = ?, completed_at = ? - WHERE id = ? - `, op.Status, op.ErrorMessage, op.Payload, nullableTime(op.StartedAt), nullableTime(op.CompletedAt), op.ID) - return err -} - -func (s *Store) MarkRunningOperationsInterrupted(ctx context.Context) error { - _, err := s.db.ExecContext(ctx, ` - UPDATE operations - SET status = 'failed', error_message = 'interrupted by server restart', completed_at = ? - WHERE status = 'running' - `, formatTime(s.now().UTC())) - return err -} - -func rollback(tx *sql.Tx) { - _ = tx.Rollback() + return nil } func formatTime(value time.Time) string { @@ -600,174 +156,3 @@ func formatTime(value time.Time) string { func parseTime(raw string) (time.Time, error) { return time.Parse(time.RFC3339Nano, raw) } - -func nullableTime(value *time.Time) any { - if value == nil { - return nil - } - return formatTime(*value) -} - -func scanPaymentRequest(scanner interface{ Scan(...any) error }) (*PaymentRequest, error) { - var pr PaymentRequest - var createdAt string - var updatedAt string - if err := scanner.Scan(&pr.ID, &pr.Slug, &pr.Title, &pr.Description, &pr.Asset, &pr.Amount, &pr.Status, &pr.OrderID, &pr.OperationID, &createdAt, &updatedAt); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound - } - return nil, err - } - var err error - if pr.CreatedAt, err = parseTime(createdAt); err != nil { - return nil, err - } - if pr.UpdatedAt, err = parseTime(updatedAt); err != nil { - return nil, err - } - return &pr, nil -} - -func collectPaymentRequests(rows *sql.Rows) ([]PaymentRequest, error) { - var out []PaymentRequest - for rows.Next() { - pr, err := scanPaymentRequest(rows) - if err != nil { - return nil, err - } - out = append(out, *pr) - } - return out, rows.Err() -} - -func scanOrder(scanner interface{ Scan(...any) error }) (*Order, error) { - var order Order - var createdAt string - var updatedAt string - if err := scanner.Scan(&order.ID, &order.PaymentRequestID, &order.OperationID, &order.AppSessionID, &order.Title, &order.Description, &order.Asset, &order.Amount, &order.Status, &createdAt, &updatedAt); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound - } - return nil, err - } - var err error - if order.CreatedAt, err = parseTime(createdAt); err != nil { - return nil, err - } - if order.UpdatedAt, err = parseTime(updatedAt); err != nil { - return nil, err - } - return &order, nil -} - -func collectOrders(rows *sql.Rows) ([]Order, error) { - var out []Order - for rows.Next() { - order, err := scanOrder(rows) - if err != nil { - return nil, err - } - out = append(out, *order) - } - return out, rows.Err() -} - -func scanPayout(scanner interface{ Scan(...any) error }) (*Payout, error) { - var payout Payout - var createdAt string - var updatedAt string - if err := scanner.Scan(&payout.ID, &payout.OperationID, &payout.Asset, &payout.Amount, &payout.DestinationWallet, &payout.Status, &createdAt, &updatedAt); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound - } - return nil, err - } - var err error - if payout.CreatedAt, err = parseTime(createdAt); err != nil { - return nil, err - } - if payout.UpdatedAt, err = parseTime(updatedAt); err != nil { - return nil, err - } - return &payout, nil -} - -func collectPayouts(rows *sql.Rows) ([]Payout, error) { - var out []Payout - for rows.Next() { - payout, err := scanPayout(rows) - if err != nil { - return nil, err - } - out = append(out, *payout) - } - return out, rows.Err() -} - -func scanOperation(scanner interface{ Scan(...any) error }) (*Operation, error) { - var op Operation - var queuedAt string - var startedAt sql.NullString - var completedAt sql.NullString - if err := scanner.Scan(&op.ID, &op.Type, &op.ResourceID, &op.Status, &op.ErrorMessage, &op.Payload, &queuedAt, &startedAt, &completedAt); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound - } - return nil, err - } - var err error - if op.QueuedAt, err = parseTime(queuedAt); err != nil { - return nil, err - } - if startedAt.Valid { - parsed, err := parseTime(startedAt.String) - if err != nil { - return nil, err - } - op.StartedAt = &parsed - } - if completedAt.Valid { - parsed, err := parseTime(completedAt.String) - if err != nil { - return nil, err - } - op.CompletedAt = &parsed - } - return &op, nil -} - -func collectOperations(rows *sql.Rows) ([]Operation, error) { - var out []Operation - for rows.Next() { - op, err := scanOperation(rows) - if err != nil { - return nil, err - } - out = append(out, *op) - } - return out, rows.Err() -} - -func scanLease(scanner interface{ Scan(...any) error }) (*OperatorLease, error) { - var lease OperatorLease - var acquiredAt string - var heartbeatAt string - var expiresAt string - if err := scanner.Scan(&lease.LeaseName, &lease.SessionToken, &acquiredAt, &heartbeatAt, &expiresAt); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, ErrNotFound - } - return nil, err - } - var err error - if lease.AcquiredAt, err = parseTime(acquiredAt); err != nil { - return nil, err - } - if lease.HeartbeatAt, err = parseTime(heartbeatAt); err != nil { - return nil, err - } - if lease.ExpiresAt, err = parseTime(expiresAt); err != nil { - return nil, err - } - return &lease, nil -} diff --git a/internal/store/store_wallet.go b/internal/store/store_wallet.go deleted file mode 100644 index c26e41c..0000000 --- a/internal/store/store_wallet.go +++ /dev/null @@ -1,105 +0,0 @@ -package store - -import ( - "context" - "fmt" - "time" -) - -type WalletStoreSession struct { - WalletAddress string - Asset string - AppSessionID string - Status string - Version uint64 - UserAllocation string - AppAllocation string - SessionData string - CreatedAt time.Time - UpdatedAt time.Time -} - -type WalletPurchase struct { - ID string `json:"id"` - WalletAddress string `json:"wallet_address"` - ItemID string `json:"item_id"` - Asset string `json:"asset"` - AppSessionID string `json:"app_session_id"` - Version uint64 `json:"version"` - PurchasedAt time.Time `json:"purchased_at"` -} - -func (s *Store) UpsertWalletSession(ctx context.Context, session WalletStoreSession) error { - return s.UpsertStoreSession(ctx, StoreSession{ - BrowserSessionID: session.WalletAddress, - Asset: session.Asset, - AppSessionID: session.AppSessionID, - Status: session.Status, - Version: session.Version, - UserAllocation: session.UserAllocation, - AppAllocation: session.AppAllocation, - SessionData: session.SessionData, - CreatedAt: session.CreatedAt, - UpdatedAt: session.UpdatedAt, - }) -} - -func (s *Store) GetWalletSession(ctx context.Context, walletAddress string, asset string) (*WalletStoreSession, error) { - record, err := s.GetStoreSession(ctx, walletAddress, asset) - if err != nil { - return nil, err - } - return &WalletStoreSession{ - WalletAddress: record.BrowserSessionID, - Asset: record.Asset, - AppSessionID: record.AppSessionID, - Status: record.Status, - Version: record.Version, - UserAllocation: record.UserAllocation, - AppAllocation: record.AppAllocation, - SessionData: record.SessionData, - CreatedAt: record.CreatedAt, - UpdatedAt: record.UpdatedAt, - }, nil -} - -func (s *Store) RecordWalletPurchase(ctx context.Context, purchase WalletPurchase) error { - return s.RecordPurchase(ctx, Purchase{ - ID: purchase.ID, - BrowserSessionID: purchase.WalletAddress, - ItemID: purchase.ItemID, - Asset: purchase.Asset, - AppSessionID: purchase.AppSessionID, - Version: purchase.Version, - PurchasedAt: purchase.PurchasedAt, - }) -} - -func (s *Store) HasWalletPurchase(ctx context.Context, walletAddress string, itemID string, asset string) (bool, error) { - return s.HasPurchase(ctx, walletAddress, itemID, asset) -} - -func (s *Store) ListPurchasesByWallet(ctx context.Context, walletAddress string, asset string) ([]WalletPurchase, error) { - purchases, err := s.ListPurchasesByBrowser(ctx, walletAddress, asset) - if err != nil { - return nil, err - } - - out := make([]WalletPurchase, 0, len(purchases)) - for _, purchase := range purchases { - out = append(out, WalletPurchase{ - ID: purchase.ID, - WalletAddress: purchase.BrowserSessionID, - ItemID: purchase.ItemID, - Asset: purchase.Asset, - AppSessionID: purchase.AppSessionID, - Version: purchase.Version, - PurchasedAt: purchase.PurchasedAt, - }) - } - return out, nil -} - -func WalletPurchaseID(walletAddress string, asset string, itemID string) string { - return fmt.Sprintf("%s:%s:%s", walletAddress, asset, itemID) -} diff --git a/internal/store/storefront.go b/internal/store/storefront.go index bca88c0..53b79db 100644 --- a/internal/store/storefront.go +++ b/internal/store/storefront.go @@ -9,35 +9,65 @@ import ( "time" ) -type StoreSession struct { - BrowserSessionID string - Asset string - AppSessionID string - Status string - Version uint64 - UserAllocation string - AppAllocation string - SessionData string - CreatedAt time.Time - UpdatedAt time.Time -} - -type Purchase struct { - ID string `json:"id"` - BrowserSessionID string `json:"browser_session_id"` - ItemID string `json:"item_id"` - Asset string `json:"asset"` - AppSessionID string `json:"app_session_id"` - Version uint64 `json:"version"` - PurchasedAt time.Time `json:"purchased_at"` -} - -func (s *Store) UpsertStoreSession(ctx context.Context, session StoreSession) error { +type WalletStoreSession struct { + WalletAddress string + Asset string + AppSessionID string + Status string + Version uint64 + UserAllocation string + AppAllocation string + SessionData string + CreatedAt time.Time + UpdatedAt time.Time +} + +type WalletPurchase struct { + ID string `json:"id"` + WalletAddress string `json:"wallet_address"` + ItemID string `json:"item_id"` + Asset string `json:"asset"` + AppSessionID string `json:"app_session_id"` + Version uint64 `json:"version"` + Status string `json:"status"` + SessionData string `json:"session_data"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + PurchasedAt time.Time `json:"purchased_at"` +} + +type WalletDepositCheckpoint struct { + ID string + WalletAddress string + Asset string + AppSessionID string + Version uint64 + Amount string + Status string + AppStateUpdate string + UserSignature string + AppSignature string + SessionData string + CreatedAt time.Time + UpdatedAt time.Time +} + +const ( + WalletPurchaseStatusPending = "pending" + WalletPurchaseStatusSubmitted = "submitted" + WalletPurchaseStatusFailed = "failed" + + WalletDepositCheckpointStatusAppSigned = "app_signed" + WalletDepositCheckpointStatusSubmitted = "submitted" + WalletDepositCheckpointStatusFailed = "failed" +) + +func (s *Store) UpsertWalletSession(ctx context.Context, session WalletStoreSession) error { _, err := s.db.ExecContext(ctx, ` - INSERT INTO store_sessions ( - browser_session_id, asset, app_session_id, status, version, user_allocation, app_allocation, session_data, created_at, updated_at + INSERT INTO wallet_store_sessions ( + wallet_address, asset, app_session_id, status, version, user_allocation, app_allocation, session_data, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(browser_session_id, asset) DO UPDATE SET + ON CONFLICT(wallet_address, asset) DO UPDATE SET app_session_id = excluded.app_session_id, status = excluded.status, version = excluded.version, @@ -45,41 +75,96 @@ func (s *Store) UpsertStoreSession(ctx context.Context, session StoreSession) er app_allocation = excluded.app_allocation, session_data = excluded.session_data, updated_at = excluded.updated_at - `, session.BrowserSessionID, session.Asset, session.AppSessionID, session.Status, session.Version, session.UserAllocation, session.AppAllocation, session.SessionData, formatTime(session.CreatedAt), formatTime(session.UpdatedAt)) + `, session.WalletAddress, session.Asset, session.AppSessionID, session.Status, session.Version, session.UserAllocation, session.AppAllocation, session.SessionData, formatTime(session.CreatedAt), formatTime(session.UpdatedAt)) return err } -func (s *Store) GetStoreSession(ctx context.Context, browserSessionID string, asset string) (*StoreSession, error) { +func (s *Store) GetWalletSession(ctx context.Context, walletAddress string, asset string) (*WalletStoreSession, error) { row := s.db.QueryRowContext(ctx, ` - SELECT browser_session_id, asset, app_session_id, status, version, user_allocation, app_allocation, session_data, created_at, updated_at - FROM store_sessions - WHERE browser_session_id = ? AND asset = ? - `, browserSessionID, asset) - session, err := scanStoreSession(row) - if err != nil { - return nil, err - } - return session, nil + SELECT wallet_address, asset, app_session_id, status, version, user_allocation, app_allocation, session_data, created_at, updated_at + FROM wallet_store_sessions + WHERE wallet_address = ? AND asset = ? + `, walletAddress, asset) + return scanWalletStoreSession(row) } -func (s *Store) RecordPurchase(ctx context.Context, purchase Purchase) error { - _, err := s.db.ExecContext(ctx, ` - INSERT INTO purchases (id, browser_session_id, item_id, asset, app_session_id, version, purchased_at) - VALUES (?, ?, ?, ?, ?, ?, ?) - `, purchase.ID, purchase.BrowserSessionID, purchase.ItemID, purchase.Asset, purchase.AppSessionID, purchase.Version, formatTime(purchase.PurchasedAt)) +func (s *Store) GetWalletSessionByAppSessionID(ctx context.Context, appSessionID string, asset string) (*WalletStoreSession, error) { + row := s.db.QueryRowContext(ctx, ` + SELECT wallet_address, asset, app_session_id, status, version, user_allocation, app_allocation, session_data, created_at, updated_at + FROM wallet_store_sessions + WHERE app_session_id = ? AND asset = ? + `, appSessionID, asset) + return scanWalletStoreSession(row) +} + +func (s *Store) UpsertPendingWalletPurchase(ctx context.Context, purchase WalletPurchase) error { + createdAt := purchase.CreatedAt + if createdAt.IsZero() { + createdAt = purchase.PurchasedAt + } + updatedAt := purchase.UpdatedAt + if updatedAt.IsZero() { + updatedAt = purchase.PurchasedAt + } + result, err := s.db.ExecContext(ctx, ` + INSERT INTO wallet_purchases ( + id, wallet_address, item_id, asset, app_session_id, version, status, session_data, created_at, updated_at, purchased_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(wallet_address, item_id, asset) DO UPDATE SET + app_session_id = excluded.app_session_id, + version = excluded.version, + status = excluded.status, + session_data = excluded.session_data, + updated_at = excluded.updated_at, + purchased_at = excluded.purchased_at + WHERE wallet_purchases.status <> ? + `, purchase.ID, purchase.WalletAddress, purchase.ItemID, purchase.Asset, purchase.AppSessionID, purchase.Version, WalletPurchaseStatusPending, purchase.SessionData, formatTime(createdAt), formatTime(updatedAt), formatTime(purchase.PurchasedAt), WalletPurchaseStatusSubmitted) if err != nil { if isSQLiteUniqueError(err) { return ErrConflict } return err } + if changed, err := result.RowsAffected(); err == nil && changed == 0 { + return ErrConflict + } return nil } -func (s *Store) HasPurchase(ctx context.Context, browserSessionID string, itemID string, asset string) (bool, error) { +func (s *Store) MarkWalletPurchaseSubmitted(ctx context.Context, id string, purchasedAt time.Time) error { + result, err := s.db.ExecContext(ctx, ` + UPDATE wallet_purchases + SET status = ?, purchased_at = ?, updated_at = ? + WHERE id = ? + `, WalletPurchaseStatusSubmitted, formatTime(purchasedAt), formatTime(purchasedAt), id) + if err != nil { + return err + } + if changed, err := result.RowsAffected(); err == nil && changed == 0 { + return ErrNotFound + } + return nil +} + +func (s *Store) MarkWalletPurchaseFailed(ctx context.Context, id string, updatedAt time.Time) error { + result, err := s.db.ExecContext(ctx, ` + UPDATE wallet_purchases + SET status = ?, updated_at = ? + WHERE id = ? AND status = ? + `, WalletPurchaseStatusFailed, formatTime(updatedAt), id, WalletPurchaseStatusPending) + if err != nil { + return err + } + if changed, err := result.RowsAffected(); err == nil && changed == 0 { + return ErrNotFound + } + return nil +} + +func (s *Store) HasWalletPurchase(ctx context.Context, walletAddress string, itemID string, asset string) (bool, error) { row := s.db.QueryRowContext(ctx, ` - SELECT 1 FROM purchases WHERE browser_session_id = ? AND item_id = ? AND asset = ? LIMIT 1 - `, browserSessionID, itemID, asset) + SELECT 1 FROM wallet_purchases WHERE wallet_address = ? AND item_id = ? AND asset = ? AND status = ? LIMIT 1 + `, walletAddress, itemID, asset, WalletPurchaseStatusSubmitted) var marker int if err := row.Scan(&marker); err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -90,21 +175,53 @@ func (s *Store) HasPurchase(ctx context.Context, browserSessionID string, itemID return true, nil } -func (s *Store) ListPurchasesByBrowser(ctx context.Context, browserSessionID string, asset string) ([]Purchase, error) { +func (s *Store) GetWalletPurchase(ctx context.Context, walletAddress string, itemID string, asset string) (*WalletPurchase, error) { + row := s.db.QueryRowContext(ctx, ` + SELECT id, wallet_address, item_id, asset, app_session_id, version, status, session_data, created_at, updated_at, purchased_at + FROM wallet_purchases + WHERE wallet_address = ? AND item_id = ? AND asset = ? + `, walletAddress, itemID, asset) + return scanWalletPurchase(row) +} + +func (s *Store) ListPendingWalletPurchases(ctx context.Context, walletAddress string, asset string) ([]WalletPurchase, error) { + rows, err := s.db.QueryContext(ctx, ` + SELECT id, wallet_address, item_id, asset, app_session_id, version, status, session_data, created_at, updated_at, purchased_at + FROM wallet_purchases + WHERE wallet_address = ? AND asset = ? AND status = ? + ORDER BY updated_at ASC + `, walletAddress, asset, WalletPurchaseStatusPending) + if err != nil { + return nil, err + } + defer rows.Close() + + out := []WalletPurchase{} + for rows.Next() { + purchase, err := scanWalletPurchase(rows) + if err != nil { + return nil, err + } + out = append(out, *purchase) + } + return out, rows.Err() +} + +func (s *Store) ListPurchasesByWallet(ctx context.Context, walletAddress string, asset string) ([]WalletPurchase, error) { rows, err := s.db.QueryContext(ctx, ` - SELECT id, browser_session_id, item_id, asset, app_session_id, version, purchased_at - FROM purchases - WHERE browser_session_id = ? AND asset = ? + SELECT id, wallet_address, item_id, asset, app_session_id, version, status, session_data, created_at, updated_at, purchased_at + FROM wallet_purchases + WHERE wallet_address = ? AND asset = ? AND status = ? ORDER BY purchased_at DESC - `, browserSessionID, asset) + `, walletAddress, asset, WalletPurchaseStatusSubmitted) if err != nil { return nil, err } defer rows.Close() - out := []Purchase{} + out := []WalletPurchase{} for rows.Next() { - purchase, err := scanPurchase(rows) + purchase, err := scanWalletPurchase(rows) if err != nil { return nil, err } @@ -113,12 +230,80 @@ func (s *Store) ListPurchasesByBrowser(ctx context.Context, browserSessionID str return out, rows.Err() } -func scanStoreSession(scanner interface{ Scan(dest ...any) error }) (*StoreSession, error) { - var session StoreSession +func (s *Store) UpsertDepositCheckpoint(ctx context.Context, checkpoint WalletDepositCheckpoint) error { + createdAt := checkpoint.CreatedAt + if createdAt.IsZero() { + createdAt = s.now().UTC() + } + updatedAt := checkpoint.UpdatedAt + if updatedAt.IsZero() { + updatedAt = createdAt + } + _, err := s.db.ExecContext(ctx, ` + INSERT INTO wallet_deposit_checkpoints ( + id, wallet_address, asset, app_session_id, version, amount, status, app_state_update, user_signature, app_signature, session_data, created_at, updated_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(wallet_address, asset) DO UPDATE SET + id = excluded.id, + app_session_id = excluded.app_session_id, + version = excluded.version, + amount = excluded.amount, + status = excluded.status, + app_state_update = excluded.app_state_update, + user_signature = excluded.user_signature, + app_signature = excluded.app_signature, + session_data = excluded.session_data, + created_at = excluded.created_at, + updated_at = excluded.updated_at + `, checkpoint.ID, checkpoint.WalletAddress, checkpoint.Asset, checkpoint.AppSessionID, checkpoint.Version, checkpoint.Amount, checkpoint.Status, checkpoint.AppStateUpdate, checkpoint.UserSignature, checkpoint.AppSignature, checkpoint.SessionData, formatTime(createdAt), formatTime(updatedAt)) + return err +} + +func (s *Store) GetActiveDepositCheckpoint(ctx context.Context, walletAddress string, asset string) (*WalletDepositCheckpoint, error) { + row := s.db.QueryRowContext(ctx, ` + SELECT id, wallet_address, asset, app_session_id, version, amount, status, app_state_update, user_signature, app_signature, session_data, created_at, updated_at + FROM wallet_deposit_checkpoints + WHERE wallet_address = ? AND asset = ? AND status = ? + `, walletAddress, asset, WalletDepositCheckpointStatusAppSigned) + return scanWalletDepositCheckpoint(row) +} + +func (s *Store) MarkDepositCheckpointSubmitted(ctx context.Context, id string, updatedAt time.Time) error { + result, err := s.db.ExecContext(ctx, ` + UPDATE wallet_deposit_checkpoints + SET status = ?, updated_at = ? + WHERE id = ? AND status = ? + `, WalletDepositCheckpointStatusSubmitted, formatTime(updatedAt), id, WalletDepositCheckpointStatusAppSigned) + if err != nil { + return err + } + if changed, err := result.RowsAffected(); err == nil && changed == 0 { + return ErrNotFound + } + return nil +} + +func (s *Store) MarkDepositCheckpointFailed(ctx context.Context, id string, updatedAt time.Time) error { + result, err := s.db.ExecContext(ctx, ` + UPDATE wallet_deposit_checkpoints + SET status = ?, updated_at = ? + WHERE id = ? AND status = ? + `, WalletDepositCheckpointStatusFailed, formatTime(updatedAt), id, WalletDepositCheckpointStatusAppSigned) + if err != nil { + return err + } + if changed, err := result.RowsAffected(); err == nil && changed == 0 { + return ErrNotFound + } + return nil +} + +func scanWalletStoreSession(scanner interface{ Scan(dest ...any) error }) (*WalletStoreSession, error) { + var session WalletStoreSession var createdAt string var updatedAt string if err := scanner.Scan( - &session.BrowserSessionID, + &session.WalletAddress, &session.Asset, &session.AppSessionID, &session.Status, @@ -137,25 +322,31 @@ func scanStoreSession(scanner interface{ Scan(dest ...any) error }) (*StoreSessi var err error session.CreatedAt, err = parseTime(createdAt) if err != nil { - return nil, fmt.Errorf("parse store session created_at: %w", err) + return nil, fmt.Errorf("parse wallet store session created_at: %w", err) } session.UpdatedAt, err = parseTime(updatedAt) if err != nil { - return nil, fmt.Errorf("parse store session updated_at: %w", err) + return nil, fmt.Errorf("parse wallet store session updated_at: %w", err) } return &session, nil } -func scanPurchase(scanner interface{ Scan(dest ...any) error }) (*Purchase, error) { - var purchase Purchase +func scanWalletPurchase(scanner interface{ Scan(dest ...any) error }) (*WalletPurchase, error) { + var purchase WalletPurchase + var createdAt string + var updatedAt string var purchasedAt string if err := scanner.Scan( &purchase.ID, - &purchase.BrowserSessionID, + &purchase.WalletAddress, &purchase.ItemID, &purchase.Asset, &purchase.AppSessionID, &purchase.Version, + &purchase.Status, + &purchase.SessionData, + &createdAt, + &updatedAt, &purchasedAt, ); err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -164,13 +355,65 @@ func scanPurchase(scanner interface{ Scan(dest ...any) error }) (*Purchase, erro return nil, err } var err error + purchase.CreatedAt, err = parseTime(createdAt) + if err != nil { + return nil, fmt.Errorf("parse wallet purchase created_at: %w", err) + } + purchase.UpdatedAt, err = parseTime(updatedAt) + if err != nil { + return nil, fmt.Errorf("parse wallet purchase updated_at: %w", err) + } purchase.PurchasedAt, err = parseTime(purchasedAt) if err != nil { - return nil, fmt.Errorf("parse purchase purchased_at: %w", err) + return nil, fmt.Errorf("parse wallet purchase purchased_at: %w", err) } return &purchase, nil } +func scanWalletDepositCheckpoint(scanner interface{ Scan(dest ...any) error }) (*WalletDepositCheckpoint, error) { + var checkpoint WalletDepositCheckpoint + var createdAt string + var updatedAt string + if err := scanner.Scan( + &checkpoint.ID, + &checkpoint.WalletAddress, + &checkpoint.Asset, + &checkpoint.AppSessionID, + &checkpoint.Version, + &checkpoint.Amount, + &checkpoint.Status, + &checkpoint.AppStateUpdate, + &checkpoint.UserSignature, + &checkpoint.AppSignature, + &checkpoint.SessionData, + &createdAt, + &updatedAt, + ); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return nil, err + } + var err error + checkpoint.CreatedAt, err = parseTime(createdAt) + if err != nil { + return nil, fmt.Errorf("parse wallet deposit checkpoint created_at: %w", err) + } + checkpoint.UpdatedAt, err = parseTime(updatedAt) + if err != nil { + return nil, fmt.Errorf("parse wallet deposit checkpoint updated_at: %w", err) + } + return &checkpoint, nil +} + +func WalletPurchaseID(walletAddress string, asset string, itemID string) string { + return fmt.Sprintf("%s:%s:%s", walletAddress, asset, itemID) +} + +func WalletDepositCheckpointID(walletAddress string, asset string) string { + return fmt.Sprintf("%s:%s:deposit", walletAddress, asset) +} + func isSQLiteUniqueError(err error) bool { return err != nil && strings.Contains(strings.ToLower(err.Error()), "unique constraint failed") } diff --git a/internal/testsupport/fake_client.go b/internal/testsupport/fake_client.go index f05a7af..94ebb27 100644 --- a/internal/testsupport/fake_client.go +++ b/internal/testsupport/fake_client.go @@ -11,38 +11,39 @@ import ( // FakeClient is a configurable test double for nitrolite.Client. type FakeClient struct { - CloseFunc func() error - GetUserAddressFunc func() string - PingFunc func(context.Context) error - SetHomeBlockchainFunc func(string, uint64) error - WaitChFunc func() <-chan struct{} - GetConfigFunc func(context.Context) (*core.NodeConfig, error) - GetBlockchainsFunc func(context.Context) ([]core.Blockchain, error) - GetAssetsFunc func(context.Context, *uint64) ([]core.Asset, error) - GetBalancesFunc func(context.Context, string) ([]core.BalanceEntry, error) - GetTransactionsFunc func(context.Context, string, *sdk.GetTransactionsOptions) ([]core.Transaction, core.PaginationMetadata, error) - GetHomeChannelFunc func(context.Context, string, string) (*core.Channel, error) - GetLatestStateFunc func(context.Context, string, string, bool) (*core.State, error) - GetAppsFunc func(context.Context, *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) - RegisterAppFunc func(context.Context, string, string, bool) error - GetAppSessionsFunc func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) - GetAppDefinitionFunc func(context.Context, string) (*app.AppDefinitionV1, error) - CreateAppSessionFunc func(context.Context, app.AppDefinitionV1, string, []string, ...sdk.CreateAppSessionOptions) (string, string, string, error) - SubmitAppSessionDepositFunc func(context.Context, app.AppStateUpdateV1, []string, string, decimal.Decimal) (string, error) - SubmitAppStateFunc func(context.Context, app.AppStateUpdateV1, []string) error - SubmitAppSessionKeyStateFunc func(context.Context, app.AppSessionKeyStateV1) error - GetLastAppKeyStatesFunc func(context.Context, string, *sdk.GetLastKeyStatesOptions) ([]app.AppSessionKeyStateV1, error) - SignSessionKeyStateFunc func(app.AppSessionKeyStateV1) (string, error) + CloseFunc func() error + GetUserAddressFunc func() string + PingFunc func(context.Context) error + SetHomeBlockchainFunc func(string, uint64) error + WaitChFunc func() <-chan struct{} + GetConfigFunc func(context.Context) (*core.NodeConfig, error) + GetBlockchainsFunc func(context.Context) ([]core.Blockchain, error) + GetAssetsFunc func(context.Context, *uint64) ([]core.Asset, error) + GetBalancesFunc func(context.Context, string) ([]core.BalanceEntry, error) + GetTransactionsFunc func(context.Context, string, *sdk.GetTransactionsOptions) ([]core.Transaction, core.PaginationMetadata, error) + GetHomeChannelFunc func(context.Context, string, string) (*core.Channel, error) + GetLatestStateFunc func(context.Context, string, string, bool) (*core.State, error) + GetAppsFunc func(context.Context, *sdk.GetAppsOptions) ([]app.AppInfoV1, core.PaginationMetadata, error) + RegisterAppFunc func(context.Context, string, string, bool) error + GetAppSessionsFunc func(context.Context, *sdk.GetAppSessionsOptions) ([]app.AppSessionInfoV1, core.PaginationMetadata, error) + GetAppDefinitionFunc func(context.Context, string) (*app.AppDefinitionV1, error) + CreateAppSessionFunc func(context.Context, app.AppDefinitionV1, string, []string, ...sdk.CreateAppSessionOptions) (string, string, string, error) + SubmitAppSessionDepositFunc func(context.Context, app.AppStateUpdateV1, []string, string, decimal.Decimal) (string, error) + SubmitAppStateFunc func(context.Context, app.AppStateUpdateV1, []string) error + SubmitAppSessionKeyStateFunc func(context.Context, app.AppSessionKeyStateV1) error + GetLastAppKeyStatesFunc func(context.Context, string, *sdk.GetLastKeyStatesOptions) ([]app.AppSessionKeyStateV1, error) + SignSessionKeyStateFunc func(app.AppSessionKeyStateV1) (string, error) SubmitChannelSessionKeyStateFunc func(context.Context, core.ChannelSessionKeyStateV1) error - GetLastChannelKeyStatesFunc func(context.Context, string, *sdk.GetLastChannelKeyStatesOptions) ([]core.ChannelSessionKeyStateV1, error) - SignChannelSessionKeyStateFunc func(core.ChannelSessionKeyStateV1) (string, error) - CloseHomeChannelFunc func(context.Context, string) (*core.State, error) - ChallengeFunc func(context.Context, core.State) (string, error) - ApproveTokenFunc func(context.Context, uint64, string, decimal.Decimal) (string, error) - DepositFunc func(context.Context, uint64, string, decimal.Decimal) (*core.State, error) - WithdrawFunc func(context.Context, uint64, string, decimal.Decimal) (*core.State, error) - TransferFunc func(context.Context, string, string, decimal.Decimal) (*core.State, error) - CheckpointFunc func(context.Context, string) (string, error) + GetLastChannelKeyStatesFunc func(context.Context, string, *sdk.GetLastChannelKeyStatesOptions) ([]core.ChannelSessionKeyStateV1, error) + SignChannelSessionKeyStateFunc func(core.ChannelSessionKeyStateV1) (string, error) + CloseHomeChannelFunc func(context.Context, string) (*core.State, error) + ChallengeFunc func(context.Context, core.State) (string, error) + ApproveTokenFunc func(context.Context, uint64, string, decimal.Decimal) (string, error) + DepositFunc func(context.Context, uint64, string, decimal.Decimal) (*core.State, error) + WithdrawFunc func(context.Context, uint64, string, decimal.Decimal) (*core.State, error) + TransferFunc func(context.Context, string, string, decimal.Decimal) (*core.State, error) + CheckpointFunc func(context.Context, string) (string, error) + GetOnChainBalanceFunc func(context.Context, uint64, string, string) (decimal.Decimal, error) } func (f *FakeClient) Close() error { @@ -269,3 +270,10 @@ func (f *FakeClient) Checkpoint(ctx context.Context, asset string) (string, erro } return "", nil } + +func (f *FakeClient) GetOnChainBalance(ctx context.Context, chainID uint64, asset string, wallet string) (decimal.Decimal, error) { + if f.GetOnChainBalanceFunc != nil { + return f.GetOnChainBalanceFunc(ctx, chainID, asset, wallet) + } + return decimal.Zero, nil +} diff --git a/internal/webui/dist/assets/ccip-CrugWtXU.js b/internal/webui/dist/assets/ccip-Ch1826Mz.js similarity index 97% rename from internal/webui/dist/assets/ccip-CrugWtXU.js rename to internal/webui/dist/assets/ccip-Ch1826Mz.js index 3652f0c..58e85a8 100644 --- a/internal/webui/dist/assets/ccip-CrugWtXU.js +++ b/internal/webui/dist/assets/ccip-Ch1826Mz.js @@ -1 +1 @@ -import{a as e,c as t,d as n,f as r,i,l as a,o,r as s,s as c,t as l,u}from"./index-CmclZSzV.js";var d=class extends n{constructor({callbackSelector:e,cause:t,data:n,extraData:r,sender:i,urls:a}){super(t.shortMessage||`An error occurred while fetching for an offchain result.`,{cause:t,metaMessages:[...t.metaMessages||[],t.metaMessages?.length?``:[],`Offchain Gateway Call:`,a&&[` Gateway URL(s):`,...a.map(e=>` ${o(e)}`)],` Sender: ${i}`,` Data: ${n}`,` Callback selector: ${e}`,` Extra data: ${r}`].flat(),name:`OffchainLookupError`})}},f=class extends n{constructor({result:e,url:t}){super(`Offchain gateway response is malformed. Response data must be a hex value.`,{metaMessages:[`Gateway URL: ${o(t)}`,`Response: ${c(e)}`],name:`OffchainLookupResponseMalformedError`})}},p=class extends n{constructor({sender:e,to:t}){super("Reverted sender address does not match target contract address (`to`).",{metaMessages:[`Contract address: ${t}`,`OffchainLookup sender address: ${e}`],name:`OffchainLookupSenderMismatchError`})}},m=`0x556f1830`,h={name:`OffchainLookup`,type:`error`,inputs:[{name:`sender`,type:`address`},{name:`urls`,type:`string[]`},{name:`callData`,type:`bytes`},{name:`callbackFunction`,type:`bytes4`},{name:`extraData`,type:`bytes`}]};async function g(e,{blockNumber:n,blockTag:r,data:o,to:c}){let{args:f}=t({data:o,abi:[h]}),[m,g,v,y,b]=f,{ccipRead:x}=e,S=x&&typeof x?.request==`function`?x.request:_;try{if(!i(c,m))throw new p({sender:m,to:c});let{data:t}=await s(e,{blockNumber:n,blockTag:r,data:u([y,a([{type:`bytes`},{type:`bytes`}],[g.includes(`x-batch-gateway:true`)?await l({data:v,ccipRequest:S}):await S({data:v,sender:m,urls:g}),b])]),to:c});return t}catch(e){throw new d({callbackSelector:y,cause:e,data:o,extraData:b,sender:m,urls:g})}}async function _({data:t,sender:n,urls:i}){let a=Error(`An unknown error occurred.`);for(let o=0;o` ${o(e)}`)],` Sender: ${i}`,` Data: ${n}`,` Callback selector: ${e}`,` Extra data: ${r}`].flat(),name:`OffchainLookupError`})}},f=class extends n{constructor({result:e,url:t}){super(`Offchain gateway response is malformed. Response data must be a hex value.`,{metaMessages:[`Gateway URL: ${o(t)}`,`Response: ${c(e)}`],name:`OffchainLookupResponseMalformedError`})}},p=class extends n{constructor({sender:e,to:t}){super("Reverted sender address does not match target contract address (`to`).",{metaMessages:[`Contract address: ${t}`,`OffchainLookup sender address: ${e}`],name:`OffchainLookupSenderMismatchError`})}},m=`0x556f1830`,h={name:`OffchainLookup`,type:`error`,inputs:[{name:`sender`,type:`address`},{name:`urls`,type:`string[]`},{name:`callData`,type:`bytes`},{name:`callbackFunction`,type:`bytes4`},{name:`extraData`,type:`bytes`}]};async function g(e,{blockNumber:n,blockTag:r,data:o,to:c}){let{args:f}=t({data:o,abi:[h]}),[m,g,v,y,b]=f,{ccipRead:x}=e,S=x&&typeof x?.request==`function`?x.request:_;try{if(!i(c,m))throw new p({sender:m,to:c});let{data:t}=await s(e,{blockNumber:n,blockTag:r,data:u([y,a([{type:`bytes`},{type:`bytes`}],[g.includes(`x-batch-gateway:true`)?await l({data:v,ccipRequest:S}):await S({data:v,sender:m,urls:g}),b])]),to:c});return t}catch(e){throw new d({callbackSelector:y,cause:e,data:o,extraData:b,sender:m,urls:g})}}async function _({data:t,sender:n,urls:i}){let a=Error(`An unknown error occurred.`);for(let o=0;o=640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.sm\:grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto}.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:p-6{padding:1.5rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:text-2xl{font-size:1.5rem;line-height:2rem}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}.sm\:text-base{font-size:1rem;line-height:1.5rem}}@media (width>=1024px){.lg\:grid-cols-\[1\.05fr_0\.95fr\]{grid-template-columns:1.05fr .95fr}.lg\:grid-cols-\[1\.15fr_0\.85fr\]{grid-template-columns:1.15fr .85fr}.lg\:px-8{padding-left:2rem;padding-right:2rem}}.shimmer-button{position:relative;overflow:hidden}.shimmer-button:after{content:"";pointer-events:none;background:linear-gradient(90deg,#0000,#ffffff94,#0000);width:38%;animation:3.8s ease-in-out infinite shimmer-slide;position:absolute;inset:-120% auto -120% -40%;transform:rotate(18deg)}@keyframes shimmer-slide{0%{transform:translate(-220%)rotate(18deg)}42%,to{transform:translate(520%)rotate(18deg)}} diff --git a/internal/webui/dist/assets/index-CmclZSzV.js b/internal/webui/dist/assets/index-CmclZSzV.js deleted file mode 100644 index c0b3878..0000000 --- a/internal/webui/dist/assets/index-CmclZSzV.js +++ /dev/null @@ -1,48 +0,0 @@ -import{A as e,B as t,C as n,D as r,E as i,F as a,I as o,L as s,M as c,N as l,O as u,P as d,R as f,S as p,T as m,V as h,_ as g,a as _,b as v,c as y,d as b,f as x,g as S,h as ee,i as C,j as te,k as ne,l as w,m as re,n as ie,o as ae,p as T,r as E,s as D,t as O,u as oe,v as se,w as ce,x as le,y as ue,z as de}from"./utils-DUS54ir-.js";var fe=Object.defineProperty,pe=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),me=(e,t)=>{let n={};for(var r in e)fe(n,r,{get:e[r],enumerable:!0});return t||fe(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var he=pe((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function ee(){}var C={H:null,A:null,T:null,S:null},te=Object.prototype.hasOwnProperty;function ne(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function w(e,t){return ne(e.type,t,e.props)}function re(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function ie(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ae=/\/+/g;function T(e,t){return typeof e==`object`&&e&&e.key!=null?ie(``+e.key):t.toString(36)}function E(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(ee,ee):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function D(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,D(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+T(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(ae,`$&/`)+`/`),D(o,r,i,``,function(e){return e})):o!=null&&(re(o)&&(o=w(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ae,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=he()})),_e=pe((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,re());else{var t=n(l);t!==null&&T(x,t.startTime-e)}}var S=!1,ee=-1,C=5,te=-1;function ne(){return g?!0:!(e.unstable_now()-tet&&ne());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&T(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?re():S=!1}}}var re;if(typeof y==`function`)re=function(){y(w)};else if(typeof MessageChannel<`u`){var ie=new MessageChannel,ae=ie.port2;ie.port1.onmessage=w,re=function(){ae.postMessage(null)}}else re=function(){_(w,0)};function T(t,n){ee=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(ee),ee=-1):h=!0,T(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,re()))),r},e.unstable_shouldYield=ne,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),ve=pe(((e,t)=>{t.exports=_e()})),ye=pe((e=>{var t=ge();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=ye()})),xe=pe((e=>{var t=ve(),n=ge(),r=be();function i(e){var t=`https://react.dev/errors/`+e;if(1ce||(e.current=se[ce],se[ce]=null,ce--)}function de(e,t){ce++,se[ce]=e.current,e.current=t}var fe=le(null),pe=le(null),me=le(null),he=le(null);function _e(e,t){switch(de(me,t),de(pe,e),de(fe,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Ud(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Ud(t),e=Wd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}ue(fe),de(fe,e)}function ye(){ue(fe),ue(pe),ue(me)}function xe(e){e.memoizedState!==null&&de(he,e);var t=fe.current,n=Wd(t,e.type);t!==n&&(de(pe,e),de(fe,n))}function Se(e){pe.current===e&&(ue(fe),ue(pe)),he.current===e&&(ue(he),ep._currentValue=oe)}var Ce,we;function Te(e){if(Ce===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);Ce=t&&t[1]||``,we=-1)`:-1i||c[r]!==l[i]){var u=` -`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{Ee=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?Te(n):``}function Oe(e,t){switch(e.tag){case 26:case 27:case 5:return Te(e.type);case 16:return Te(`Lazy`);case 13:return e.child!==t&&t!==null?Te(`Suspense Fallback`):Te(`Suspense`);case 19:return Te(`SuspenseList`);case 0:case 15:return De(e.type,!1);case 11:return De(e.type.render,!1);case 1:return De(e.type,!0);case 31:return Te(`Activity`);default:return``}}function ke(e){try{var t=``,n=null;do t+=Oe(e,n),n=e,e=e.return;while(e);return t}catch(e){return` -Error generating stack: `+e.message+` -`+e.stack}}var Ae=Object.prototype.hasOwnProperty,je=t.unstable_scheduleCallback,Me=t.unstable_cancelCallback,k=t.unstable_shouldYield,Ne=t.unstable_requestPaint,Pe=t.unstable_now,Fe=t.unstable_getCurrentPriorityLevel,Ie=t.unstable_ImmediatePriority,Le=t.unstable_UserBlockingPriority,Re=t.unstable_NormalPriority,ze=t.unstable_LowPriority,Be=t.unstable_IdlePriority,Ve=t.log,He=t.unstable_setDisableYieldValue,Ue=null,We=null;function A(e){if(typeof Ve==`function`&&He(e),We&&typeof We.setStrictMode==`function`)try{We.setStrictMode(Ue,e)}catch{}}var Ge=Math.clz32?Math.clz32:j,Ke=Math.log,qe=Math.LN2;function j(e){return e>>>=0,e===0?32:31-(Ke(e)/qe|0)|0}var Je=256,Ye=262144,Xe=4194304;function Ze(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Qe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ze(n))):i=Ze(o):i=Ze(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ze(n))):i=Ze(o)):i=Ze(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function M(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function N(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function $e(){var e=Xe;return Xe<<=1,!(Xe&62914560)&&(Xe=4194304),e}function et(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function tt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function nt(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),mn=!1;if(pn)try{var hn={};Object.defineProperty(hn,`passive`,{get:function(){mn=!0}}),window.addEventListener(`test`,hn,hn),window.removeEventListener(`test`,hn,hn)}catch{mn=!1}var gn=null,_n=null,vn=null;function yn(){if(vn)return vn;var e,t=_n,n=t.length,r,i=`value`in gn?gn.value:gn.textContent,a=i.length;for(e=0;e=Zn),er=` `,tr=!1;function nr(e,t){switch(e){case`keyup`:return Yn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function rr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var ir=!1;function ar(e,t){switch(e){case`compositionend`:return rr(t);case`keypress`:return t.which===32?(tr=!0,er):null;case`textInput`:return e=t.data,e===er&&tr?null:e;default:return null}}function or(e,t){if(ir)return e===`compositionend`||!Xn&&nr(e,t)?(e=yn(),vn=_n=gn=null,ir=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Er(n)}}function Or(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Or(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function kr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Vt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Vt(e.document)}return t}function Ar(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var jr=pn&&`documentMode`in document&&11>=document.documentMode,Mr=null,Nr=null,Pr=null,Fr=!1;function Ir(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Fr||Mr==null||Mr!==Vt(r)||(r=Mr,`selectionStart`in r&&Ar(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Pr&&Tr(Pr,r)||(Pr=r,r=Dd(Nr,`onSelect`),0>=o,i-=o,Di=1<<32-Ge(t)+i|n<m?(h=d,d=null):h=d.sibling;var g=p(i,d,s[m],c);if(g===null){d===null&&(d=h);break}e&&d&&g.alternate===null&&t(i,d),a=o(g,a,m),u===null?l=g:u.sibling=g,u=g,d=h}if(m===s.length)return n(i,d),R&&ki(i,m),l;if(d===null){for(;mh?(g=m,m=null):g=m.sibling;var y=p(a,m,v.value,l);if(y===null){m===null&&(m=g);break}e&&m&&y.alternate===null&&t(a,m),s=o(y,s,h),d===null?u=y:d.sibling=y,d=y,m=g}if(v.done)return n(a,m),R&&ki(a,h),u;if(m===null){for(;!v.done;h++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return R&&ki(a,h),u}for(m=r(m);!v.done;h++,v=c.next())v=_(m,a,h,v.value,l),v!==null&&(e&&v.alternate!==null&&m.delete(v.key===null?h:v.key),s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return e&&m.forEach(function(e){return t(a,e)}),R&&ki(a,h),u}function x(e,r,o,c){if(typeof o==`object`&&o&&o.type===g&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case m:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===g){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===te&&Oa(l)===r.type){n(e,r.sibling),c=a(r,o.props),B(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===g?(c=hi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=mi(o.type,o.key,o.props,null,e.mode,c),B(c,o),c.return=e,e=c)}return s(e);case h:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=_i(o,e.mode,c),c.return=e,e=c}return s(e);case te:return o=Oa(o),x(e,r,o,c)}if(E(o))return v(e,r,o,c);if(ie(o)){if(l=ie(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),y(e,r,o,c)}if(typeof o.then==`function`)return x(e,r,Pa(o),c);if(o.$$typeof===b)return x(e,r,na(e,o),c);Fa(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=L(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Na=0;var i=x(e,t,n,r);return Ma=null,i}catch(t){if(t===Sa||t===wa)throw t;var a=ui(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var La=Ia(!0),Ra=Ia(!1),za=!1;function Ba(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Va(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ha(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ua(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,G&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=si(e),oi(e,null,n),t}return ri(e,r,t,n),si(e)}function Wa(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}function Ga(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ka=!1;function qa(){if(Ka){var e=pa;if(e!==null)throw e}}function Ja(e,t,n,r){Ka=!1;var i=e.updateQueue;za=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var p=s.lane&-536870913,m=p!==s.lane;if(m?(q&p)===p:(r&p)===p){p!==0&&p===fa&&(Ka=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;p=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,p);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,p=typeof h==`function`?h.call(_,d,p):h,p==null)break a;d=f({},d,p);break a;case 2:za=!0}}p=s.callback,p!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[p]:m.push(p))}else m={lane:p,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=p;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Kl|=o,e.lanes=o,e.memoizedState=d}}function Ya(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function Xa(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=D.T,s={};D.T=s,Ps(e,!1,t,n);try{var c=i(),l=D.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Ns(e,t,ga(c,r),mu(e)):Ns(e,t,r,mu(e))}catch(n){Ns(e,t,{then:function(){},status:`rejected`,reason:n},mu())}finally{O.p=a,o!==null&&s.types!==null&&(o.types=s.types),D.T=o}}function Cs(){}function ws(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Ts(e).queue;Ss(e,a,t,oe,n===null?Cs:function(){return Es(e),n(r)})}function Ts(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:oe,baseState:oe,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Fo,lastRenderedState:oe},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Fo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Es(e){var t=Ts(e);t.next===null&&(t=e.alternate.memoizedState),Ns(e,t.next.queue,{},mu())}function Ds(){return ta(ep)}function Os(){return Ao().memoizedState}function ks(){return Ao().memoizedState}function As(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=mu();e=Ha(n);var r=Ua(t,e,n);r!==null&&(gu(r,t,n),Wa(r,t,n)),t={cache:ca()},e.payload=t;return}t=t.return}}function js(e,t,n){var r=mu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Fs(e)?Is(t,n):(n=ii(e,t,n,r),n!==null&&(gu(n,e,r),Ls(n,t,r)))}function Ms(e,t,n){Ns(e,t,n,mu())}function Ns(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Fs(e))Is(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,I(s,o))return ri(e,t,i,0),Bl===null&&ni(),!1}catch{}if(n=ii(e,t,i,r),n!==null)return gu(n,e,r),Ls(n,t,r),!0}return!1}function Ps(e,t,n,r){if(r={lane:2,revertLane:fd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Fs(e)){if(t)throw Error(i(479))}else t=ii(e,n,r,2),t!==null&&gu(t,e,2)}function Fs(e){var t=e.alternate;return e===H||t!==null&&t===H}function Is(e,t){mo=po=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Ls(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,it(e,n)}}var Rs={readContext:ta,use:No,useCallback:bo,useContext:bo,useEffect:bo,useImperativeHandle:bo,useLayoutEffect:bo,useInsertionEffect:bo,useMemo:bo,useReducer:bo,useRef:bo,useState:bo,useDebugValue:bo,useDeferredValue:bo,useTransition:bo,useSyncExternalStore:bo,useId:bo,useHostTransitionStatus:bo,useFormState:bo,useActionState:bo,useOptimistic:bo,useMemoCache:bo,useCacheRefresh:bo};Rs.useEffectEvent=bo;var zs={readContext:ta,use:No,useCallback:function(e,t){return ko().memoizedState=[e,t===void 0?null:t],e},useContext:ta,useEffect:ls,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),ss(4194308,4,hs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ss(4194308,4,e,t)},useInsertionEffect:function(e,t){ss(4,2,e,t)},useMemo:function(e,t){var n=ko();t=t===void 0?null:t;var r=e();if(ho){A(!0);try{e()}finally{A(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=ko();if(n!==void 0){var i=n(t);if(ho){A(!0);try{n(t)}finally{A(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=js.bind(null,H,e),[r.memoizedState,e]},useRef:function(e){var t=ko();return e={current:e},t.memoizedState=e},useState:function(e){e=Go(e);var t=e.queue,n=Ms.bind(null,H,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:_s,useDeferredValue:function(e,t){return bs(ko(),e,t)},useTransition:function(){var e=Go(!1);return e=Ss.bind(null,H,e.queue,!0,!1),ko().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=H,a=ko();if(R){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Bl===null)throw Error(i(349));q&127||Bo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,ls(Ho.bind(null,r,o,e),[e]),r.flags|=2048,as(9,{destroy:void 0},Vo.bind(null,r,o,n,t),null),n},useId:function(){var e=ko(),t=Bl.identifierPrefix;if(R){var n=Oi,r=Di;n=(r&~(1<<32-Ge(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=go++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[dt]=t,o[ft]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Id(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Nc(t)}}return Rc(t),Pc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Nc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=me.current,Hi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Pi,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[dt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Nd(e.nodeValue,n)),e||zi(t,!0)}else e=Hd(e).createTextNode(r),e[dt]=t,t.stateNode=e}return Rc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Hi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[dt]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),e=!1}else n=z(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(co(t),t):(co(t),null);if(t.flags&128)throw Error(i(558))}return Rc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Hi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[dt]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Rc(t),a=!1}else a=z(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(co(t),t):(co(t),null)}return co(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Ic(t,t.updateQueue),Rc(t),null);case 4:return ye(),e===null&&Cd(t.stateNode.containerInfo),Rc(t),null;case 10:return Yi(t.type),Rc(t),null;case 19:if(ue(V),r=t.memoizedState,r===null)return Rc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)Lc(r,!1);else{if(Y!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=lo(e),o!==null){for(t.flags|=128,Lc(r,!1),e=o.updateQueue,t.updateQueue=e,Ic(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)pi(n,e),n=n.sibling;return de(V,V.current&1|2),R&&ki(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Pe()>nu&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304)}else{if(!a)if(e=lo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Ic(t,e),Lc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!R)return Rc(t),null}else 2*Pe()-r.renderingStartTime>nu&&n!==536870912&&(t.flags|=128,a=!0,Lc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Rc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Pe(),e.sibling=null,n=V.current,de(V,a?n&1|2:n&1),R&&ki(t,r.treeForkCount),e);case 22:case 23:return co(t),to(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Rc(t),t.subtreeFlags&6&&(t.flags|=8192)):Rc(t),n=t.updateQueue,n!==null&&Ic(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&ue(va),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Yi(sa),Rc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Mi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Yi(sa),ye(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Se(t),null;case 31:if(t.memoizedState!==null){if(co(t),t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(co(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ue(V),null;case 4:return ye(),null;case 10:return Yi(t.type),null;case 22:case 23:return co(t),to(),e!==null&&ue(va),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Yi(sa),null;case 25:return null;default:return null}}function Vc(e,t){switch(Mi(t),t.tag){case 3:Yi(sa),ye();break;case 26:case 27:case 5:Se(t);break;case 4:ye();break;case 31:t.memoizedState!==null&&co(t);break;case 13:co(t);break;case 19:ue(V);break;case 10:Yi(t.type);break;case 22:case 23:co(t),to(),e!==null&&ue(va);break;case 24:Yi(sa)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){X(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){X(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){X(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Xa(t,n)}catch(t){X(e,e.return,t)}}}function Gc(e,t,n){n.props=Ks(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){X(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){X(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){X(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){X(e,t,n)}else n.current=null}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){X(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Ld(r,e.type,n,t),r[ft]=t}catch(t){X(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&$d(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&$d(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=an));else if(r!==4&&(r===27&&$d(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&$d(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Id(t,r,n),t[dt]=e,t[ft]=n}catch(t){X(e,e.return,t)}}var tl=!1,nl=!1,rl=!1,il=typeof WeakSet==`function`?WeakSet:Set,al=null;function ol(e,t){if(e=e.containerInfo,Bd=lp,e=kr(e),Ar(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(Vd={focusedElem:e,selectionRange:n},lp=!1,al=t;al!==null;)if(t=al,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,al=e;else for(;al!==null;){switch(t=al,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Id(o,r,n),o[dt]=e,wt(o),r=o;break a;case`link`:var s=Uf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Dr(s,h),v=Dr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,D.T=null,n=uu,uu=null;var o=ou,s=cu;if(au=0,su=ou=null,cu=0,G&6)throw Error(i(331));var c=G;if(G|=4,Fl(o.current),Dl(o,o.current,s,n),G=c,ad(0,!1),We&&typeof We.onPostCommitFiberRoot==`function`)try{We.onPostCommitFiberRoot(Ue,o)}catch{}return!0}finally{O.p=a,D.T=r,Hu(e,t)}}function Gu(e,t,n){t=yi(n,t),t=Qs(e.stateNode,t,2),e=Ua(e,t,2),e!==null&&(tt(e,2),id(e))}function X(e,t,n){if(e.tag===3)Gu(e,e,n);else for(;t!==null;){if(t.tag===3){Gu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(iu===null||!iu.has(r))){e=yi(n,e),n=$s(2),r=Ua(t,n,2),r!==null&&(ec(n,r,t,e),tt(r,2),id(r));break}}t=t.return}}function Ku(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new zl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Wl=!0,i.add(n),e=qu.bind(null,e,t,n),t.then(e,e))}function qu(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Bl===e&&(q&n)===n&&(Y===4||Y===3&&(q&62914560)===q&&300>Pe()-eu?!(G&2)&&Cu(e,0):Jl|=n,Xl===q&&(Xl=0)),id(e)}function Ju(e,t){t===0&&(t=$e()),e=ai(e,t),e!==null&&(tt(e,t),id(e))}function Yu(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Ju(e,n)}function Xu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),Ju(e,n)}function Zu(e,t){return je(e,t)}var Qu=null,$u=null,ed=!1,td=!1,nd=!1,rd=0;function id(e){e!==$u&&e.next===null&&($u===null?Qu=$u=e:$u=$u.next=e),td=!0,ed||(ed=!0,dd())}function ad(e,t){if(!nd&&td){nd=!0;do for(var n=!1,r=Qu;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Ge(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ud(r,a))}else a=q,a=Qe(r,r===Bl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||M(r,a)||(n=!0,ud(r,a));r=r.next}while(n);nd=!1}}function od(){sd()}function sd(){td=ed=!1;var e=0;rd!==0&&qd()&&(e=rd);for(var t=Pe(),n=null,r=Qu;r!==null;){var i=r.next,a=cd(r,t);a===0?(r.next=null,n===null?Qu=i:n.next=i,i===null&&($u=n)):(n=r,(e!==0||a&3)&&(td=!0)),r=i}au!==0&&au!==5||ad(e,!1),rd!==0&&(rd=0)}function cd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Rd(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function Cf(e,t,n){var r=Sf;if(r&&typeof t==`string`&&t){var i=Ut(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),_f.has(i)||(_f.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Id(t,`link`,e),wt(t),r.head.appendChild(t)))}}function wf(e){yf.D(e),Cf(`dns-prefetch`,e,null)}function Tf(e,t){yf.C(e,t),Cf(`preconnect`,e,t)}function Ef(e,t,n){yf.L(e,t,n);var r=Sf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Ut(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Ut(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Ut(n.imageSizes)+`"]`)):i+=`[href="`+Ut(e)+`"]`;var a=i;switch(t){case`style`:a=Mf(e);break;case`script`:a=If(e)}gf.has(a)||(e=f({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),gf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(Nf(a))||t===`script`&&r.querySelector(Lf(a))||(t=r.createElement(`link`),Id(t,`link`,e),wt(t),r.head.appendChild(t)))}}function Df(e,t){yf.m(e,t);var n=Sf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Ut(r)+`"][href="`+Ut(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=If(e)}if(!gf.has(a)&&(e=f({rel:`modulepreload`,href:e},t),gf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Lf(a)))return}r=n.createElement(`link`),Id(r,`link`,e),wt(r),n.head.appendChild(r)}}}function Of(e,t,n){yf.S(e,t,n);var r=Sf;if(r&&e){var i=Ct(r).hoistableStyles,a=Mf(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(Nf(a)))s.loading=5;else{e=f({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=gf.get(a))&&Bf(e,n);var c=o=r.createElement(`link`);wt(c),Id(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,zf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function kf(e,t){yf.X(e,t);var n=Sf;if(n&&e){var r=Ct(n).hoistableScripts,i=If(e),a=r.get(i);a||(a=n.querySelector(Lf(i)),a||(e=f({src:e,async:!0},t),(t=gf.get(i))&&Vf(e,t),a=n.createElement(`script`),wt(a),Id(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Af(e,t){yf.M(e,t);var n=Sf;if(n&&e){var r=Ct(n).hoistableScripts,i=If(e),a=r.get(i);a||(a=n.querySelector(Lf(i)),a||(e=f({src:e,async:!0,type:`module`},t),(t=gf.get(i))&&Vf(e,t),a=n.createElement(`script`),wt(a),Id(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function jf(e,t,n,r){var a=(a=me.current)?vf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Mf(n.href),n=Ct(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Mf(n.href);var o=Ct(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(Nf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),gf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},gf.set(e,n),o||Ff(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=If(n),n=Ct(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Mf(e){return`href="`+Ut(e)+`"`}function Nf(e){return`link[rel="stylesheet"][`+e+`]`}function Pf(e){return f({},e,{"data-precedence":e.precedence,precedence:null})}function Ff(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Id(t,`link`,n),wt(t),e.head.appendChild(t))}function If(e){return`[src="`+Ut(e)+`"]`}function Lf(e){return`script[async]`+e}function Rf(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Ut(n.href)+`"]`);if(r)return t.instance=r,wt(r),r;var a=f({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),wt(r),Id(r,`style`,a),zf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Mf(n.href);var o=e.querySelector(Nf(a));if(o)return t.state.loading|=4,t.instance=o,wt(o),o;r=Pf(n),(a=gf.get(a))&&Bf(r,a),o=(e.ownerDocument||e).createElement(`link`),wt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Id(o,`link`,r),t.state.loading|=4,zf(o,n.precedence,e),t.instance=o;case`script`:return o=If(n.src),(a=e.querySelector(Lf(o)))?(t.instance=a,wt(a),a):(r=n,(a=gf.get(o))&&(r=f({},n),Vf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),wt(a),Id(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,zf(r,n.precedence,e));return t.instance}function zf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Gf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Kf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function qf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Mf(r.href),a=t.querySelector(Nf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Xf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,wt(a);return}a=t.ownerDocument||t,r=Pf(r),(i=gf.get(i))&&Bf(r,i),a=a.createElement(`link`),wt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Id(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Xf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Jf=0;function Yf(e,t){return e.stylesheets&&e.count===0&&Qf(e,e.stylesheets),0Jf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Xf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Qf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Zf=null;function Qf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Zf=new Map,t.forEach($f,e),Zf=null,Xf.call(e))}function $f(e,t){if(!(t.state.loading&4)){var n=Zf.get(e);if(n)var r=n.get(null);else{n=new Map,Zf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=xe()})),Ce=ge(),we=Se(),Te=9e15,Ee=1e9,De=`0123456789abcdef`,Oe=`2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058`,ke=`3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789`,Ae={precision:20,rounding:4,modulo:1,toExpNeg:-7,toExpPos:21,minE:-Te,maxE:Te,crypto:!1},je,Me,k=!0,Ne=`[DecimalError] `,Pe=Ne+`Invalid argument: `,Fe=Ne+`Precision limit exceeded`,Ie=Ne+`crypto unavailable`,Le=`[object Decimal]`,Re=Math.floor,ze=Math.pow,Be=/^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i,Ve=/^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i,He=/^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i,Ue=/^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,We=1e7,A=7,Ge=9007199254740991,Ke=Oe.length-1,qe=ke.length-1,j={toStringTag:Le};j.absoluteValue=j.abs=function(){var e=new this.constructor(this);return e.s<0&&(e.s=1),N(e)},j.ceil=function(){return N(new this.constructor(this),this.e+1,2)},j.clampedTo=j.clamp=function(e,t){var n,r=this,i=r.constructor;if(e=new i(e),t=new i(t),!e.s||!t.s)return new i(NaN);if(e.gt(t))throw Error(Pe+t);return n=r.cmp(e),n<0?e:r.cmp(t)>0?t:new i(r)},j.comparedTo=j.cmp=function(e){var t,n,r,i,a=this,o=a.d,s=(e=new a.constructor(e)).d,c=a.s,l=e.s;if(!o||!s)return!c||!l?NaN:c===l?o===s?0:!o^c<0?1:-1:c;if(!o[0]||!s[0])return o[0]?c:s[0]?-l:0;if(c!==l)return c;if(a.e!==e.e)return a.e>e.e^c<0?1:-1;for(r=o.length,i=s.length,t=0,n=rs[t]^c<0?1:-1;return r===i?0:r>i^c<0?1:-1},j.cosine=j.cos=function(){var e,t,n=this,r=n.constructor;return n.d?n.d[0]?(e=r.precision,t=r.rounding,r.precision=e+Math.max(n.e,n.sd())+A,r.rounding=1,n=Qe(r,gt(r,n)),r.precision=e,r.rounding=t,N(Me==2||Me==3?n.neg():n,e,t,!0)):new r(1):new r(NaN)},j.cubeRoot=j.cbrt=function(){var e,t,n,r,i,a,o,s,c,l,u=this,d=u.constructor;if(!u.isFinite()||u.isZero())return new d(u);for(k=!1,a=u.s*ze(u.s*u,1/3),!a||Math.abs(a)==1/0?(n=Je(u.d),e=u.e,(a=(e-n.length+1)%3)&&(n+=a==1||a==-2?`0`:`00`),a=ze(n,1/3),e=Re((e+1)/3)-(e%3==(e<0?-1:2)),a==1/0?n=`5e`+e:(n=a.toExponential(),n=n.slice(0,n.indexOf(`e`)+1)+e),r=new d(n),r.s=u.s):r=new d(a.toString()),o=(e=d.precision)+3;;)if(s=r,c=s.times(s).times(s),l=c.plus(u),r=M(l.plus(u).times(s),l.plus(c),o+2,1),Je(s.d).slice(0,o)===(n=Je(r.d)).slice(0,o))if(n=n.slice(o-3,o+1),n==`9999`||!i&&n==`4999`){if(!i&&(N(s,e+1,0),s.times(s).times(s).eq(u))){r=s;break}o+=4,i=1}else{(!+n||!+n.slice(1)&&n.charAt(0)==`5`)&&(N(r,e+1,1),t=!r.times(r).times(r).eq(u));break}return k=!0,N(r,e,d.rounding,t)},j.decimalPlaces=j.dp=function(){var e,t=this.d,n=NaN;if(t){if(e=t.length-1,n=(e-Re(this.e/A))*A,e=t[e],e)for(;e%10==0;e/=10)n--;n<0&&(n=0)}return n},j.dividedBy=j.div=function(e){return M(this,new this.constructor(e))},j.dividedToIntegerBy=j.divToInt=function(e){var t=this,n=t.constructor;return N(M(t,new n(e),0,1,1),n.precision,n.rounding)},j.equals=j.eq=function(e){return this.cmp(e)===0},j.floor=function(){return N(new this.constructor(this),this.e+1,3)},j.greaterThan=j.gt=function(e){return this.cmp(e)>0},j.greaterThanOrEqualTo=j.gte=function(e){var t=this.cmp(e);return t==1||t===0},j.hyperbolicCosine=j.cosh=function(){var e,t,n,r,i,a=this,o=a.constructor,s=new o(1);if(!a.isFinite())return new o(a.s?1/0:NaN);if(a.isZero())return s;n=o.precision,r=o.rounding,o.precision=n+Math.max(a.e,a.sd())+4,o.rounding=1,i=a.d.length,i<32?(e=Math.ceil(i/3),t=(1/ht(4,e)).toString()):(e=16,t=`2.3283064365386962890625e-10`),a=mt(o,1,a.times(t),new o(1),!0);for(var c,l=e,u=new o(8);l--;)c=a.times(a),a=s.minus(c.times(u.minus(c.times(u))));return N(a,o.precision=n,o.rounding=r,!0)},j.hyperbolicSine=j.sinh=function(){var e,t,n,r,i=this,a=i.constructor;if(!i.isFinite()||i.isZero())return new a(i);if(t=a.precision,n=a.rounding,a.precision=t+Math.max(i.e,i.sd())+4,a.rounding=1,r=i.d.length,r<3)i=mt(a,2,i,i,!0);else{e=1.4*Math.sqrt(r),e=e>16?16:e|0,i=i.times(1/ht(5,e)),i=mt(a,2,i,i,!0);for(var o,s=new a(5),c=new a(16),l=new a(20);e--;)o=i.times(i),i=i.times(s.plus(o.times(c.times(o).plus(l))))}return a.precision=t,a.rounding=n,N(i,t,n,!0)},j.hyperbolicTangent=j.tanh=function(){var e,t,n=this,r=n.constructor;return n.isFinite()?n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+7,r.rounding=1,M(n.sinh(),n.cosh(),r.precision=e,r.rounding=t)):new r(n.s)},j.inverseCosine=j.acos=function(){var e=this,t=e.constructor,n=e.abs().cmp(1),r=t.precision,i=t.rounding;return n===-1?e.isZero()?nt(t,r+4,i).times(.5):(t.precision=r+6,t.rounding=1,e=new t(1).minus(e).div(e.plus(1)).sqrt().atan(),t.precision=r,t.rounding=i,e.times(2)):n===0?e.isNeg()?nt(t,r,i):new t(0):new t(NaN)},j.inverseHyperbolicCosine=j.acosh=function(){var e,t,n=this,r=n.constructor;return n.lte(1)?new r(n.eq(1)?0:NaN):n.isFinite()?(e=r.precision,t=r.rounding,r.precision=e+Math.max(Math.abs(n.e),n.sd())+4,r.rounding=1,k=!1,n=n.times(n).minus(1).sqrt().plus(n),k=!0,r.precision=e,r.rounding=t,n.ln()):new r(n)},j.inverseHyperbolicSine=j.asinh=function(){var e,t,n=this,r=n.constructor;return!n.isFinite()||n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+2*Math.max(Math.abs(n.e),n.sd())+6,r.rounding=1,k=!1,n=n.times(n).plus(1).sqrt().plus(n),k=!0,r.precision=e,r.rounding=t,n.ln())},j.inverseHyperbolicTangent=j.atanh=function(){var e,t,n,r,i=this,a=i.constructor;return i.isFinite()?i.e>=0?new a(i.abs().eq(1)?i.s/0:i.isZero()?i:NaN):(e=a.precision,t=a.rounding,r=i.sd(),Math.max(r,e)<2*-i.e-1?N(new a(i),e,t,!0):(a.precision=n=r-i.e,i=M(i.plus(1),new a(1).minus(i),n+e,1),a.precision=e+4,a.rounding=1,i=i.ln(),a.precision=e,a.rounding=t,i.times(.5))):new a(NaN)},j.inverseSine=j.asin=function(){var e,t,n,r,i=this,a=i.constructor;return i.isZero()?new a(i):(t=i.abs().cmp(1),n=a.precision,r=a.rounding,t===-1?(a.precision=n+6,a.rounding=1,i=i.div(new a(1).minus(i.times(i)).sqrt().plus(1)).atan(),a.precision=n,a.rounding=r,i.times(2)):t===0?(e=nt(a,n+4,r).times(.5),e.s=i.s,e):new a(NaN))},j.inverseTangent=j.atan=function(){var e,t,n,r,i,a,o,s,c,l=this,u=l.constructor,d=u.precision,f=u.rounding;if(!l.isFinite()){if(!l.s)return new u(NaN);if(d+4<=qe)return o=nt(u,d+4,f).times(.5),o.s=l.s,o}else if(l.isZero())return new u(l);else if(l.abs().eq(1)&&d+4<=qe)return o=nt(u,d+4,f).times(.25),o.s=l.s,o;for(u.precision=s=d+10,u.rounding=1,n=Math.min(28,s/A+2|0),e=n;e;--e)l=l.div(l.times(l).plus(1).sqrt().plus(1));for(k=!1,t=Math.ceil(s/A),r=1,c=l.times(l),o=new u(l),i=l;e!==-1;)if(i=i.times(c),a=o.minus(i.div(r+=2)),i=i.times(c),o=a.plus(i.div(r+=2)),o.d[t]!==void 0)for(e=t;o.d[e]===a.d[e]&&e--;);return n&&(o=o.times(2<this.d.length-2},j.isNaN=function(){return!this.s},j.isNegative=j.isNeg=function(){return this.s<0},j.isPositive=j.isPos=function(){return this.s>0},j.isZero=function(){return!!this.d&&this.d[0]===0},j.lessThan=j.lt=function(e){return this.cmp(e)<0},j.lessThanOrEqualTo=j.lte=function(e){return this.cmp(e)<1},j.logarithm=j.log=function(e){var t,n,r,i,a,o,s,c,l=this,u=l.constructor,d=u.precision,f=u.rounding,p=5;if(e==null)e=new u(10),t=!0;else{if(e=new u(e),n=e.d,e.s<0||!n||!n[0]||e.eq(1))return new u(NaN);t=e.eq(10)}if(n=l.d,l.s<0||!n||!n[0]||l.eq(1))return new u(n&&!n[0]?-1/0:l.s==1?n?0:1/0:NaN);if(t)if(n.length>1)a=!0;else{for(i=n[0];i%10==0;)i/=10;a=i!==1}if(k=!1,s=d+p,o=lt(l,s),r=t?tt(u,s+10):lt(e,s),c=M(o,r,s,1),Xe(c.d,i=d,f))do if(s+=10,o=lt(l,s),r=t?tt(u,s+10):lt(e,s),c=M(o,r,s,1),!a){+Je(c.d).slice(i+1,i+15)+1==0x5af3107a4000&&(c=N(c,d+1,0));break}while(Xe(c.d,i+=10,f));return k=!0,N(c,d,f)},j.minus=j.sub=function(e){var t,n,r,i,a,o,s,c,l,u,d,f,p=this,m=p.constructor;if(e=new m(e),!p.d||!e.d)return!p.s||!e.s?e=new m(NaN):p.d?e.s=-e.s:e=new m(e.d||p.s!==e.s?p:NaN),e;if(p.s!=e.s)return e.s=-e.s,p.plus(e);if(l=p.d,f=e.d,s=m.precision,c=m.rounding,!l[0]||!f[0]){if(f[0])e.s=-e.s;else if(l[0])e=new m(p);else return new m(c===3?-0:0);return k?N(e,s,c):e}if(n=Re(e.e/A),u=Re(p.e/A),l=l.slice(),a=u-n,a){for(d=a<0,d?(t=l,a=-a,o=f.length):(t=f,n=u,o=l.length),r=Math.max(Math.ceil(s/A),o)+2,a>r&&(a=r,t.length=1),t.reverse(),r=a;r--;)t.push(0);t.reverse()}else{for(r=l.length,o=f.length,d=r0;--r)l[o++]=0;for(r=f.length;r>a;){if(l[--r]o?a+1:o+1,i>o&&(i=o,n.length=1),n.reverse();i--;)n.push(0);n.reverse()}for(o=l.length,i=u.length,o-i<0&&(i=o,n=u,u=l,l=n),t=0;i;)t=(l[--i]=l[i]+u[i]+t)/We|0,l[i]%=We;for(t&&(l.unshift(t),++r),o=l.length;l[--o]==0;)l.pop();return e.d=l,e.e=et(l,r),k?N(e,s,c):e},j.precision=j.sd=function(e){var t,n=this;if(e!==void 0&&e!==!!e&&e!==1&&e!==0)throw Error(Pe+e);return n.d?(t=rt(n.d),e&&n.e+1>t&&(t=n.e+1)):t=NaN,t},j.round=function(){var e=this,t=e.constructor;return N(new t(e),e.e+1,t.rounding)},j.sine=j.sin=function(){var e,t,n=this,r=n.constructor;return n.isFinite()?n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+Math.max(n.e,n.sd())+A,r.rounding=1,n=pt(r,gt(r,n)),r.precision=e,r.rounding=t,N(Me>2?n.neg():n,e,t,!0)):new r(NaN)},j.squareRoot=j.sqrt=function(){var e,t,n,r,i,a,o=this,s=o.d,c=o.e,l=o.s,u=o.constructor;if(l!==1||!s||!s[0])return new u(!l||l<0&&(!s||s[0])?NaN:s?o:1/0);for(k=!1,l=Math.sqrt(+o),l==0||l==1/0?(t=Je(s),(t.length+c)%2==0&&(t+=`0`),l=Math.sqrt(t),c=Re((c+1)/2)-(c<0||c%2),l==1/0?t=`5e`+c:(t=l.toExponential(),t=t.slice(0,t.indexOf(`e`)+1)+c),r=new u(t)):r=new u(l.toString()),n=(c=u.precision)+3;;)if(a=r,r=a.plus(M(o,a,n+2,1)).times(.5),Je(a.d).slice(0,n)===(t=Je(r.d)).slice(0,n))if(t=t.slice(n-3,n+1),t==`9999`||!i&&t==`4999`){if(!i&&(N(a,c+1,0),a.times(a).eq(o))){r=a;break}n+=4,i=1}else{(!+t||!+t.slice(1)&&t.charAt(0)==`5`)&&(N(r,c+1,1),e=!r.times(r).eq(o));break}return k=!0,N(r,c,u.rounding,e)},j.tangent=j.tan=function(){var e,t,n=this,r=n.constructor;return n.isFinite()?n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+10,r.rounding=1,n=n.sin(),n.s=1,n=M(n,new r(1).minus(n.times(n)).sqrt(),e+10,0),r.precision=e,r.rounding=t,N(Me==2||Me==4?n.neg():n,e,t,!0)):new r(NaN)},j.times=j.mul=function(e){var t,n,r,i,a,o,s,c,l,u=this,d=u.constructor,f=u.d,p=(e=new d(e)).d;if(e.s*=u.s,!f||!f[0]||!p||!p[0])return new d(!e.s||f&&!f[0]&&!p||p&&!p[0]&&!f?NaN:!f||!p?e.s/0:e.s*0);for(n=Re(u.e/A)+Re(e.e/A),c=f.length,l=p.length,c=0;){for(t=0,i=c+r;i>r;)s=a[i]+p[r]*f[i-r-1]+t,a[i--]=s%We|0,t=s/We|0;a[i]=(a[i]+t)%We|0}for(;!a[--o];)a.pop();return t?++n:a.shift(),e.d=a,e.e=et(a,n),k?N(e,d.precision,d.rounding):e},j.toBinary=function(e,t){return _t(this,2,e,t)},j.toDecimalPlaces=j.toDP=function(e,t){var n=this,r=n.constructor;return n=new r(n),e===void 0?n:(Ye(e,0,Ee),t===void 0?t=r.rounding:Ye(t,0,8),N(n,e+n.e+1,t))},j.toExponential=function(e,t){var n,r=this,i=r.constructor;return e===void 0?n=$e(r,!0):(Ye(e,0,Ee),t===void 0?t=i.rounding:Ye(t,0,8),r=N(new i(r),e+1,t),n=$e(r,!0,e+1)),r.isNeg()&&!r.isZero()?`-`+n:n},j.toFixed=function(e,t){var n,r,i=this,a=i.constructor;return e===void 0?n=$e(i):(Ye(e,0,Ee),t===void 0?t=a.rounding:Ye(t,0,8),r=N(new a(i),e+i.e+1,t),n=$e(r,!1,e+r.e+1)),i.isNeg()&&!i.isZero()?`-`+n:n},j.toFraction=function(e){var t,n,r,i,a,o,s,c,l,u,d,f,p=this,m=p.d,h=p.constructor;if(!m)return new h(p);if(l=n=new h(1),r=c=new h(0),t=new h(r),a=t.e=rt(m)-p.e-1,o=a%A,t.d[0]=ze(10,o<0?A+o:o),e==null)e=a>0?t:l;else{if(s=new h(e),!s.isInt()||s.lt(l))throw Error(Pe+s);e=s.gt(t)?a>0?t:l:s}for(k=!1,s=new h(Je(m)),u=h.precision,h.precision=a=m.length*A*2;d=M(s,t,0,1,1),i=n.plus(d.times(r)),i.cmp(e)!=1;)n=r,r=i,i=l,l=c.plus(d.times(i)),c=i,i=t,t=s.minus(d.times(i)),s=i;return i=M(e.minus(n),r,0,1,1),c=c.plus(i.times(l)),n=n.plus(i.times(r)),c.s=l.s=p.s,f=M(l,r,a,1).minus(p).abs().cmp(M(c,n,a,1).minus(p).abs())<1?[l,r]:[c,n],h.precision=u,k=!0,f},j.toHexadecimal=j.toHex=function(e,t){return _t(this,16,e,t)},j.toNearest=function(e,t){var n=this,r=n.constructor;if(n=new r(n),e==null){if(!n.d)return n;e=new r(1),t=r.rounding}else{if(e=new r(e),t===void 0?t=r.rounding:Ye(t,0,8),!n.d)return e.s?n:e;if(!e.d)return e.s&&=n.s,e}return e.d[0]?(k=!1,n=M(n,e,0,t,1).times(e),k=!0,N(n)):(e.s=n.s,n=e),n},j.toNumber=function(){return+this},j.toOctal=function(e,t){return _t(this,8,e,t)},j.toPower=j.pow=function(e){var t,n,r,i,a,o,s=this,c=s.constructor,l=+(e=new c(e));if(!s.d||!e.d||!s.d[0]||!e.d[0])return new c(ze(+s,l));if(s=new c(s),s.eq(1))return s;if(r=c.precision,a=c.rounding,e.eq(1))return N(s,r,a);if(t=Re(e.e/A),t>=e.d.length-1&&(n=l<0?-l:l)<=Ge)return i=at(c,s,n,r),e.s<0?new c(1).div(i):N(i,r,a);if(o=s.s,o<0){if(tc.maxE+1||t0?o/0:0):(k=!1,c.rounding=s.s=1,n=Math.min(12,(t+``).length),i=ct(e.times(lt(s,r+n)),r),i.d&&(i=N(i,r+5,1),Xe(i.d,r,a)&&(t=r+10,i=N(ct(e.times(lt(s,t+n)),t),t+5,1),+Je(i.d).slice(r+1,r+15)+1==0x5af3107a4000&&(i=N(i,r+1,0)))),i.s=o,k=!0,c.rounding=a,N(i,r,a))},j.toPrecision=function(e,t){var n,r=this,i=r.constructor;return e===void 0?n=$e(r,r.e<=i.toExpNeg||r.e>=i.toExpPos):(Ye(e,1,Ee),t===void 0?t=i.rounding:Ye(t,0,8),r=N(new i(r),e,t),n=$e(r,e<=r.e||r.e<=i.toExpNeg,e)),r.isNeg()&&!r.isZero()?`-`+n:n},j.toSignificantDigits=j.toSD=function(e,t){var n=this,r=n.constructor;return e===void 0?(e=r.precision,t=r.rounding):(Ye(e,1,Ee),t===void 0?t=r.rounding:Ye(t,0,8)),N(new r(n),e,t)},j.toString=function(){var e=this,t=e.constructor,n=$e(e,e.e<=t.toExpNeg||e.e>=t.toExpPos);return e.isNeg()&&!e.isZero()?`-`+n:n},j.truncated=j.trunc=function(){return N(new this.constructor(this),this.e+1,1)},j.valueOf=j.toJSON=function(){var e=this,t=e.constructor,n=$e(e,e.e<=t.toExpNeg||e.e>=t.toExpPos);return e.isNeg()?`-`+n:n};function Je(e){var t,n,r,i=e.length-1,a=``,o=e[0];if(i>0){for(a+=o,t=1;tn)throw Error(Pe+e)}function Xe(e,t,n,r){var i,a,o,s;for(a=e[0];a>=10;a/=10)--t;return--t<0?(t+=A,i=0):(i=Math.ceil((t+1)/A),t%=A),a=ze(10,A-t),s=e[i]%a|0,r==null?t<3?(t==0?s=s/100|0:t==1&&(s=s/10|0),o=n<4&&s==99999||n>3&&s==49999||s==5e4||s==0):o=(n<4&&s+1==a||n>3&&s+1==a/2)&&(e[i+1]/a/100|0)==ze(10,t-2)-1||(s==a/2||s==0)&&(e[i+1]/a/100|0)==0:t<4?(t==0?s=s/1e3|0:t==1?s=s/100|0:t==2&&(s=s/10|0),o=(r||n<4)&&s==9999||!r&&n>3&&s==4999):o=((r||n<4)&&s+1==a||!r&&n>3&&s+1==a/2)&&(e[i+1]/a/1e3|0)==ze(10,t-3)-1,o}function Ze(e,t,n){for(var r,i=[0],a,o=0,s=e.length;on-1&&(i[r+1]===void 0&&(i[r+1]=0),i[r+1]+=i[r]/n|0,i[r]%=n)}return i.reverse()}function Qe(e,t){var n,r,i;if(t.isZero())return t;r=t.d.length,r<32?(n=Math.ceil(r/3),i=(1/ht(4,n)).toString()):(n=16,i=`2.3283064365386962890625e-10`),e.precision+=n,t=mt(e,1,t.times(i),new e(1));for(var a=n;a--;){var o=t.times(t);t=o.times(o).minus(o).times(8).plus(1)}return e.precision-=n,t}var M=(function(){function e(e,t,n){var r,i=0,a=e.length;for(e=e.slice();a--;)r=e[a]*t+i,e[a]=r%n|0,i=r/n|0;return i&&e.unshift(i),e}function t(e,t,n,r){var i,a;if(n!=r)a=n>r?1:-1;else for(i=a=0;it[i]?1:-1;break}return a}function n(e,t,n,r){for(var i=0;n--;)e[n]-=i,i=+(e[n]1;)e.shift()}return function(r,i,a,o,s,c){var l,u,d,f,p,m,h,g,_,v,y,b,x,S,ee,C,te,ne,w,re,ie=r.constructor,ae=r.s==i.s?1:-1,T=r.d,E=i.d;if(!T||!T[0]||!E||!E[0])return new ie(!r.s||!i.s||(T?E&&T[0]==E[0]:!E)?NaN:T&&T[0]==0||!E?ae*0:ae/0);for(c?(p=1,u=r.e-i.e):(c=We,p=A,u=Re(r.e/p)-Re(i.e/p)),w=E.length,te=T.length,_=new ie(ae),v=_.d=[],d=0;E[d]==(T[d]||0);d++);if(E[d]>(T[d]||0)&&u--,a==null?(S=a=ie.precision,o=ie.rounding):S=s?a+(r.e-i.e)+1:a,S<0)v.push(1),m=!0;else{if(S=S/p+2|0,d=0,w==1){for(f=0,E=E[0],S++;(d1&&(E=e(E,f,c),T=e(T,f,c),w=E.length,te=T.length),C=w,y=T.slice(0,w),b=y.length;b=c/2&&++ne;do f=0,l=t(E,y,w,b),l<0?(x=y[0],w!=b&&(x=x*c+(y[1]||0)),f=x/ne|0,f>1?(f>=c&&(f=c-1),h=e(E,f,c),g=h.length,b=y.length,l=t(h,y,g,b),l==1&&(f--,n(h,w=10;f/=10)d++;_.e=d+u*p-1,N(_,s?a+_.e+1:a,o,m)}return _}})();function N(e,t,n,r){var i,a,o,s,c,l,u,d,f,p=e.constructor;out:if(t!=null){if(d=e.d,!d)return e;for(i=1,s=d[0];s>=10;s/=10)i++;if(a=t-i,a<0)a+=A,o=t,u=d[f=0],c=u/ze(10,i-o-1)%10|0;else if(f=Math.ceil((a+1)/A),s=d.length,f>=s)if(r){for(;s++<=f;)d.push(0);u=c=0,i=1,a%=A,o=a-A+1}else break out;else{for(u=s=d[f],i=1;s>=10;s/=10)i++;a%=A,o=a-A+i,c=o<0?0:u/ze(10,i-o-1)%10|0}if(r=r||t<0||d[f+1]!==void 0||(o<0?u:u%ze(10,i-o-1)),l=n<4?(c||r)&&(n==0||n==(e.s<0?3:2)):c>5||c==5&&(n==4||r||n==6&&(a>0?o>0?u/ze(10,i-o):0:d[f-1])%10&1||n==(e.s<0?8:7)),t<1||!d[0])return d.length=0,l?(t-=e.e+1,d[0]=ze(10,(A-t%A)%A),e.e=-t||0):d[0]=e.e=0,e;if(a==0?(d.length=f,s=1,f--):(d.length=f+1,s=ze(10,A-a),d[f]=o>0?(u/ze(10,i-o)%ze(10,o)|0)*s:0),l)for(;;)if(f==0){for(a=1,o=d[0];o>=10;o/=10)a++;for(o=d[0]+=s,s=1;o>=10;o/=10)s++;a!=s&&(e.e++,d[0]==We&&(d[0]=1));break}else{if(d[f]+=s,d[f]!=We)break;d[f--]=0,s=1}for(a=d.length;d[--a]===0;)d.pop()}return k&&(e.e>p.maxE?(e.d=null,e.e=NaN):e.e0?a=a.charAt(0)+`.`+a.slice(1)+it(r):o>1&&(a=a.charAt(0)+`.`+a.slice(1)),a=a+(e.e<0?`e`:`e+`)+e.e):i<0?(a=`0.`+it(-i-1)+a,n&&(r=n-o)>0&&(a+=it(r))):i>=o?(a+=it(i+1-o),n&&(r=n-i-1)>0&&(a=a+`.`+it(r))):((r=i+1)0&&(i+1===o&&(a+=`.`),a+=it(r))),a}function et(e,t){var n=e[0];for(t*=A;n>=10;n/=10)t++;return t}function tt(e,t,n){if(t>Ke)throw k=!0,n&&(e.precision=n),Error(Fe);return N(new e(Oe),t,1,!0)}function nt(e,t,n){if(t>qe)throw Error(Fe);return N(new e(ke),t,n,!0)}function rt(e){var t=e.length-1,n=t*A+1;if(t=e[t],t){for(;t%10==0;t/=10)n--;for(t=e[0];t>=10;t/=10)n++}return n}function it(e){for(var t=``;e--;)t+=`0`;return t}function at(e,t,n,r){var i,a=new e(1),o=Math.ceil(r/A+4);for(k=!1;;){if(n%2&&(a=a.times(t),vt(a.d,o)&&(i=!0)),n=Re(n/2),n===0){n=a.d.length-1,i&&a.d[n]===0&&++a.d[n];break}t=t.times(t),vt(t.d,o)}return k=!0,a}function ot(e){return e.d[e.d.length-1]&1}function st(e,t,n){for(var r,i,a=new e(t[0]),o=0;++o17)return new f(e.d?e.d[0]?e.s<0?0:1/0:1:e.s?e.s<0?0:e:NaN);for(t==null?(k=!1,c=m):c=t,s=new f(.03125);e.e>-2;)e=e.times(s),d+=5;for(r=Math.log(ze(2,d))/Math.LN10*2+5|0,c+=r,n=a=o=new f(1),f.precision=c;;){if(a=N(a.times(e),c,1),n=n.times(++u),s=o.plus(M(a,n,c,1)),Je(s.d).slice(0,c)===Je(o.d).slice(0,c)){for(i=d;i--;)o=N(o.times(o),c,1);if(t==null)if(l<3&&Xe(o.d,c-r,p,l))f.precision=c+=10,n=a=s=new f(1),u=0,l++;else return N(o,f.precision=m,p,k=!0);else return f.precision=m,o}o=s}}function lt(e,t){var n,r,i,a,o,s,c,l,u,d,f,p=1,m=10,h=e,g=h.d,_=h.constructor,v=_.rounding,y=_.precision;if(h.s<0||!g||!g[0]||!h.e&&g[0]==1&&g.length==1)return new _(g&&!g[0]?-1/0:h.s==1?g?0:h:NaN);if(t==null?(k=!1,u=y):u=t,_.precision=u+=m,n=Je(g),r=n.charAt(0),Math.abs(a=h.e)<0x5543df729c000){for(;r<7&&r!=1||r==1&&n.charAt(1)>3;)h=h.times(e),n=Je(h.d),r=n.charAt(0),p++;a=h.e,r>1?(h=new _(`0.`+n),a++):h=new _(r+`.`+n.slice(1))}else return l=tt(_,u+2,y).times(a+``),h=lt(new _(r+`.`+n.slice(1)),u-m).plus(l),_.precision=y,t==null?N(h,y,v,k=!0):h;for(d=h,c=o=h=M(h.minus(1),h.plus(1),u,1),f=N(h.times(h),u,1),i=3;;){if(o=N(o.times(f),u,1),l=c.plus(M(o,new _(i),u,1)),Je(l.d).slice(0,u)===Je(c.d).slice(0,u))if(c=c.times(2),a!==0&&(c=c.plus(tt(_,u+2,y).times(a+``))),c=M(c,new _(p),u,1),t==null)if(Xe(c.d,u-m,v,s))_.precision=u+=m,l=o=h=M(d.minus(1),d.plus(1),u,1),f=N(h.times(h),u,1),i=s=1;else return N(c,_.precision=y,v,k=!0);else return _.precision=y,c;c=l,i+=2}}function ut(e){return String(e.s*e.s/0)}function dt(e,t){var n,r,i;for((n=t.indexOf(`.`))>-1&&(t=t.replace(`.`,``)),(r=t.search(/e/i))>0?(n<0&&(n=r),n+=+t.slice(r+1),t=t.substring(0,r)):n<0&&(n=t.length),r=0;t.charCodeAt(r)===48;r++);for(i=t.length;t.charCodeAt(i-1)===48;--i);if(t=t.slice(r,i),t){if(i-=r,e.e=n=n-r-1,e.d=[],r=(n+1)%A,n<0&&(r+=A),re.constructor.maxE?(e.d=null,e.e=NaN):e.e-1){if(t=t.replace(/(\d)_(?=\d)/g,`$1`),Ue.test(t))return dt(e,t)}else if(t===`Infinity`||t===`NaN`)return+t||(e.s=NaN),e.e=NaN,e.d=null,e;if(Ve.test(t))n=16,t=t.toLowerCase();else if(Be.test(t))n=2;else if(He.test(t))n=8;else throw Error(Pe+t);for(a=t.search(/p/i),a>0?(c=+t.slice(a+1),t=t.substring(2,a)):t=t.slice(2),a=t.indexOf(`.`),o=a>=0,r=e.constructor,o&&(t=t.replace(`.`,``),s=t.length,a=s-a,i=at(r,new r(n),a,a*2)),l=Ze(t,n,We),u=l.length-1,a=u;l[a]===0;--a)l.pop();return a<0?new r(e.s*0):(e.e=et(l,u),e.d=l,k=!1,o&&(e=M(e,i,s*4)),c&&(e=e.times(Math.abs(c)<54?ze(2,c):P.pow(2,c))),k=!0,e)}function pt(e,t){var n,r=t.d.length;if(r<3)return t.isZero()?t:mt(e,2,t,t);n=1.4*Math.sqrt(r),n=n>16?16:n|0,t=t.times(1/ht(5,n)),t=mt(e,2,t,t);for(var i,a=new e(5),o=new e(16),s=new e(20);n--;)i=t.times(t),t=t.times(a.plus(i.times(o.times(i).minus(s))));return t}function mt(e,t,n,r,i){var a,o,s,c,l=1,u=e.precision,d=Math.ceil(u/A);for(k=!1,c=n.times(n),s=new e(r);;){if(o=M(s.times(c),new e(t++*t++),u,1),s=i?r.plus(o):r.minus(o),r=M(o.times(c),new e(t++*t++),u,1),o=s.plus(r),o.d[d]!==void 0){for(a=d;o.d[a]===s.d[a]&&a--;);if(a==-1)break}a=s,s=r,r=o,o=a,l++}return k=!0,o.d.length=d+1,o}function ht(e,t){for(var n=e;--t;)n*=e;return n}function gt(e,t){var n,r=t.s<0,i=nt(e,e.precision,1),a=i.times(.5);if(t=t.abs(),t.lte(a))return Me=r?4:1,t;if(n=t.divToInt(i),n.isZero())Me=r?3:2;else{if(t=t.minus(n.times(i)),t.lte(a))return Me=ot(n)?r?2:3:r?4:1,t;Me=ot(n)?r?1:4:r?3:2}return t.minus(i).abs()}function _t(e,t,n,r){var i,a,o,s,c,l,u,d,f,p=e.constructor,m=n!==void 0;if(m?(Ye(n,1,Ee),r===void 0?r=p.rounding:Ye(r,0,8)):(n=p.precision,r=p.rounding),!e.isFinite())u=ut(e);else{for(u=$e(e),o=u.indexOf(`.`),m?(i=2,t==16?n=n*4-3:t==8&&(n=n*3-2)):i=t,o>=0&&(u=u.replace(`.`,``),f=new p(1),f.e=u.length-o,f.d=Ze($e(f),10,i),f.e=f.d.length),d=Ze(u,10,i),a=c=d.length;d[--c]==0;)d.pop();if(!d[0])u=m?`0p+0`:`0`;else{if(o<0?a--:(e=new p(e),e.d=d,e.e=a,e=M(e,f,n,r,0,i),d=e.d,a=e.e,l=je),o=d[n],s=i/2,l||=d[n+1]!==void 0,l=r<4?(o!==void 0||l)&&(r===0||r===(e.s<0?3:2)):o>s||o===s&&(r===4||l||r===6&&d[n-1]&1||r===(e.s<0?8:7)),d.length=n,l)for(;++d[--n]>i-1;)d[n]=0,n||(++a,d.unshift(1));for(c=d.length;!d[c-1];--c);for(o=0,u=``;o1)if(t==16||t==8){for(o=t==16?4:3,--c;c%o;c++)u+=`0`;for(d=Ze(u,i,t),c=d.length;!d[c-1];--c);for(o=1,u=`1.`;oc)for(a-=c;a--;)u+=`0`;else at)return e.length=t,!0}function yt(e){return new this(e).abs()}function bt(e){return new this(e).acos()}function xt(e){return new this(e).acosh()}function St(e,t){return new this(e).plus(t)}function Ct(e){return new this(e).asin()}function wt(e){return new this(e).asinh()}function Tt(e){return new this(e).atan()}function Et(e){return new this(e).atanh()}function Dt(e,t){e=new this(e),t=new this(t);var n,r=this.precision,i=this.rounding,a=r+4;return!e.s||!t.s?n=new this(NaN):!e.d&&!t.d?(n=nt(this,a,1).times(t.s>0?.25:.75),n.s=e.s):!t.d||e.isZero()?(n=t.s<0?nt(this,r,i):new this(0),n.s=e.s):!e.d||t.isZero()?(n=nt(this,a,1).times(.5),n.s=e.s):t.s<0?(this.precision=a,this.rounding=1,n=this.atan(M(e,t,a,1)),t=nt(this,a,1),this.precision=r,this.rounding=i,n=e.s<0?n.minus(t):n.plus(t)):n=this.atan(M(e,t,a,1)),n}function Ot(e){return new this(e).cbrt()}function kt(e){return N(e=new this(e),e.e+1,2)}function At(e,t,n){return new this(e).clamp(t,n)}function jt(e){if(!e||typeof e!=`object`)throw Error(Ne+`Object expected`);var t,n,r,i=e.defaults===!0,a=[`precision`,1,Ee,`rounding`,0,8,`toExpNeg`,-Te,0,`toExpPos`,0,Te,`maxE`,0,Te,`minE`,-Te,0,`modulo`,0,9];for(t=0;t=a[t+1]&&r<=a[t+2])this[n]=r;else throw Error(Pe+n+`: `+r);if(n=`crypto`,i&&(this[n]=Ae[n]),(r=e[n])!==void 0)if(r===!0||r===!1||r===0||r===1)if(r)if(typeof crypto<`u`&&crypto&&(crypto.getRandomValues||crypto.randomBytes))this[n]=!0;else throw Error(Ie);else this[n]=!1;else throw Error(Pe+n+`: `+r);return this}function Mt(e){return new this(e).cos()}function Nt(e){return new this(e).cosh()}function Pt(e){var t,n,r;function i(e){var t,n,r,a=this;if(!(a instanceof i))return new i(e);if(a.constructor=i,zt(e)){a.s=e.s,k?!e.d||e.e>i.maxE?(a.e=NaN,a.d=null):e.e=10;n/=10)t++;k?t>i.maxE?(a.e=NaN,a.d=null):t=429e7?t[a]=crypto.getRandomValues(new Uint32Array(1))[0]:s[a++]=i%1e7;else if(crypto.randomBytes){for(t=crypto.randomBytes(r*=4);a=214e7?crypto.randomBytes(4).copy(t,a):(s.push(i%1e7),a+=4);a=r/4}else throw Error(Ie);for(r=s[--a],e%=A,r&&e&&(i=ze(10,A-e),s[a]=(r/i|0)*i);s[a]===0;a--)s.pop();if(a<0)n=0,s=[0];else{for(n=-1;s[0]===0;n-=A)s.shift();for(r=1,i=s[0];i>=10;i/=10)r++;r(\[(\d*)\])*)$/;function mn(e){let t=e.type;if(pn.test(e.type)&&`components`in e){t=`(`;let n=e.components.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function vn(e){return _n.test(e)}function yn(e){return ln(_n,e)}var bn=/^event (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function xn(e){return bn.test(e)}function Sn(e){return ln(bn,e)}var Cn=/^function (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)(?: (?external|public{1}))?(?: (?pure|view|nonpayable|payable{1}))?(?: returns\s?\((?.*?)\))?$/;function wn(e){return Cn.test(e)}function Tn(e){return ln(Cn,e)}var En=/^struct (?[a-zA-Z$_][a-zA-Z0-9$_]*) \{(?.*?)\}$/;function Dn(e){return En.test(e)}function On(e){return ln(En,e)}var kn=/^constructor\((?.*?)\)(?:\s(?payable{1}))?$/;function An(e){return kn.test(e)}function jn(e){return ln(kn,e)}var Mn=/^fallback\(\) external(?:\s(?payable{1}))?$/;function Nn(e){return Mn.test(e)}function Pn(e){return ln(Mn,e)}var Fn=/^receive\(\) external payable$/;function In(e){return Fn.test(e)}var Ln=new Set([`indexed`]),Rn=new Set([`calldata`,`memory`,`storage`]),zn=class extends cn{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownTypeError`})}},Bn=class extends cn{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSolidityTypeError`})}},Vn=class extends cn{constructor({param:e}){super(`Invalid ABI parameter.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParameterError`})}},Hn=class extends cn{constructor({param:e,name:t}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`"${t}" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SolidityProtectedKeywordError`})}},Un=class extends cn{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidModifierError`})}},Wn=class extends cn{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`,`Data location can only be specified for array, struct, or mapping types, but "${n}" was given.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidFunctionModifierError`})}},Gn=class extends cn{constructor({abiParameter:e}){super(`Invalid ABI parameter.`,{details:JSON.stringify(e,null,2),metaMessages:[`ABI parameter type is invalid.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiTypeParameterError`})}},Kn=class extends cn{constructor({signature:e,type:t}){super(`Invalid ${t} signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidSignatureError`})}},qn=class extends cn{constructor({signature:e}){super(`Unknown signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSignatureError`})}},Jn=class extends cn{constructor({signature:e}){super(`Invalid struct signature.`,{details:e,metaMessages:[`No properties exist.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidStructSignatureError`})}},Yn=class extends cn{constructor({type:e}){super(`Circular reference detected.`,{metaMessages:[`Struct "${e}" is a circular reference.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`CircularReferenceError`})}},Xn=class extends cn{constructor({current:e,depth:t}){super(`Unbalanced parentheses.`,{metaMessages:[`"${e.trim()}" has too many ${t>0?`opening`:`closing`} parentheses.`],details:`Depth "${t}"`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParenthesisError`})}};function Zn(e,t,n){let r=``;if(n)for(let e of Object.entries(n)){if(!e)continue;let t=``;for(let n of e[1])t+=`[${n.type}${n.name?`:${n.name}`:``}]`;r+=`(${e[0]}{${t}})`}return t?`${t}:${e}${r}`:`${e}${r}`}var Qn=new Map([[`address`,{type:`address`}],[`bool`,{type:`bool`}],[`bytes`,{type:`bytes`}],[`bytes32`,{type:`bytes32`}],[`int`,{type:`int256`}],[`int256`,{type:`int256`}],[`string`,{type:`string`}],[`uint`,{type:`uint256`}],[`uint8`,{type:`uint8`}],[`uint16`,{type:`uint16`}],[`uint24`,{type:`uint24`}],[`uint32`,{type:`uint32`}],[`uint64`,{type:`uint64`}],[`uint96`,{type:`uint96`}],[`uint112`,{type:`uint112`}],[`uint160`,{type:`uint160`}],[`uint192`,{type:`uint192`}],[`uint256`,{type:`uint256`}],[`address owner`,{type:`address`,name:`owner`}],[`address to`,{type:`address`,name:`to`}],[`bool approved`,{type:`bool`,name:`approved`}],[`bytes _data`,{type:`bytes`,name:`_data`}],[`bytes data`,{type:`bytes`,name:`data`}],[`bytes signature`,{type:`bytes`,name:`signature`}],[`bytes32 hash`,{type:`bytes32`,name:`hash`}],[`bytes32 r`,{type:`bytes32`,name:`r`}],[`bytes32 root`,{type:`bytes32`,name:`root`}],[`bytes32 s`,{type:`bytes32`,name:`s`}],[`string name`,{type:`string`,name:`name`}],[`string symbol`,{type:`string`,name:`symbol`}],[`string tokenURI`,{type:`string`,name:`tokenURI`}],[`uint tokenId`,{type:`uint256`,name:`tokenId`}],[`uint8 v`,{type:`uint8`,name:`v`}],[`uint256 balance`,{type:`uint256`,name:`balance`}],[`uint256 tokenId`,{type:`uint256`,name:`tokenId`}],[`uint256 value`,{type:`uint256`,name:`value`}],[`event:address indexed from`,{type:`address`,name:`from`,indexed:!0}],[`event:address indexed to`,{type:`address`,name:`to`,indexed:!0}],[`event:uint indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}],[`event:uint256 indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}]]);function $n(e,t={}){if(wn(e))return er(e,t);if(xn(e))return tr(e,t);if(vn(e))return nr(e,t);if(An(e))return rr(e,t);if(Nn(e))return ir(e);if(In(e))return{type:`receive`,stateMutability:`payable`};throw new qn({signature:e})}function er(e,t={}){let n=Tn(e);if(!n)throw new Kn({signature:e,type:`function`});let r=lr(n.parameters),i=[],a=r.length;for(let e=0;e[a-zA-Z$_][a-zA-Z0-9$_]*(?:\spayable)?)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,or=/^\((?.+?)\)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,sr=/^u?int$/;function cr(e,t){let n=Zn(e,t?.type,t?.structs);if(Qn.has(n))return Qn.get(n);let r=fn.test(e),i=ln(r?or:ar,e);if(!i)throw new Vn({param:e});if(i.name&&fr(i.name))throw new Hn({param:e,name:i.name});let a=i.name?{name:i.name}:{},o=i.modifier===`indexed`?{indexed:!0}:{},s=t?.structs??{},c,l={};if(r){c=`tuple`;let e=lr(i.type),t=[],n=e.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?$/;function gr(e=[],t={},n=new Set){let r=[],i=e.length;for(let a=0;at(e,n)}function vr(e,{includeName:t=!1}={}){if(e.type!==`function`&&e.type!==`event`&&e.type!==`error`)throw new Yr(e.type);return`${e.name}(${yr(e.inputs,{includeName:t})})`}function yr(e,{includeName:t=!1}={}){return e?e.map(e=>br(e,{includeName:t})).join(t?`, `:`,`):``}function br(e,{includeName:t}){return e.type.startsWith(`tuple`)?`(${yr(e.components,{includeName:t})})${e.type.slice(5)}`:e.type+(t&&e.name?` ${e.name}`:``)}function xr(e,{strict:t=!0}={}){return!e||typeof e!=`string`?!1:t?/^0x[0-9a-fA-F]*$/.test(e):e.startsWith(`0x`)}function Sr(e){return xr(e,{strict:!1})?Math.ceil((e.length-2)/2):e.length}var Cr=`2.48.4`,wr={getDocsUrl:({docsBaseUrl:e,docsPath:t=``,docsSlug:n})=>t?`${e??`https://viem.sh`}${t}${n?`#${n}`:``}`:void 0,version:`viem@${Cr}`},I=class e extends Error{constructor(t,n={}){let r=n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details,i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=wr.getDocsUrl?.({...n,docsPath:i}),o=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...a?[`Docs: ${a}`]:[],...r?[`Details: ${r}`]:[],...wr.version?[`Version: ${wr.version}`]:[]].join(` -`);super(o,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.name=n.name??this.name,this.shortMessage=t,this.version=Cr}walk(e){return Tr(this,e)}};function Tr(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause!==void 0?Tr(e.cause,t):t?null:e}var Er=class extends I{constructor({docsPath:e}){super([`A constructor was not found on the ABI.`,`Make sure you are using the correct ABI and that the constructor exists on it.`].join(` -`),{docsPath:e,name:`AbiConstructorNotFoundError`})}},Dr=class extends I{constructor({docsPath:e}){super(["Constructor arguments were provided (`args`), but a constructor parameters (`inputs`) were not found on the ABI.","Make sure you are using the correct ABI, and that the `inputs` attribute on the constructor exists."].join(` -`),{docsPath:e,name:`AbiConstructorParamsNotFoundError`})}},Or=class extends I{constructor({data:e,params:t,size:n}){super([`Data size of ${n} bytes is too small for given parameters.`].join(` -`),{metaMessages:[`Params: (${yr(t,{includeName:!0})})`,`Data: ${e} (${n} bytes)`],name:`AbiDecodingDataSizeTooSmallError`}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`params`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`size`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=e,this.params=t,this.size=n}},kr=class extends I{constructor({cause:e}={}){super(`Cannot decode zero data ("0x") with ABI parameters.`,{name:`AbiDecodingZeroDataError`,cause:e})}},Ar=class extends I{constructor({expectedLength:e,givenLength:t,type:n}){super([`ABI encoding array length mismatch for type ${n}.`,`Expected length: ${e}`,`Given length: ${t}`].join(` -`),{name:`AbiEncodingArrayLengthMismatchError`})}},jr=class extends I{constructor({expectedSize:e,value:t}){super(`Size of bytes "${t}" (bytes${Sr(t)}) does not match expected size (bytes${e}).`,{name:`AbiEncodingBytesSizeMismatchError`})}},Mr=class extends I{constructor({expectedLength:e,givenLength:t}){super([`ABI encoding params/values length mismatch.`,`Expected length (params): ${e}`,`Given length (values): ${t}`].join(` -`),{name:`AbiEncodingLengthMismatchError`})}},Nr=class extends I{constructor(e,{docsPath:t}){super([`Arguments (\`args\`) were provided to "${e}", but "${e}" on the ABI does not contain any parameters (\`inputs\`).`,`Cannot encode error result without knowing what the parameter types are.`,`Make sure you are using the correct ABI and that the inputs exist on it.`].join(` -`),{docsPath:t,name:`AbiErrorInputsNotFoundError`})}},Pr=class extends I{constructor(e,{docsPath:t}={}){super([`Error ${e?`"${e}" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`].join(` -`),{docsPath:t,name:`AbiErrorNotFoundError`})}},Fr=class extends I{constructor(e,{docsPath:t,cause:n}){super([`Encoded error signature "${e}" not found on ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`,`You can look up the decoded signature here: https://4byte.sourcify.dev/?q=${e}.`].join(` -`),{docsPath:t,name:`AbiErrorSignatureNotFoundError`,cause:n}),Object.defineProperty(this,`signature`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.signature=e}},Ir=class extends I{constructor({docsPath:e}){super(`Cannot extract event signature from empty topics.`,{docsPath:e,name:`AbiEventSignatureEmptyTopicsError`})}},Lr=class extends I{constructor(e,{docsPath:t}){super([`Encoded event signature "${e}" not found on ABI.`,`Make sure you are using the correct ABI and that the event exists on it.`,`You can look up the signature here: https://4byte.sourcify.dev/?q=${e}.`].join(` -`),{docsPath:t,name:`AbiEventSignatureNotFoundError`})}},Rr=class extends I{constructor(e,{docsPath:t}={}){super([`Event ${e?`"${e}" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the event exists on it.`].join(` -`),{docsPath:t,name:`AbiEventNotFoundError`})}},zr=class extends I{constructor(e,{docsPath:t}={}){super([`Function ${e?`"${e}" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the function exists on it.`].join(` -`),{docsPath:t,name:`AbiFunctionNotFoundError`})}},Br=class extends I{constructor(e,{docsPath:t}){super([`Function "${e}" does not contain any \`outputs\` on ABI.`,`Cannot decode function result without knowing what the parameter types are.`,`Make sure you are using the correct ABI and that the function exists on it.`].join(` -`),{docsPath:t,name:`AbiFunctionOutputsNotFoundError`})}},Vr=class extends I{constructor(e,{docsPath:t}){super([`Encoded function signature "${e}" not found on ABI.`,`Make sure you are using the correct ABI and that the function exists on it.`,`You can look up the signature here: https://4byte.sourcify.dev/?q=${e}.`].join(` -`),{docsPath:t,name:`AbiFunctionSignatureNotFoundError`})}},Hr=class extends I{constructor(e,t){super(`Found ambiguous types in overloaded ABI items.`,{metaMessages:[`\`${e.type}\` in \`${vr(e.abiItem)}\`, and`,`\`${t.type}\` in \`${vr(t.abiItem)}\``,``,`These types encode differently and cannot be distinguished at runtime.`,`Remove one of the ambiguous items in the ABI.`],name:`AbiItemAmbiguityError`})}},Ur=class extends I{constructor({expectedSize:e,givenSize:t}){super(`Expected bytes${e}, got bytes${t}.`,{name:`BytesSizeMismatchError`})}},Wr=class extends I{constructor({abiItem:e,data:t,params:n,size:r}){super([`Data size of ${r} bytes is too small for non-indexed event parameters.`].join(` -`),{metaMessages:[`Params: (${yr(n,{includeName:!0})})`,`Data: ${t} (${r} bytes)`],name:`DecodeLogDataMismatch`}),Object.defineProperty(this,`abiItem`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`params`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`size`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiItem=e,this.data=t,this.params=n,this.size=r}},Gr=class extends I{constructor({abiItem:e,param:t}){super([`Expected a topic for indexed event parameter${t.name?` "${t.name}"`:``} on event "${vr(e,{includeName:!0})}".`].join(` -`),{name:`DecodeLogTopicsMismatch`}),Object.defineProperty(this,`abiItem`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiItem=e}},Kr=class extends I{constructor(e,{docsPath:t}){super([`Type "${e}" is not a valid encoding type.`,`Please provide a valid ABI type.`].join(` -`),{docsPath:t,name:`InvalidAbiEncodingType`})}},qr=class extends I{constructor(e,{docsPath:t}){super([`Type "${e}" is not a valid decoding type.`,`Please provide a valid ABI type.`].join(` -`),{docsPath:t,name:`InvalidAbiDecodingType`})}},Jr=class extends I{constructor(e){super([`Value "${e}" is not a valid array.`].join(` -`),{name:`InvalidArrayError`})}},Yr=class extends I{constructor(e){super([`"${e}" is not a valid definition type.`,`Valid types: "function", "event", "error"`].join(` -`),{name:`InvalidDefinitionTypeError`})}},Xr=class extends I{constructor(e){super(`Filter type "${e}" is not supported.`,{name:`FilterTypeNotSupportedError`})}},Zr=class extends I{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset "${e}" is out-of-bounds (size: ${n}).`,{name:`SliceOffsetOutOfBoundsError`})}},Qr=class extends I{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (${e}) exceeds padding size (${t}).`,{name:`SizeExceedsPaddingSizeError`})}},$r=class extends I{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} is expected to be ${t} ${n} long, but is ${e} ${n} long.`,{name:`InvalidBytesLengthError`})}};function ei(e,{dir:t,size:n=32}={}){return typeof e==`string`?ti(e,{dir:t,size:n}):ni(e,{dir:t,size:n})}function ti(e,{dir:t,size:n=32}={}){if(n===null)return e;let r=e.replace(`0x`,``);if(r.length>n*2)throw new Qr({size:Math.ceil(r.length/2),targetSize:n,type:`hex`});return`0x${r[t===`right`?`padEnd`:`padStart`](n*2,`0`)}`}function ni(e,{dir:t,size:n=32}={}){if(n===null)return e;if(e.length>n)throw new Qr({size:e.length,targetSize:n,type:`bytes`});let r=new Uint8Array(n);for(let i=0;it)throw new oi({givenSize:Sr(e),maxSize:t})}function li(e,t={}){let{signed:n}=t;t.size&&ci(e,{size:t.size});let r=BigInt(e);if(!n)return r;let i=(e.length-2)/2;return r<=(1n<t.toString(16).padStart(2,`0`));function pi(e,t={}){return typeof e==`number`||typeof e==`bigint`?L(e,t):typeof e==`string`?_i(e,t):typeof e==`boolean`?mi(e,t):hi(e,t)}function mi(e,t={}){let n=`0x${Number(e)}`;return typeof t.size==`number`?(ci(n,{size:t.size}),ei(n,{size:t.size})):n}function hi(e,t={}){let n=``;for(let t=0;ta||i=xi.zero&&e<=xi.nine)return e-xi.zero;if(e>=xi.A&&e<=xi.F)return e-(xi.A-10);if(e>=xi.a&&e<=xi.f)return e-(xi.a-10)}function Ci(e,t={}){let n=e;t.size&&(ci(n,{size:t.size}),n=ei(n,{dir:`right`,size:t.size}));let r=n.slice(2);r.length%2&&(r=`0${r}`);let i=r.length/2,a=new Uint8Array(i);for(let e=0,t=0;e>ki)*ji)%Ai,t&Oi&&(i^=Di<<(Di<n>32?s(e,t,n):de(e,t,n),Ri=(e,n,r)=>r>32?f(e,n,r):t(e,n,r);function zi(e,t=24){let n=new Uint32Array(10);for(let r=24-t;r<24;r++){for(let t=0;t<10;t++)n[t]=e[t]^e[t+10]^e[t+20]^e[t+30]^e[t+40];for(let t=0;t<10;t+=2){let r=(t+8)%10,i=(t+2)%10,a=n[i],o=n[i+1],s=Li(a,o,1)^n[r],c=Ri(a,o,1)^n[r+1];for(let n=0;n<50;n+=10)e[t+n]^=s,e[t+n+1]^=c}let t=e[2],i=e[3];for(let n=0;n<24;n++){let r=Ni[n],a=Li(t,i,r),o=Ri(t,i,r),s=Mi[n];t=e[s],i=e[s+1],e[s]=a,e[s+1]=o}for(let t=0;t<50;t+=10){for(let r=0;r<10;r++)n[r]=e[t+r];for(let r=0;r<10;r++)e[t+r]^=~n[(r+2)%10]&n[(r+4)%10]}e[0]^=R[r],e[1]^=Ii[r]}r(n)}var Bi=class e extends le{constructor(e,t,n,r=!1,i=24){if(super(),this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,this.enableXOF=!1,this.blockLen=e,this.suffix=t,this.outputLen=n,this.enableXOF=r,this.rounds=i,m(n),!(0=r&&this.keccak();let a=Math.min(r-this.posOut,i-n);e.set(t.subarray(this.posOut,this.posOut+a),n),this.posOut+=a,n+=a}return e}xofInto(e){if(!this.enableXOF)throw Error(`XOF is not possible for this instance`);return this.writeInto(e)}xof(e){return m(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(i(e,this),this.finished)throw Error(`digest() was already called`);return this.writeInto(e),this.destroy(),e}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,r(this.state)}_cloneInto(t){let{blockLen:n,suffix:r,outputLen:i,rounds:a,enableXOF:o}=this;return t||=new e(n,r,i,o,a),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=a,t.suffix=r,t.outputLen=i,t.enableXOF=o,t.destroyed=this.destroyed,t}},Vi=(e,t,n)=>ne(()=>new Bi(t,e,n));Vi(6,144,224/8),Vi(6,136,256/8),Vi(6,104,384/8),Vi(6,72,512/8),Vi(1,144,224/8);var Hi=Vi(1,136,256/8);Vi(1,104,384/8),Vi(1,72,512/8);var Ui=(e,t,n)=>te((r={})=>new Bi(t,e,r.dkLen===void 0?n:r.dkLen,!0));Ui(31,168,128/8),Ui(31,136,256/8);function z(e,t){let n=t||`hex`,r=Hi(xr(e,{strict:!1})?yi(e):e);return n===`bytes`?r:pi(r)}var Wi=e=>z(yi(e));function Gi(e){return Wi(e)}function Ki(e){let t=!0,n=``,r=0,i=``,a=!1;for(let o=0;oKi(typeof e==`string`?e:gn(e));function Ji(e){return Gi(qi(e))}var Yi=Ji,Xi=class extends I{constructor({address:e}){super(`Address "${e}" is invalid.`,{metaMessages:[`- Address must be a hex value of 20 bytes (40 hex characters).`,`- Address must match its checksum counterpart.`],name:`InvalidAddressError`})}},Zi=class extends Map{constructor(e){super(),Object.defineProperty(this,`maxSize`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&(super.delete(e),super.set(e,t)),t}set(e,t){if(super.has(e)&&super.delete(e),super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=super.keys().next().value;e!==void 0&&super.delete(e)}return this}},Qi=new Zi(8192);function $i(e,t){if(Qi.has(`${e}.${t}`))return Qi.get(`${e}.${t}`);let n=t?`${t}${e.toLowerCase()}`:e.substring(2).toLowerCase(),r=z(Ti(n),`bytes`),i=(t?n.substring(`${t}0x`.length):n).split(``);for(let e=0;e<40;e+=2)r[e>>1]>>4>=8&&i[e]&&(i[e]=i[e].toUpperCase()),(r[e>>1]&15)>=8&&i[e+1]&&(i[e+1]=i[e+1].toUpperCase());let a=`0x${i.join(``)}`;return Qi.set(`${e}.${t}`,a),a}function ea(e,t){if(!ra(e,{strict:!1}))throw new Xi({address:e});return $i(e,t)}var ta=/^0x[a-fA-F0-9]{40}$/,na=new Zi(8192);function ra(e,t){let{strict:n=!0}=t??{},r=`${e}.${n}`;if(na.has(r))return na.get(r);let i=ta.test(e)?e.toLowerCase()===e?!0:n?$i(e)===e:!0:!1;return na.set(r,i),i}function ia(e){return typeof e[0]==`string`?oa(e):aa(e)}function aa(e){let t=0;for(let n of e)t+=n.length;let n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.length;return n}function oa(e){return`0x${e.reduce((e,t)=>e+t.replace(`0x`,``),``)}`}function sa(e,t,n,{strict:r}={}){return xr(e,{strict:!1})?da(e,t,n,{strict:r}):ua(e,t,n,{strict:r})}function ca(e,t){if(typeof t==`number`&&t>0&&t>Sr(e)-1)throw new Zr({offset:t,position:`start`,size:Sr(e)})}function la(e,t,n){if(typeof t==`number`&&typeof n==`number`&&Sr(e)!==n-t)throw new Zr({offset:n,position:`end`,size:Sr(e)})}function ua(e,t,n,{strict:r}={}){ca(e,t);let i=e.slice(t,n);return r&&la(i,t,n),i}function da(e,t,n,{strict:r}={}){ca(e,t);let i=`0x${e.replace(`0x`,``).slice((t??0)*2,(n??e.length)*2)}`;return r&&la(i,t,n),i}var fa=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,pa=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;function ma(e,t){if(e.length!==t.length)throw new Mr({expectedLength:e.length,givenLength:t.length});let n=_a(ha({params:e,values:t}));return n.length===0?`0x`:n}function ha({params:e,values:t}){let n=[];for(let r=0;r0?ia([t,e]):t}}if(i)return{dynamic:!0,encoded:e}}return{dynamic:!1,encoded:ia(a.map(({encoded:e})=>e))}}function ba(e,{param:t}){let[,n]=t.type.split(`bytes`),r=Sr(e);if(!n){let t=e;return r%32!=0&&(t=ti(t,{dir:`right`,size:Math.ceil((e.length-2)/2/32)*32})),{dynamic:!0,encoded:ia([ti(L(r,{size:32})),t])}}if(r!==Number.parseInt(n,10))throw new jr({expectedSize:Number.parseInt(n,10),value:e});return{dynamic:!1,encoded:ti(e,{dir:`right`})}}function xa(e){if(typeof e!=`boolean`)throw new I(`Invalid boolean value: "${e}" (type: ${typeof e}). Expected: \`true\` or \`false\`.`);return{dynamic:!1,encoded:ti(mi(e))}}function Sa(e,{signed:t,size:n=256}){if(typeof n==`number`){let r=2n**(BigInt(n)-(t?1n:0n))-1n,i=t?-r-1n:0n;if(e>r||ee))}}function Ta(e){let t=e.match(/^(.*)\[(\d+)?\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}var Ea=e=>sa(Ji(e),0,4);function Da(e){let{abi:t,args:n=[],name:r}=e,i=xr(r,{strict:!1}),a=t.filter(e=>i?e.type===`function`?Ea(e)===r:e.type===`event`?Yi(e)===r:!1:`name`in e&&e.name===r);if(a.length===0)return;if(a.length===1)return a[0];let o;for(let e of a)if(`inputs`in e){if(!n||n.length===0){if(!e.inputs||e.inputs.length===0)return e;continue}if(e.inputs&&e.inputs.length!==0&&e.inputs.length===n.length&&n.every((t,n)=>{let r=`inputs`in e&&e.inputs[n];return r?Oa(t,r):!1})){if(o&&`inputs`in o&&o.inputs){let t=ka(e.inputs,o.inputs,n);if(t)throw new Hr({abiItem:e,type:t[0]},{abiItem:o,type:t[1]})}o=e}}return o||a[0]}function Oa(e,t){let n=typeof e,r=t.type;switch(r){case`address`:return ra(e,{strict:!1});case`bool`:return n===`boolean`;case`function`:return n===`string`;case`string`:return n===`string`;default:return r===`tuple`&&`components`in t?Object.values(t.components).every((t,r)=>n===`object`&&Oa(Object.values(e)[r],t)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(r)?n===`number`||n===`bigint`:/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(r)?n===`string`||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(r)?Array.isArray(e)&&e.every(e=>Oa(e,{...t,type:r.replace(/(\[[0-9]{0,}\])$/,``)})):!1}}function ka(e,t,n){for(let r in e){let i=e[r],a=t[r];if(i.type===`tuple`&&a.type===`tuple`&&`components`in i&&`components`in a)return ka(i.components,a.components,n[r]);let o=[i.type,a.type];if(o.includes(`address`)&&o.includes(`bytes20`)||(o.includes(`address`)&&o.includes(`string`)||o.includes(`address`)&&o.includes(`bytes`))&&ra(n[r],{strict:!1}))return o}}var Aa=`/docs/contract/encodeEventTopics`;function ja(e){let{abi:t,eventName:n,args:r}=e,i=t[0];if(n){let e=Da({abi:t,name:n});if(!e)throw new Rr(n,{docsPath:Aa});i=e}if(i.type!==`event`)throw new Rr(void 0,{docsPath:Aa});let a=Yi(vr(i)),o=[];if(r&&`inputs`in i){let e=i.inputs?.filter(e=>`indexed`in e&&e.indexed),t=Array.isArray(r)?r:Object.values(r).length>0?e?.map(e=>r[e.name])??[]:[];t.length>0&&(o=e?.map((e,n)=>Array.isArray(t[n])?t[n].map((r,i)=>Ma({param:e,value:t[n][i]})):t[n]!==void 0&&t[n]!==null?Ma({param:e,value:t[n]}):null)??[])}return[a,...o]}function Ma({param:e,value:t}){if(e.type===`string`||e.type===`bytes`)return z(yi(t));if(e.type===`tuple`||e.type.match(/^(.*)\[(\d+)?\]$/))throw new Xr(e.type);return ma([e],[t])}function Na(e,{method:t}){let n={};return e.transport.type===`fallback`&&e.transport.onResponse?.(({method:e,response:r,status:i,transport:a})=>{i===`success`&&t===e&&(n[r]=a.request)}),(t=>n[t]||e.request)}async function Pa(e,t){let{address:n,abi:r,args:i,eventName:a,fromBlock:o,strict:s,toBlock:c}=t,l=Na(e,{method:`eth_newFilter`}),u=a?ja({abi:r,args:i,eventName:a}):void 0,d=await e.request({method:`eth_newFilter`,params:[{address:n,fromBlock:typeof o==`bigint`?L(o):o,toBlock:typeof c==`bigint`?L(c):c,topics:u}]});return{abi:r,args:i,eventName:a,id:d,request:l(d),strict:!!s,type:`event`}}function B(e){return typeof e==`string`?{address:e,type:`json-rpc`}:e}var Fa=`/docs/contract/encodeFunctionData`;function Ia(e){let{abi:t,args:n,functionName:r}=e,i=t[0];if(r){let e=Da({abi:t,args:n,name:r});if(!e)throw new zr(r,{docsPath:Fa});i=e}if(i.type!==`function`)throw new zr(void 0,{docsPath:Fa});return{abi:[i],functionName:Ea(vr(i))}}function La(e){let{args:t}=e,{abi:n,functionName:r}=e.abi.length===1&&e.functionName?.startsWith(`0x`)?e:Ia(e),i=n[0];return oa([r,(`inputs`in i&&i.inputs?ma(i.inputs,t??[]):void 0)??`0x`])}var Ra={1:"An `assert` condition failed.",17:`Arithmetic operation resulted in underflow or overflow.`,18:"Division or modulo by zero (e.g. `5 / 0` or `23 % 0`).",33:`Attempted to convert to an invalid type.`,34:`Attempted to access a storage byte array that is incorrectly encoded.`,49:"Performed `.pop()` on an empty array",50:`Array index is out of bounds.`,65:`Allocated too much memory or created an array which is too large.`,81:`Attempted to call a zero-initialized variable of internal function type.`},za={inputs:[{name:`message`,type:`string`}],name:`Error`,type:`error`},Ba={inputs:[{name:`reason`,type:`uint256`}],name:`Panic`,type:`error`},Va=class extends I{constructor({offset:e}){super(`Offset \`${e}\` cannot be negative.`,{name:`NegativeOffsetError`})}},Ha=class extends I{constructor({length:e,position:t}){super(`Position \`${t}\` is out of bounds (\`0 < position < ${e}\`).`,{name:`PositionOutOfBoundsError`})}},Ua=class extends I{constructor({count:e,limit:t}){super(`Recursive read limit of \`${t}\` exceeded (recursive read count: \`${e}\`).`,{name:`RecursiveReadLimitExceededError`})}},Wa={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:1/0,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new Ua({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new Ha({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new Va({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new Va({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let n=t??this.position;return this.assertPosition(n+e-1),this.bytes.subarray(n,n+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let n=this.inspectBytes(e);return this.position+=t??e,n},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===1/0)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}};function Ga(e,{recursiveReadLimit:t=8192}={}){let n=Object.create(Wa);return n.bytes=e,n.dataView=new DataView(e.buffer??e,e.byteOffset,e.byteLength),n.positionReadCount=new Map,n.recursiveReadLimit=t,n}function Ka(e,t={}){return t.size!==void 0&&ci(e,{size:t.size}),li(hi(e,t),t)}function qa(e,t={}){let n=e;if(t.size!==void 0&&(ci(n,{size:t.size}),n=si(n)),n.length>1||n[0]>1)throw new ii(n);return!!n[0]}function Ja(e,t={}){return t.size!==void 0&&ci(e,{size:t.size}),di(hi(e,t),t)}function Ya(e,t={}){let n=e;return t.size!==void 0&&(ci(n,{size:t.size}),n=si(n,{dir:`right`})),new TextDecoder().decode(n)}function Xa(e,t){let n=typeof t==`string`?Ci(t):t,r=Ga(n);if(Sr(n)===0&&e.length>0)throw new kr;if(Sr(t)&&Sr(t)<32)throw new Or({data:typeof t==`string`?t:hi(t),params:e,size:Sr(t)});let i=0,a=[];for(let t=0;t48?Ka(i,{signed:n}):Ja(i,{signed:n}),32]}function ao(e,t,{staticPosition:n}){let r=t.components.length===0||t.components.some(({name:e})=>!e),i=r?[]:{},a=0;if(so(t)){let o=n+Ja(e.readBytes($a));for(let n=0;ne.type===`error`&&i===Ea(vr(e)));if(!a)throw new Fr(i,{docsPath:`/docs/contract/decodeErrorResult`,cause:r});return{abiItem:a,args:`inputs`in a&&a.inputs&&a.inputs.length>0?Xa(a.inputs,sa(n,4)):void 0,errorName:a.name}}var V=(e,t,n)=>JSON.stringify(e,(e,n)=>{let r=typeof n==`bigint`?n.toString():n;return typeof t==`function`?t(e,r):r},n);function lo({abiItem:e,args:t,includeFunctionName:n=!0,includeName:r=!1}){if(`name`in e&&`inputs`in e&&e.inputs)return`${n?e.name:``}(${e.inputs.map((e,n)=>`${r&&e.name?`${e.name}: `:``}${typeof t[n]==`object`?V(t[n]):t[n]}`).join(`, `)})`}var uo={gwei:9,wei:18},H={ether:-9,wei:9};function U(e,t){let n=e.toString(),r=n.startsWith(`-`);r&&(n=n.slice(1)),n=n.padStart(t,`0`);let[i,a]=[n.slice(0,n.length-t),n.slice(n.length-t)];return a=a.replace(/(0+)$/,``),`${r?`-`:``}${i||`0`}${a?`.${a}`:``}`}function fo(e,t=`wei`){return U(e,uo[t])}function po(e,t=`wei`){return U(e,H[t])}var mo=class extends I{constructor({address:e}){super(`State for account "${e}" is set multiple times.`,{name:`AccountStateConflictError`})}},ho=class extends I{constructor(){super(`state and stateDiff are set on the same account.`,{name:`StateAssignmentConflictError`})}};function go(e){return e.reduce((e,{slot:t,value:n})=>`${e} ${t}: ${n}\n`,``)}function _o(e){return e.reduce((e,{address:t,...n})=>{let r=`${e} ${t}:\n`;return n.nonce&&(r+=` nonce: ${n.nonce}\n`),n.balance&&(r+=` balance: ${n.balance}\n`),n.code&&(r+=` code: ${n.code}\n`),n.state&&(r+=` state: -`,r+=go(n.state)),n.stateDiff&&(r+=` stateDiff: -`,r+=go(n.stateDiff)),r},` State Override: -`).slice(0,-1)}function vo(e){let t=Object.entries(e).map(([e,t])=>t===void 0||t===!1?null:[e,t]).filter(Boolean),n=t.reduce((e,[t])=>Math.max(e,t.length),0);return t.map(([e,t])=>` ${`${e}:`.padEnd(n+1)} ${t}`).join(` -`)}var yo=class extends I{constructor({v:e}){super(`Invalid \`v\` value "${e}". Expected 27 or 28.`,{name:`InvalidLegacyVError`})}},bo=class extends I{constructor({transaction:e}){super(`Cannot infer a transaction type from provided transaction.`,{metaMessages:[`Provided Transaction:`,`{`,vo(e),`}`,``,`To infer the type, either provide:`,"- a `type` to the Transaction, or","- an EIP-1559 Transaction with `maxFeePerGas`, or","- an EIP-2930 Transaction with `gasPrice` & `accessList`, or","- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or","- an EIP-7702 Transaction with `authorizationList`, or","- a Legacy Transaction with `gasPrice`"],name:`InvalidSerializableTransactionError`})}},xo=class extends I{constructor({storageKey:e}){super(`Size for storage key "${e}" is invalid. Expected 32 bytes. Got ${Math.floor((e.length-2)/2)} bytes.`,{name:`InvalidStorageKeySizeError`})}},So=class extends I{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d}){let f=vo({chain:r&&`${r?.name} (id: ${r?.id})`,from:t?.address,to:u,value:d!==void 0&&`${fo(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${po(o)} gwei`,maxFeePerGas:s!==void 0&&`${po(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${po(c)} gwei`,nonce:l});super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Request Arguments:`,f].filter(Boolean),name:`TransactionExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},Co=class extends I{constructor({blockHash:e,blockNumber:t,blockTag:n,hash:r,index:i}){let a=`Transaction`;n&&i!==void 0&&(a=`Transaction at block time "${n}" at index "${i}"`),e&&i!==void 0&&(a=`Transaction at block hash "${e}" at index "${i}"`),t&&i!==void 0&&(a=`Transaction at block number "${t}" at index "${i}"`),r&&(a=`Transaction with hash "${r}"`),super(`${a} could not be found.`,{name:`TransactionNotFoundError`})}},wo=class extends I{constructor({hash:e}){super(`Transaction receipt with hash "${e}" could not be found. The Transaction may not be processed on a block yet.`,{name:`TransactionReceiptNotFoundError`})}},To=class extends I{constructor({receipt:e}){super(`Transaction with hash "${e.transactionHash}" reverted.`,{metaMessages:[`The receipt marked the transaction as "reverted". This could mean that the function on the contract you are trying to call threw an error.`,` `,`You can attempt to extract the revert reason by:`,"- calling the `simulateContract` or `simulateCalls` Action with the `abi` and `functionName` of the contract","- using the `call` Action with raw `data`"],name:`TransactionReceiptRevertedError`}),Object.defineProperty(this,`receipt`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.receipt=e}},Eo=class extends I{constructor({hash:e}){super(`Timed out while waiting for transaction with hash "${e}" to be confirmed.`,{name:`WaitForTransactionReceiptTimeoutError`})}},Do=e=>e,Oo=e=>e,ko=class extends I{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d,stateOverride:f}){let p=vo({from:(t?B(t):void 0)?.address,to:u,value:d!==void 0&&`${fo(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${po(o)} gwei`,maxFeePerGas:s!==void 0&&`${po(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${po(c)} gwei`,nonce:l});f&&(p+=`\n${_o(f)}`),super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Raw Call Arguments:`,p].filter(Boolean),name:`CallExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},Ao=class extends I{constructor(e,{abi:t,args:n,contractAddress:r,docsPath:i,functionName:a,sender:o}){let s=Da({abi:t,args:n,name:a}),c=s?lo({abiItem:s,args:n,includeFunctionName:!1,includeName:!1}):void 0,l=s?vr(s,{includeName:!0}):void 0,u=vo({address:r&&Do(r),function:l,args:c&&c!==`()`&&`${[...Array(a?.length??0).keys()].map(()=>` `).join(``)}${c}`,sender:o});super(e.shortMessage||`An unknown error occurred while executing the contract function "${a}".`,{cause:e,docsPath:i,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],u&&`Contract Call:`,u].filter(Boolean),name:`ContractFunctionExecutionError`}),Object.defineProperty(this,`abi`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`args`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`contractAddress`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`formattedArgs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`functionName`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`sender`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abi=t,this.args=n,this.cause=e,this.contractAddress=r,this.functionName=a,this.sender=o}},jo=class extends I{constructor({abi:e,data:t,functionName:n,message:r,cause:i}){let a,o,s,c;if(t&&t!==`0x`)try{o=co({abi:e,data:t,cause:i});let{abiItem:n,errorName:r,args:a}=o;if(r===`Error`)c=a[0];else if(r===`Panic`){let[e]=a;c=Ra[e]}else{let e=n?vr(n,{includeName:!0}):void 0,t=n&&a?lo({abiItem:n,args:a,includeFunctionName:!1,includeName:!1}):void 0;s=[e?`Error: ${e}`:``,t&&t!==`()`?` ${[...Array(r?.length??0).keys()].map(()=>` `).join(``)}${t}`:``]}}catch(e){a=e}else r&&(c=r);let l;a instanceof Fr&&(l=a.signature,s=[`Unable to decode signature "${l}" as it was not found on the provided ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`,`You can look up the decoded signature here: https://4byte.sourcify.dev/?q=${l}.`]),super(c&&c!==`execution reverted`||l?[`The contract function "${n}" reverted with the following ${l?`signature`:`reason`}:`,c||l].join(` -`):`The contract function "${n}" reverted.`,{cause:a??i,metaMessages:s,name:`ContractFunctionRevertedError`}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`raw`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`reason`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`signature`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=o,this.raw=t,this.reason=c,this.signature=l}},Mo=class extends I{constructor({functionName:e,cause:t}){super(`The contract function "${e}" returned no data ("0x").`,{metaMessages:[`This could be due to any of the following:`,` - The contract does not have the function "${e}",`,` - The parameters passed to the contract function may be invalid, or`,` - The address is not a contract.`],name:`ContractFunctionZeroDataError`,cause:t})}},No=class extends I{constructor({factory:e}){super(`Deployment for counterfactual contract call failed${e?` for factory "${e}".`:``}`,{metaMessages:[`Please ensure:`,"- The `factory` is a valid contract deployment factory (ie. Create2 Factory, ERC-4337 Factory, etc).","- The `factoryData` is a valid encoded function call for contract deployment function on the factory."],name:`CounterfactualDeploymentFailedError`})}},Po=class extends I{constructor({data:e,message:t}){super(t||``,{name:`RawContractError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=e}},Fo=class extends I{constructor({body:e,cause:t,details:n,headers:r,status:i,url:a}){super(`HTTP request failed.`,{cause:t,details:n,metaMessages:[i&&`Status: ${i}`,`URL: ${Oo(a)}`,e&&`Request body: ${V(e)}`].filter(Boolean),name:`HttpRequestError`}),Object.defineProperty(this,`body`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`headers`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`status`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.body=e,this.headers=r,this.status=i,this.url=a}},Io=class extends I{constructor({body:e,error:t,url:n}){super(`RPC Request failed.`,{cause:t,details:t.message,metaMessages:[`URL: ${Oo(n)}`,`Request body: ${V(e)}`],name:`RpcRequestError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.code=t.code,this.data=t.data,this.url=n}},Lo=class extends I{constructor({body:e,url:t}){super(`The request took too long to respond.`,{details:`The request timed out.`,metaMessages:[`URL: ${Oo(t)}`,`Request body: ${V(e)}`],name:`TimeoutError`}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.url=t}},Ro=-1,zo=class extends I{constructor(e,{code:t,docsPath:n,metaMessages:r,name:i,shortMessage:a}){super(a,{cause:e,docsPath:n,metaMessages:r||e?.metaMessages,name:i||`RpcError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name=i||e.name,this.code=e instanceof Io?e.code:t??Ro}},Bo=class extends zo{constructor(e,t){super(e,t),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=t.data}},Vo=class e extends zo{constructor(t){super(t,{code:e.code,name:`ParseRpcError`,shortMessage:`Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.`})}};Object.defineProperty(Vo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32700});var Ho=class e extends zo{constructor(t){super(t,{code:e.code,name:`InvalidRequestRpcError`,shortMessage:`JSON is not a valid request object.`})}};Object.defineProperty(Ho,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32600});var Uo=class e extends zo{constructor(t,{method:n}={}){super(t,{code:e.code,name:`MethodNotFoundRpcError`,shortMessage:`The method${n?` "${n}"`:``} does not exist / is not available.`})}};Object.defineProperty(Uo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32601});var Wo=class e extends zo{constructor(t){super(t,{code:e.code,name:`InvalidParamsRpcError`,shortMessage:[`Invalid parameters were provided to the RPC method.`,`Double check you have provided the correct parameters.`].join(` -`)})}};Object.defineProperty(Wo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32602});var Go=class e extends zo{constructor(t){super(t,{code:e.code,name:`InternalRpcError`,shortMessage:`An internal error was received.`})}};Object.defineProperty(Go,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32603});var Ko=class e extends zo{constructor(t){super(t,{code:e.code,name:`InvalidInputRpcError`,shortMessage:[`Missing or invalid parameters.`,`Double check you have provided the correct parameters.`].join(` -`)})}};Object.defineProperty(Ko,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32e3});var qo=class e extends zo{constructor(t){super(t,{code:e.code,name:`ResourceNotFoundRpcError`,shortMessage:`Requested resource not found.`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`ResourceNotFoundRpcError`})}};Object.defineProperty(qo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32001});var Jo=class e extends zo{constructor(t){super(t,{code:e.code,name:`ResourceUnavailableRpcError`,shortMessage:`Requested resource not available.`})}};Object.defineProperty(Jo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32002});var Yo=class e extends zo{constructor(t){super(t,{code:e.code,name:`TransactionRejectedRpcError`,shortMessage:`Transaction creation failed.`})}};Object.defineProperty(Yo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32003});var Xo=class e extends zo{constructor(t,{method:n}={}){super(t,{code:e.code,name:`MethodNotSupportedRpcError`,shortMessage:`Method${n?` "${n}"`:``} is not supported.`})}};Object.defineProperty(Xo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32004});var Zo=class e extends zo{constructor(t){super(t,{code:e.code,name:`LimitExceededRpcError`,shortMessage:`Request exceeds defined limit.`})}};Object.defineProperty(Zo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32005});var Qo=class e extends zo{constructor(t){super(t,{code:e.code,name:`JsonRpcVersionUnsupportedError`,shortMessage:`Version of JSON-RPC protocol is not supported.`})}};Object.defineProperty(Qo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32006});var $o=class e extends Bo{constructor(t){super(t,{code:e.code,name:`UserRejectedRequestError`,shortMessage:`User rejected the request.`})}};Object.defineProperty($o,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4001});var es=class e extends Bo{constructor(t){super(t,{code:e.code,name:`UnauthorizedProviderError`,shortMessage:`The requested method and/or account has not been authorized by the user.`})}};Object.defineProperty(es,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4100});var ts=class e extends Bo{constructor(t,{method:n}={}){super(t,{code:e.code,name:`UnsupportedProviderMethodError`,shortMessage:`The Provider does not support the requested method${n?` " ${n}"`:``}.`})}};Object.defineProperty(ts,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4200});var ns=class e extends Bo{constructor(t){super(t,{code:e.code,name:`ProviderDisconnectedError`,shortMessage:`The Provider is disconnected from all chains.`})}};Object.defineProperty(ns,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4900});var rs=class e extends Bo{constructor(t){super(t,{code:e.code,name:`ChainDisconnectedError`,shortMessage:`The Provider is not connected to the requested chain.`})}};Object.defineProperty(rs,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4901});var is=class e extends Bo{constructor(t){super(t,{code:e.code,name:`SwitchChainError`,shortMessage:`An error occurred when attempting to switch chain.`})}};Object.defineProperty(is,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4902});var as=class e extends Bo{constructor(t){super(t,{code:e.code,name:`UnsupportedNonOptionalCapabilityError`,shortMessage:`This Wallet does not support a capability that was not marked as optional.`})}};Object.defineProperty(as,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5700});var os=class e extends Bo{constructor(t){super(t,{code:e.code,name:`UnsupportedChainIdError`,shortMessage:`This Wallet does not support the requested chain ID.`})}};Object.defineProperty(os,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5710});var ss=class e extends Bo{constructor(t){super(t,{code:e.code,name:`DuplicateIdError`,shortMessage:`There is already a bundle submitted with this ID.`})}};Object.defineProperty(ss,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5720});var cs=class e extends Bo{constructor(t){super(t,{code:e.code,name:`UnknownBundleIdError`,shortMessage:`This bundle id is unknown / has not been submitted`})}};Object.defineProperty(cs,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5730});var ls=class e extends Bo{constructor(t){super(t,{code:e.code,name:`BundleTooLargeError`,shortMessage:`The call bundle is too large for the Wallet to process.`})}};Object.defineProperty(ls,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5740});var us=class e extends Bo{constructor(t){super(t,{code:e.code,name:`AtomicReadyWalletRejectedUpgradeError`,shortMessage:`The Wallet can support atomicity after an upgrade, but the user rejected the upgrade.`})}};Object.defineProperty(us,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5750});var ds=class e extends Bo{constructor(t){super(t,{code:e.code,name:`AtomicityNotSupportedError`,shortMessage:`The wallet does not support atomic execution but the request requires it.`})}};Object.defineProperty(ds,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5760});var fs=class e extends Bo{constructor(t){super(t,{code:e.code,name:`WalletConnectSessionSettlementError`,shortMessage:`WalletConnect session settlement failed.`})}};Object.defineProperty(fs,`code`,{enumerable:!0,configurable:!0,writable:!0,value:7e3});var ps=class extends zo{constructor(e){super(e,{name:`UnknownRpcError`,shortMessage:`An unknown RPC error occurred.`})}},ms=3;function hs(e,{abi:t,address:n,args:r,docsPath:i,functionName:a,sender:o}){let s=e instanceof Po?e:e instanceof I?e.walk(e=>`data`in e)||e.walk():{},{code:c,data:l,details:u,message:d,shortMessage:f}=s;return new Ao(e instanceof kr?new Mo({functionName:a,cause:e}):[ms,Go.code].includes(c)&&(l||u||d||f)||c===Ko.code&&u===`execution reverted`&&l?new jo({abi:t,data:typeof l==`object`?l.data:l,functionName:a,message:s instanceof Io?u:f??d,cause:e}):e,{abi:t,args:r,contractAddress:n,docsPath:i,functionName:a,sender:o})}function gs(e){return $i(`0x${z(`0x${e.substring(4)}`).substring(26)}`)}var _s=`modulepreload`,vs=function(e){return`/`+e},ys={},bs=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}r=o(t.map(t=>{if(t=vs(t,n),t in ys)return;ys[t]=!0;let r=t.endsWith(`.css`),i=r?`[rel="stylesheet"]`:``;if(n)for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}else if(document.querySelector(`link[href="${t}"]${i}`))return;let o=document.createElement(`link`);if(o.rel=r?`stylesheet`:_s,r||(o.as=`script`),o.crossOrigin=``,o.href=t,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),r)return new Promise((e,n)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};async function xs({hash:e,signature:t}){let n=xr(e)?e:pi(e),{secp256k1:r}=await bs(async()=>{let{secp256k1:e}=await Promise.resolve().then(()=>Fg);return{secp256k1:e}},void 0);return`0x${(()=>{if(typeof t==`object`&&`r`in t&&`s`in t){let{r:e,s:n,v:i,yParity:a}=t,o=Ss(Number(a??i));return new r.Signature(li(e),li(n)).addRecoveryBit(o)}let e=xr(t)?t:pi(t);if(Sr(e)!==65)throw Error(`invalid signature length`);let n=Ss(di(`0x${e.slice(130)}`));return r.Signature.fromCompact(e.substring(2,130)).addRecoveryBit(n)})().recoverPublicKey(n.substring(2)).toHex(!1)}`}function Ss(e){if(e===0||e===1)return e;if(e===27)return 0;if(e===28)return 1;throw Error(`Invalid yParityOrV value`)}async function Cs({hash:e,signature:t}){return gs(await xs({hash:e,signature:t}))}function ws(e,t=`hex`){let n=Ts(e),r=Ga(new Uint8Array(n.length));return n.encode(r),t===`hex`?hi(r.bytes):r.bytes}function Ts(e){return Array.isArray(e)?Es(e.map(e=>Ts(e))):Ds(e)}function Es(e){let t=e.reduce((e,t)=>e+t.length,0),n=Os(t);return{length:t<=55?1+t:1+n+t,encode(r){t<=55?r.pushByte(192+t):(r.pushByte(247+n),n===1?r.pushUint8(t):n===2?r.pushUint16(t):n===3?r.pushUint24(t):r.pushUint32(t));for(let{encode:t}of e)t(r)}}}function Ds(e){let t=typeof e==`string`?Ci(e):e,n=Os(t.length);return{length:t.length===1&&t[0]<128?1:t.length<=55?1+t.length:1+n+t.length,encode(e){t.length===1&&t[0]<128?e.pushBytes(t):t.length<=55?(e.pushByte(128+t.length),e.pushBytes(t)):(e.pushByte(183+n),n===1?e.pushUint8(t.length):n===2?e.pushUint16(t.length):n===3?e.pushUint24(t.length):e.pushUint32(t.length),e.pushBytes(t))}}}function Os(e){if(e<2**8)return 1;if(e<2**16)return 2;if(e<2**24)return 3;if(e<2**32)return 4;throw new I(`Length is too large.`)}function ks(e){let{chainId:t,nonce:n,to:r}=e,i=e.contractAddress??e.address,a=z(oa([`0x05`,ws([t?L(t):`0x`,i,n?L(n):`0x`])]));return r===`bytes`?Ci(a):a}async function As(e){let{authorization:t,signature:n}=e;return Cs({hash:ks(t),signature:n??t})}var js=class extends I{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d}){let f=vo({from:t?.address,to:u,value:d!==void 0&&`${fo(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${po(o)} gwei`,maxFeePerGas:s!==void 0&&`${po(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${po(c)} gwei`,nonce:l});super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Estimate Gas Arguments:`,f].filter(Boolean),name:`EstimateGasExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},Ms=class extends I{constructor({cause:e,message:t}={}){let n=t?.replace(`execution reverted: `,``)?.replace(`execution reverted`,``);super(`Execution reverted ${n?`with reason: ${n}`:`for an unknown reason`}.`,{cause:e,name:`ExecutionRevertedError`})}};Object.defineProperty(Ms,`code`,{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(Ms,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/execution reverted|gas required exceeds allowance/});var Ns=class extends I{constructor({cause:e,maxFeePerGas:t}={}){super(`The fee cap (\`maxFeePerGas\`${t?` = ${po(t)} gwei`:``}) cannot be higher than the maximum allowed value (2^256-1).`,{cause:e,name:`FeeCapTooHighError`})}};Object.defineProperty(Ns,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/});var Ps=class extends I{constructor({cause:e,maxFeePerGas:t}={}){super(`The fee cap (\`maxFeePerGas\`${t?` = ${po(t)}`:``} gwei) cannot be lower than the block base fee.`,{cause:e,name:`FeeCapTooLowError`})}};Object.defineProperty(Ps,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/});var Fs=class extends I{constructor({cause:e,nonce:t}={}){super(`Nonce provided for the transaction ${t?`(${t}) `:``}is higher than the next one expected.`,{cause:e,name:`NonceTooHighError`})}};Object.defineProperty(Fs,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce too high/});var Is=class extends I{constructor({cause:e,nonce:t}={}){super([`Nonce provided for the transaction ${t?`(${t}) `:``}is lower than the current nonce of the account.`,"Try increasing the nonce or find the latest nonce with `getTransactionCount`."].join(` -`),{cause:e,name:`NonceTooLowError`})}};Object.defineProperty(Is,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce too low|transaction already imported|already known/});var Ls=class extends I{constructor({cause:e,nonce:t}={}){super(`Nonce provided for the transaction ${t?`(${t}) `:``}exceeds the maximum allowed nonce.`,{cause:e,name:`NonceMaxValueError`})}};Object.defineProperty(Ls,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce has max value/});var Rs=class extends I{constructor({cause:e}={}){super([`The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account.`].join(` -`),{cause:e,metaMessages:[`This error could arise when the account does not have enough funds to:`,` - pay for the total gas fee,`,` - pay for the value to send.`,` `,"The cost of the transaction is calculated as `gas * gas fee + value`, where:"," - `gas` is the amount of gas needed for transaction to execute,"," - `gas fee` is the gas fee,"," - `value` is the amount of ether to send to the recipient."],name:`InsufficientFundsError`})}};Object.defineProperty(Rs,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/insufficient funds|exceeds transaction sender account balance/});var zs=class extends I{constructor({cause:e,gas:t}={}){super(`The amount of gas ${t?`(${t}) `:``}provided for the transaction exceeds the limit allowed for the block.`,{cause:e,name:`IntrinsicGasTooHighError`})}};Object.defineProperty(zs,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too high|gas limit reached/});var Bs=class extends I{constructor({cause:e,gas:t}={}){super(`The amount of gas ${t?`(${t}) `:``}provided for the transaction is too low.`,{cause:e,name:`IntrinsicGasTooLowError`})}};Object.defineProperty(Bs,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too low/});var Vs=class extends I{constructor({cause:e}){super(`The transaction type is not supported for this chain.`,{cause:e,name:`TransactionTypeNotSupportedError`})}};Object.defineProperty(Vs,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/transaction type not valid/});var Hs=class extends I{constructor({cause:e,maxPriorityFeePerGas:t,maxFeePerGas:n}={}){super([`The provided tip (\`maxPriorityFeePerGas\`${t?` = ${po(t)} gwei`:``}) cannot be higher than the fee cap (\`maxFeePerGas\`${n?` = ${po(n)} gwei`:``}).`].join(` -`),{cause:e,name:`TipAboveFeeCapError`})}};Object.defineProperty(Hs,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max priority fee per gas higher than max fee per gas|tip higher than fee cap/});var Us=class extends I{constructor({cause:e}){super(`An error occurred while executing: ${e?.shortMessage}`,{cause:e,name:`UnknownNodeError`})}};function Ws(e,t){let n=(e.details||``).toLowerCase(),r=e instanceof I?e.walk(e=>e?.code===Ms.code):e;return r instanceof I?new Ms({cause:e,message:r.details}):Ms.nodeMessage.test(n)?new Ms({cause:e,message:e.details}):Ns.nodeMessage.test(n)?new Ns({cause:e,maxFeePerGas:t?.maxFeePerGas}):Ps.nodeMessage.test(n)?new Ps({cause:e,maxFeePerGas:t?.maxFeePerGas}):Fs.nodeMessage.test(n)?new Fs({cause:e,nonce:t?.nonce}):Is.nodeMessage.test(n)?new Is({cause:e,nonce:t?.nonce}):Ls.nodeMessage.test(n)?new Ls({cause:e,nonce:t?.nonce}):Rs.nodeMessage.test(n)?new Rs({cause:e}):zs.nodeMessage.test(n)?new zs({cause:e,gas:t?.gas}):Bs.nodeMessage.test(n)?new Bs({cause:e,gas:t?.gas}):Vs.nodeMessage.test(n)?new Vs({cause:e}):Hs.nodeMessage.test(n)?new Hs({cause:e,maxFeePerGas:t?.maxFeePerGas,maxPriorityFeePerGas:t?.maxPriorityFeePerGas}):new Us({cause:e})}function Gs(e,{docsPath:t,...n}){return new js((()=>{let t=Ws(e,n);return t instanceof Us?e:t})(),{docsPath:t,...n})}function Ks(e,{format:t}){if(!t)return{};let n={};function r(t){let i=Object.keys(t);for(let a of i)a in e&&(n[a]=e[a]),t[a]&&typeof t[a]==`object`&&!Array.isArray(t[a])&&r(t[a])}return r(t(e||{})),n}var qs={legacy:`0x0`,eip2930:`0x1`,eip1559:`0x2`,eip4844:`0x3`,eip7702:`0x4`};function Js(e,t){let n={};return e.authorizationList!==void 0&&(n.authorizationList=Ys(e.authorizationList)),e.accessList!==void 0&&(n.accessList=e.accessList),e.blobVersionedHashes!==void 0&&(n.blobVersionedHashes=e.blobVersionedHashes),e.blobs!==void 0&&(typeof e.blobs[0]==`string`?n.blobs=e.blobs:n.blobs=e.blobs.map(e=>hi(e))),e.data!==void 0&&(n.data=e.data),e.account&&(n.from=e.account.address),e.from!==void 0&&(n.from=e.from),e.gas!==void 0&&(n.gas=L(e.gas)),e.gasPrice!==void 0&&(n.gasPrice=L(e.gasPrice)),e.maxFeePerBlobGas!==void 0&&(n.maxFeePerBlobGas=L(e.maxFeePerBlobGas)),e.maxFeePerGas!==void 0&&(n.maxFeePerGas=L(e.maxFeePerGas)),e.maxPriorityFeePerGas!==void 0&&(n.maxPriorityFeePerGas=L(e.maxPriorityFeePerGas)),e.nonce!==void 0&&(n.nonce=L(e.nonce)),e.to!==void 0&&(n.to=e.to),e.type!==void 0&&(n.type=qs[e.type]),e.value!==void 0&&(n.value=L(e.value)),n}function Ys(e){return e.map(e=>({address:e.address,r:e.r?L(BigInt(e.r)):e.r,s:e.s?L(BigInt(e.s)):e.s,chainId:L(e.chainId),nonce:L(e.nonce),...e.yParity===void 0?{}:{yParity:L(e.yParity)},...e.v!==void 0&&e.yParity===void 0?{v:L(e.v)}:{}}))}function Xs(e){if(!(!e||e.length===0))return e.reduce((e,{slot:t,value:n})=>{if(t.length!==66)throw new $r({size:t.length,targetSize:66,type:`hex`});if(n.length!==66)throw new $r({size:n.length,targetSize:66,type:`hex`});return e[t]=n,e},{})}function Zs(e){let{balance:t,nonce:n,state:r,stateDiff:i,code:a}=e,o={};if(a!==void 0&&(o.code=a),t!==void 0&&(o.balance=L(t)),n!==void 0&&(o.nonce=L(n)),r!==void 0&&(o.state=Xs(r)),i!==void 0){if(o.state)throw new ho;o.stateDiff=Xs(i)}return o}function Qs(e){if(!e)return;let t={};for(let{address:n,...r}of e){if(!ra(n,{strict:!1}))throw new Xi({address:n});if(t[n])throw new mo({address:n});t[n]=Zs(r)}return t}2n**(8n-1n)-1n,2n**(16n-1n)-1n,2n**(24n-1n)-1n,2n**(32n-1n)-1n,2n**(40n-1n)-1n,2n**(48n-1n)-1n,2n**(56n-1n)-1n,2n**(64n-1n)-1n,2n**(72n-1n)-1n,2n**(80n-1n)-1n,2n**(88n-1n)-1n,2n**(96n-1n)-1n,2n**(104n-1n)-1n,2n**(112n-1n)-1n,2n**(120n-1n)-1n,2n**(128n-1n)-1n,2n**(136n-1n)-1n,2n**(144n-1n)-1n,2n**(152n-1n)-1n,2n**(160n-1n)-1n,2n**(168n-1n)-1n,2n**(176n-1n)-1n,2n**(184n-1n)-1n,2n**(192n-1n)-1n,2n**(200n-1n)-1n,2n**(208n-1n)-1n,2n**(216n-1n)-1n,2n**(224n-1n)-1n,2n**(232n-1n)-1n,2n**(240n-1n)-1n,2n**(248n-1n)-1n,2n**(256n-1n)-1n,-(2n**(8n-1n)),-(2n**(16n-1n)),-(2n**(24n-1n)),-(2n**(32n-1n)),-(2n**(40n-1n)),-(2n**(48n-1n)),-(2n**(56n-1n)),-(2n**(64n-1n)),-(2n**(72n-1n)),-(2n**(80n-1n)),-(2n**(88n-1n)),-(2n**(96n-1n)),-(2n**(104n-1n)),-(2n**(112n-1n)),-(2n**(120n-1n)),-(2n**(128n-1n)),-(2n**(136n-1n)),-(2n**(144n-1n)),-(2n**(152n-1n)),-(2n**(160n-1n)),-(2n**(168n-1n)),-(2n**(176n-1n)),-(2n**(184n-1n)),-(2n**(192n-1n)),-(2n**(200n-1n)),-(2n**(208n-1n)),-(2n**(216n-1n)),-(2n**(224n-1n)),-(2n**(232n-1n)),-(2n**(240n-1n)),-(2n**(248n-1n)),-(2n**(256n-1n));var $s=2n**256n-1n;function ec(e){let{account:t,maxFeePerGas:n,maxPriorityFeePerGas:r,to:i}=e,a=t?B(t):void 0;if(a&&!ra(a.address))throw new Xi({address:a.address});if(i&&!ra(i))throw new Xi({address:i});if(n&&n>$s)throw new Ns({maxFeePerGas:n});if(r&&n&&r>n)throw new Hs({maxFeePerGas:n,maxPriorityFeePerGas:r})}var tc=class extends I{constructor(){super("`baseFeeMultiplier` must be greater than 1.",{name:`BaseFeeScalarError`})}},nc=class extends I{constructor(){super(`Chain does not support EIP-1559 fees.`,{name:`Eip1559FeesNotSupportedError`})}},rc=class extends I{constructor({maxPriorityFeePerGas:e}){super(`\`maxFeePerGas\` cannot be less than the \`maxPriorityFeePerGas\` (${po(e)} gwei).`,{name:`MaxFeePerGasTooLowError`})}},ic=class extends I{constructor({blockHash:e,blockNumber:t}){let n=`Block`;e&&(n=`Block at hash "${e}"`),t&&(n=`Block at number "${t}"`),super(`${n} could not be found.`,{name:`BlockNotFoundError`})}},ac={"0x0":`legacy`,"0x1":`eip2930`,"0x2":`eip1559`,"0x3":`eip4844`,"0x4":`eip7702`};function oc(e,t){let n={...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,chainId:e.chainId?di(e.chainId):void 0,gas:e.gas?BigInt(e.gas):void 0,gasPrice:e.gasPrice?BigInt(e.gasPrice):void 0,maxFeePerBlobGas:e.maxFeePerBlobGas?BigInt(e.maxFeePerBlobGas):void 0,maxFeePerGas:e.maxFeePerGas?BigInt(e.maxFeePerGas):void 0,maxPriorityFeePerGas:e.maxPriorityFeePerGas?BigInt(e.maxPriorityFeePerGas):void 0,nonce:e.nonce?di(e.nonce):void 0,to:e.to?e.to:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,type:e.type?ac[e.type]:void 0,typeHex:e.type?e.type:void 0,value:e.value?BigInt(e.value):void 0,v:e.v?BigInt(e.v):void 0};return e.authorizationList&&(n.authorizationList=sc(e.authorizationList)),n.yParity=(()=>{if(e.yParity)return Number(e.yParity);if(typeof n.v==`bigint`){if(n.v===0n||n.v===27n)return 0;if(n.v===1n||n.v===28n)return 1;if(n.v>=35n)return+(n.v%2n==0n)}})(),n.type===`legacy`&&(delete n.accessList,delete n.maxFeePerBlobGas,delete n.maxFeePerGas,delete n.maxPriorityFeePerGas,delete n.yParity),n.type===`eip2930`&&(delete n.maxFeePerBlobGas,delete n.maxFeePerGas,delete n.maxPriorityFeePerGas),n.type===`eip1559`&&delete n.maxFeePerBlobGas,n}function sc(e){return e.map(e=>({address:e.address,chainId:Number(e.chainId),nonce:Number(e.nonce),r:e.r,s:e.s,yParity:Number(e.yParity)}))}function cc(e,t){let n=(e.transactions??[]).map(e=>typeof e==`string`?e:oc(e));return{...e,baseFeePerGas:e.baseFeePerGas?BigInt(e.baseFeePerGas):null,blobGasUsed:e.blobGasUsed?BigInt(e.blobGasUsed):void 0,difficulty:e.difficulty?BigInt(e.difficulty):void 0,excessBlobGas:e.excessBlobGas?BigInt(e.excessBlobGas):void 0,gasLimit:e.gasLimit?BigInt(e.gasLimit):void 0,gasUsed:e.gasUsed?BigInt(e.gasUsed):void 0,hash:e.hash?e.hash:null,logsBloom:e.logsBloom?e.logsBloom:null,nonce:e.nonce?e.nonce:null,number:e.number?BigInt(e.number):null,size:e.size?BigInt(e.size):void 0,timestamp:e.timestamp?BigInt(e.timestamp):void 0,transactions:n,totalDifficulty:e.totalDifficulty?BigInt(e.totalDifficulty):null}}async function lc(e,{blockHash:t,blockNumber:n,blockTag:r=e.experimental_blockTag??`latest`,includeTransactions:i}={}){let a=i??!1,o=n===void 0?void 0:L(n),s=null;if(s=t?await e.request({method:`eth_getBlockByHash`,params:[t,a]},{dedupe:!0}):await e.request({method:`eth_getBlockByNumber`,params:[o||r,a]},{dedupe:!!o}),!s)throw new ic({blockHash:t,blockNumber:n});return(e.chain?.formatters?.block?.format||cc)(s,`getBlock`)}async function uc(e){let t=await e.request({method:`eth_gasPrice`});return BigInt(t)}async function dc(e,t){return fc(e,t)}async function fc(e,t){let{block:n,chain:r=e.chain,request:i}=t||{};try{let t=r?.fees?.maxPriorityFeePerGas??r?.fees?.defaultPriorityFee;if(typeof t==`function`){let r=await t({block:n||await F(e,lc,`getBlock`)({}),client:e,request:i});if(r===null)throw Error();return r}return t===void 0?li(await e.request({method:`eth_maxPriorityFeePerGas`})):t}catch{let[t,r]=await Promise.all([n?Promise.resolve(n):F(e,lc,`getBlock`)({}),F(e,uc,`getGasPrice`)({})]);if(typeof t.baseFeePerGas!=`bigint`)throw new nc;let i=r-t.baseFeePerGas;return i<0n?0n:i}}async function pc(e,t){return mc(e,t)}async function mc(e,t){let{block:n,chain:r=e.chain,request:i,type:a=`eip1559`}=t||{},o=await(async()=>typeof r?.fees?.baseFeeMultiplier==`function`?r.fees.baseFeeMultiplier({block:n,client:e,request:i}):r?.fees?.baseFeeMultiplier??1.2)();if(o<1)throw new tc;let s=10**(o.toString().split(`.`)[1]?.length??0),c=e=>e*BigInt(Math.ceil(o*s))/BigInt(s),l=n||await F(e,lc,`getBlock`)({});if(typeof r?.fees?.estimateFeesPerGas==`function`){let t=await r.fees.estimateFeesPerGas({block:n,client:e,multiply:c,request:i,type:a});if(t!==null)return t}if(a===`eip1559`){if(typeof l.baseFeePerGas!=`bigint`)throw new nc;let t=typeof i?.maxPriorityFeePerGas==`bigint`?i.maxPriorityFeePerGas:await fc(e,{block:l,chain:r,request:i}),n=c(l.baseFeePerGas);return{maxFeePerGas:i?.maxFeePerGas??n+t,maxPriorityFeePerGas:t}}return{gasPrice:i?.gasPrice??c(await F(e,uc,`getGasPrice`)({}))}}async function hc(e,{address:t,blockTag:n=`latest`,blockNumber:r}){return di(await e.request({method:`eth_getTransactionCount`,params:[t,typeof r==`bigint`?L(r):n]},{dedupe:!!r}))}function gc(e){let{kzg:t}=e,n=e.to??(typeof e.blobs[0]==`string`?`hex`:`bytes`),r=typeof e.blobs[0]==`string`?e.blobs.map(e=>Ci(e)):e.blobs,i=[];for(let e of r)i.push(Uint8Array.from(t.blobToKzgCommitment(e)));return n===`bytes`?i:i.map(e=>hi(e))}function _c(e){let{kzg:t}=e,n=e.to??(typeof e.blobs[0]==`string`?`hex`:`bytes`),r=typeof e.blobs[0]==`string`?e.blobs.map(e=>Ci(e)):e.blobs,i=typeof e.commitments[0]==`string`?e.commitments.map(e=>Ci(e)):e.commitments,a=[];for(let e=0;ehi(e))}function vc(e,t,n,r){if(typeof e.setBigUint64==`function`)return e.setBigUint64(t,n,r);let i=BigInt(32),a=BigInt(4294967295),o=Number(n>>i&a),s=Number(n&a),c=r?4:0,l=r?0:4;e.setUint32(t+c,o,r),e.setUint32(t+l,s,r)}function yc(e,t,n){return e&t^~e&n}function bc(e,t,n){return e&t^e&n^t&n}var xc=class extends le{constructor(t,n,r,i){super(),this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.blockLen=t,this.outputLen=n,this.padOffset=r,this.isLE=i,this.buffer=new Uint8Array(t),this.view=e(this.buffer)}update(t){n(this),t=a(t),p(t);let{view:r,buffer:i,blockLen:o}=this,s=t.length;for(let n=0;ns-l&&(this.process(o,0),l=0);for(let e=l;ep.length)throw Error(`_sha2: outputLen bigger than state`);for(let e=0;e>>3;wc[e]=(l(n,17)^l(n,19)^n>>>10)+wc[e-7]+r+wc[e-16]|0}let{A:n,B:r,C:i,D:a,E:o,F:s,G:c,H:u}=this;for(let e=0;e<64;e++){let t=l(o,6)^l(o,11)^l(o,25),d=u+t+yc(o,s,c)+Cc[e]+wc[e]|0,f=(l(n,2)^l(n,13)^l(n,22))+bc(n,r,i)|0;u=c,c=s,s=o,o=a+d|0,a=i,i=r,r=n,n=d+f|0}n=n+this.A|0,r=r+this.B|0,i=i+this.C|0,a=a+this.D|0,o=o+this.E|0,s=s+this.F|0,c=c+this.G|0,u=u+this.H|0,this.set(n,r,i,a,o,s,c,u)}roundClean(){r(wc)}destroy(){this.set(0,0,0,0,0,0,0,0),r(this.buffer)}},Ec=h(`0x428a2f98d728ae22.0x7137449123ef65cd.0xb5c0fbcfec4d3b2f.0xe9b5dba58189dbbc.0x3956c25bf348b538.0x59f111f1b605d019.0x923f82a4af194f9b.0xab1c5ed5da6d8118.0xd807aa98a3030242.0x12835b0145706fbe.0x243185be4ee4b28c.0x550c7dc3d5ffb4e2.0x72be5d74f27b896f.0x80deb1fe3b1696b1.0x9bdc06a725c71235.0xc19bf174cf692694.0xe49b69c19ef14ad2.0xefbe4786384f25e3.0x0fc19dc68b8cd5b5.0x240ca1cc77ac9c65.0x2de92c6f592b0275.0x4a7484aa6ea6e483.0x5cb0a9dcbd41fbd4.0x76f988da831153b5.0x983e5152ee66dfab.0xa831c66d2db43210.0xb00327c898fb213f.0xbf597fc7beef0ee4.0xc6e00bf33da88fc2.0xd5a79147930aa725.0x06ca6351e003826f.0x142929670a0e6e70.0x27b70a8546d22ffc.0x2e1b21385c26c926.0x4d2c6dfc5ac42aed.0x53380d139d95b3df.0x650a73548baf63de.0x766a0abb3c77b2a8.0x81c2c92e47edaee6.0x92722c851482353b.0xa2bfe8a14cf10364.0xa81a664bbc423001.0xc24b8b70d0f89791.0xc76c51a30654be30.0xd192e819d6ef5218.0xd69906245565a910.0xf40e35855771202a.0x106aa07032bbd1b8.0x19a4c116b8d2d0c8.0x1e376c085141ab53.0x2748774cdf8eeb99.0x34b0bcb5e19b48a8.0x391c0cb3c5c95a63.0x4ed8aa4ae3418acb.0x5b9cca4f7763e373.0x682e6ff3d6b2b8a3.0x748f82ee5defb2fc.0x78a5636f43172f60.0x84c87814a1f0ab72.0x8cc702081a6439ec.0x90befffa23631e28.0xa4506cebde82bde9.0xbef9a3f7b2c67915.0xc67178f2e372532b.0xca273eceea26619c.0xd186b8c721c0c207.0xeada7dd6cde0eb1e.0xf57d4f7fee6ed178.0x06f067aa72176fba.0x0a637dc5a2c898a6.0x113f9804bef90dae.0x1b710b35131c471b.0x28db77f523047d84.0x32caab7b40c72493.0x3c9ebe0a15c9bebc.0x431d67c49c100d4c.0x4cc5d4becb3e42b6.0x597f299cfc657e2a.0x5fcb6fab3ad6faec.0x6c44198c4a475817`.split(`.`).map(e=>BigInt(e)));Ec[0],Ec[1];var Dc=ne(()=>new Tc),Oc=Dc;function kc(e,t){let n=t||`hex`,r=Oc(xr(e,{strict:!1})?yi(e):e);return n===`bytes`?r:pi(r)}function Ac(e){let{commitment:t,version:n=1}=e,r=e.to??(typeof t==`string`?`hex`:`bytes`),i=kc(t,`bytes`);return i.set([n],0),r===`bytes`?i:hi(i)}function jc(e){let{commitments:t,version:n}=e,r=e.to??(typeof t[0]==`string`?`hex`:`bytes`),i=[];for(let e of t)i.push(Ac({commitment:e,to:r,version:n}));return i}var Mc=6,Nc=4096,Pc=32*Nc,Fc=Pc*Mc-1-1*Nc*Mc,Ic=class extends I{constructor({maxSize:e,size:t}){super(`Blob size is too large.`,{metaMessages:[`Max: ${e} bytes`,`Given: ${t} bytes`],name:`BlobSizeTooLargeError`})}},Lc=class extends I{constructor(){super(`Blob data must not be empty.`,{name:`EmptyBlobError`})}},Rc=class extends I{constructor({hash:e,size:t}){super(`Versioned hash "${e}" size is invalid.`,{metaMessages:[`Expected: 32`,`Received: ${t}`],name:`InvalidVersionedHashSizeError`})}},zc=class extends I{constructor({hash:e,version:t}){super(`Versioned hash "${e}" version is invalid.`,{metaMessages:[`Expected: 1`,`Received: ${t}`],name:`InvalidVersionedHashVersionError`})}};function Bc(e){let t=e.to??(typeof e.data==`string`?`hex`:`bytes`),n=typeof e.data==`string`?Ci(e.data):e.data,r=Sr(n);if(!r)throw new Lc;if(r>761855)throw new Ic({maxSize:Fc,size:r});let i=[],a=!0,o=0;for(;a;){let e=Ga(new Uint8Array(Pc)),t=0;for(;te.bytes):i.map(e=>hi(e.bytes))}function Vc(e){let{data:t,kzg:n,to:r}=e,i=e.blobs??Bc({data:t,to:r}),a=e.commitments??gc({blobs:i,kzg:n,to:r}),o=e.proofs??_c({blobs:i,commitments:a,kzg:n,to:r}),s=[];for(let e=0;e{let t=Ws(e,n);return t instanceof Us?e:t})(),{docsPath:t,...n})}async function Wc(e){return di(await e.request({method:`eth_chainId`},{dedupe:!0}))}async function Gc(e,t){let{account:n=e.account,accessList:r,authorizationList:i,chain:a=e.chain,blobVersionedHashes:o,blobs:s,data:c,gas:l,gasPrice:u,maxFeePerBlobGas:d,maxFeePerGas:f,maxPriorityFeePerGas:p,nonce:m,nonceManager:h,to:g,type:_,value:v,...y}=t,b=await(async()=>{if(!n||!h||m!==void 0)return m;let t=B(n),r=a?a.id:await F(e,Wc,`getChainId`)({});return await h.consume({address:t.address,chainId:r,client:e})})();ec(t);let x=a?.formatters?.transactionRequest?.format,S=(x||Js)({...Ks(y,{format:x}),account:n?B(n):void 0,accessList:r,authorizationList:i,blobs:s,blobVersionedHashes:o,data:c,gas:l,gasPrice:u,maxFeePerBlobGas:d,maxFeePerGas:f,maxPriorityFeePerGas:p,nonce:b,to:g,type:_,value:v},`fillTransaction`);try{let n=await e.request({method:`eth_fillTransaction`,params:[S]}),r=(a?.formatters?.transaction?.format||oc)(n.tx);delete r.blockHash,delete r.blockNumber,delete r.r,delete r.s,delete r.transactionIndex,delete r.v,delete r.yParity,r.data=r.input,r.gas&&=t.gas??r.gas,r.gasPrice&&=t.gasPrice??r.gasPrice,r.maxFeePerBlobGas&&=t.maxFeePerBlobGas??r.maxFeePerBlobGas,r.maxFeePerGas&&=t.maxFeePerGas??r.maxFeePerGas,r.maxPriorityFeePerGas&&=t.maxPriorityFeePerGas??r.maxPriorityFeePerGas,r.nonce!==void 0&&(r.nonce=t.nonce??r.nonce);let i=await(async()=>{if(typeof a?.fees?.baseFeeMultiplier==`function`){let n=await F(e,lc,`getBlock`)({});return a.fees.baseFeeMultiplier({block:n,client:e,request:t})}return a?.fees?.baseFeeMultiplier??1.2})();if(i<1)throw new tc;let o=10**(i.toString().split(`.`)[1]?.length??0),s=e=>e*BigInt(Math.ceil(i*o))/BigInt(o);return r.feePayerSignature||(r.maxFeePerGas&&!t.maxFeePerGas&&(r.maxFeePerGas=s(r.maxFeePerGas)),r.gasPrice&&!t.gasPrice&&(r.gasPrice=s(r.gasPrice))),{raw:n.raw,transaction:{from:S.from,...r},...n.capabilities?{capabilities:n.capabilities}:{}}}catch(n){throw Uc(n,{...t,chain:e.chain})}}var Kc=[`blobVersionedHashes`,`chainId`,`fees`,`gas`,`nonce`,`type`],qc=new Map,Jc=new Zi(128);async function Yc(e,t){let n=t;n.account??=e.account,n.parameters??=Kc;let{account:r,chain:i=e.chain,nonceManager:a,parameters:o}=n,s=(()=>{if(typeof i?.prepareTransactionRequest==`function`)return{fn:i.prepareTransactionRequest,runAt:[`beforeFillTransaction`]};if(Array.isArray(i?.prepareTransactionRequest))return{fn:i.prepareTransactionRequest[0],runAt:i.prepareTransactionRequest[1].runAt}})(),c;async function l(){return c||(n.chainId===void 0?i?i.id:(c=await F(e,Wc,`getChainId`)({}),c):n.chainId)}let u=r&&B(r),d=n.nonce;if(o.includes(`nonce`)&&d===void 0&&u&&a){let t=await l();d=await a.consume({address:u.address,chainId:t,client:e})}s?.fn&&s.runAt?.includes(`beforeFillTransaction`)&&(n=await s.fn({...n,chain:i},{phase:`beforeFillTransaction`}),d??=n.nonce);let f=!((o.includes(`blobVersionedHashes`)||o.includes(`sidecars`))&&n.kzg&&n.blobs||Jc.get(e.uid)===!1||![`fees`,`gas`].some(e=>o.includes(e)))&&(o.includes(`chainId`)&&typeof n.chainId!=`number`||o.includes(`nonce`)&&typeof d!=`number`||o.includes(`fees`)&&typeof n.gasPrice!=`bigint`&&(typeof n.maxFeePerGas!=`bigint`||typeof n.maxPriorityFeePerGas!=`bigint`)||o.includes(`gas`)&&typeof n.gas!=`bigint`)?await F(e,Gc,`fillTransaction`)({...n,nonce:d}).then(t=>{let{chainId:r,from:i,gas:a,gasPrice:o,nonce:s,maxFeePerBlobGas:c,maxFeePerGas:l,maxPriorityFeePerGas:u,type:d,...f}=t.transaction;return Jc.set(e.uid,!0),{...n,...i?{from:i}:{},...d&&!n.type?{type:d}:{},...r===void 0?{}:{chainId:r},...a===void 0?{}:{gas:a},...o===void 0?{}:{gasPrice:o},...s===void 0?{}:{nonce:s},...c!==void 0&&n.type!==`legacy`&&n.type!==`eip2930`?{maxFeePerBlobGas:c}:{},...l!==void 0&&n.type!==`legacy`&&n.type!==`eip2930`?{maxFeePerGas:l}:{},...u!==void 0&&n.type!==`legacy`&&n.type!==`eip2930`?{maxPriorityFeePerGas:u}:{},...`nonceKey`in f&&f.nonceKey!==void 0?{nonceKey:f.nonceKey}:{},...`keyAuthorization`in f&&f.keyAuthorization!==void 0&&f.keyAuthorization!==null&&!(`keyAuthorization`in n)?{keyAuthorization:f.keyAuthorization}:{},...`feePayerSignature`in f&&f.feePayerSignature!==void 0&&f.feePayerSignature!==null?{feePayerSignature:f.feePayerSignature}:{},...`feeToken`in f&&f.feeToken!==void 0&&f.feeToken!==null&&!(`feeToken`in n)?{feeToken:f.feeToken}:{},...t.capabilities?{_capabilities:t.capabilities}:{}}}).catch(t=>{let r=t;if(r.name!==`TransactionExecutionError`)return n;if(r.walk?.(e=>e.name===`ExecutionRevertedError`))throw t;return r.walk?.(e=>{let t=e;return t.name===`MethodNotFoundRpcError`||t.name===`MethodNotSupportedRpcError`||t.message?.includes(`eth_fillTransaction is not available`)})&&Jc.set(e.uid,!1),n}):n;d??=f.nonce,n={...f,...u?{from:u?.address}:{},...d===void 0?{}:{nonce:d}};let{blobs:p,gas:m,kzg:h,type:g}=n;s?.fn&&s.runAt?.includes(`beforeFillParameters`)&&(n=await s.fn({...n,chain:i},{phase:`beforeFillParameters`}));let _;async function v(){return _||(_=await F(e,lc,`getBlock`)({blockTag:`latest`}),_)}if(o.includes(`nonce`)&&d===void 0&&u&&!a&&(n.nonce=await F(e,hc,`getTransactionCount`)({address:u.address,blockTag:`pending`})),(o.includes(`blobVersionedHashes`)||o.includes(`sidecars`))&&p&&h){let e=gc({blobs:p,kzg:h});if(o.includes(`blobVersionedHashes`)){let t=jc({commitments:e,to:`hex`});n.blobVersionedHashes=t}if(o.includes(`sidecars`)){let t=Vc({blobs:p,commitments:e,proofs:_c({blobs:p,commitments:e,kzg:h}),to:`hex`});n.sidecars=t}}if(o.includes(`chainId`)&&(n.chainId=await l()),(o.includes(`fees`)||o.includes(`type`))&&g===void 0)try{n.type=Hc(n)}catch{let t=qc.get(e.uid);t===void 0&&(t=typeof(await v())?.baseFeePerGas==`bigint`,qc.set(e.uid,t)),n.type=t?`eip1559`:`legacy`}if(o.includes(`fees`))if(n.type!==`legacy`&&n.type!==`eip2930`){if(n.maxFeePerGas===void 0||n.maxPriorityFeePerGas===void 0){let{maxFeePerGas:t,maxPriorityFeePerGas:r}=await mc(e,{block:await v(),chain:i,request:n});if(n.maxPriorityFeePerGas===void 0&&n.maxFeePerGas&&n.maxFeePerGas{if(Array.isArray(r))return r;if(i?.type!==`local`)return[`blobVersionedHashes`]})();try{let n=await(async()=>{if(t.to)return t.to;if(t.authorizationList&&t.authorizationList.length>0)return await As({authorization:t.authorizationList[0]}).catch(()=>{throw new I("`to` is required. Could not infer from `authorizationList`")})})(),{accessList:o,authorizationList:s,blobs:c,blobVersionedHashes:l,blockNumber:u,blockTag:d,data:f,gas:p,gasPrice:m,maxFeePerBlobGas:h,maxFeePerGas:g,maxPriorityFeePerGas:_,nonce:v,value:y,stateOverride:b,...x}=r?await Yc(e,{...t,parameters:a,to:n}):t;if(p&&t.gas!==p)return p;let S=(typeof u==`bigint`?L(u):void 0)||d,ee=Qs(b);ec(t);let C=e.chain?.formatters?.transactionRequest?.format,te=(C||Js)({...Ks(x,{format:C}),account:i,accessList:o,authorizationList:s,blobs:c,blobVersionedHashes:l,data:f,gasPrice:m,maxFeePerBlobGas:h,maxFeePerGas:g,maxPriorityFeePerGas:_,nonce:v,to:n,value:y},`estimateGas`);return BigInt(await e.request({method:`eth_estimateGas`,params:ee?[te,S??e.experimental_blockTag??`latest`,ee]:S?[te,S]:[te]}))}catch(n){throw Gs(n,{...t,account:i,chain:e.chain})}}async function Zc(e,t){let{abi:n,address:r,args:i,functionName:a,dataSuffix:o=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,...s}=t,c=La({abi:n,args:i,functionName:a});try{return await F(e,Xc,`estimateGas`)({data:`${c}${o?o.replace(`0x`,``):``}`,to:r,...s})}catch(e){throw hs(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/estimateContractGas`,functionName:a,sender:(s.account?B(s.account):void 0)?.address})}}function Qc(e,t){if(!ra(e,{strict:!1}))throw new Xi({address:e});if(!ra(t,{strict:!1}))throw new Xi({address:t});return e.toLowerCase()===t.toLowerCase()}function $c(e,{args:t,eventName:n}={}){return{...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,blockTimestamp:e.blockTimestamp?BigInt(e.blockTimestamp):e.blockTimestamp===null?null:void 0,logIndex:e.logIndex?Number(e.logIndex):null,transactionHash:e.transactionHash?e.transactionHash:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,...n?{args:t,eventName:n}:{}}}var el=`/docs/contract/decodeEventLog`;function tl(e){let{abi:t,data:n,strict:r,topics:i}=e,a=r??!0,[o,...s]=i;if(!o)throw new Ir({docsPath:el});let c=t.find(e=>e.type===`event`&&o===Yi(vr(e)));if(!(c&&`name`in c)||c.type!==`event`)throw new Lr(o,{docsPath:el});let{name:l,inputs:u}=c,d=u?.some(e=>!(`name`in e&&e.name)),f=d?[]:{},p=u.map((e,t)=>[e,t]).filter(([e])=>`indexed`in e&&e.indexed),m=[];for(let e=0;e!(`indexed`in e&&e.indexed)),g=a?h:[...m.map(([e])=>e),...h];if(g.length>0){if(n&&n!==`0x`)try{let e=Xa(g,n);if(e){let t=0;if(!a)for(let[n,r]of m)f[d?r:n.name||r]=e[t++];if(d)for(let n=0;n0?f:void 0}}function nl({param:e,value:t}){return e.type===`string`||e.type===`bytes`||e.type===`tuple`||e.type.match(/^(.*)\[(\d+)?\]$/)?t:(Xa([e],t)||[])[0]}function rl(e){let{abi:t,args:n,logs:r,strict:i=!0}=e,a=(()=>{if(e.eventName)return Array.isArray(e.eventName)?e.eventName:[e.eventName]})(),o=t.filter(e=>e.type===`event`).map(e=>({abi:e,selector:Yi(e)}));return r.map(e=>{let t=typeof e.blockNumber==`string`?$c(e):e,r=o.filter(e=>t.topics[0]===e.selector);if(r.length===0)return null;let s,c;for(let e of r)try{s=tl({...t,abi:[e.abi],strict:!0}),c=e;break}catch{}if(!s&&!i){c=r[0];try{s=tl({data:t.data,topics:t.topics,abi:[c.abi],strict:!1})}catch{let e=c.abi.inputs?.some(e=>!(`name`in e&&e.name));return{...t,args:e?[]:{},eventName:c.abi.name}}}return!s||!c||a&&!a.includes(s.eventName)||!il({args:s.args,inputs:c.abi.inputs,matchArgs:n})?null:{...s,...t}}).filter(Boolean)}function il(e){let{args:t,inputs:n,matchArgs:r}=e;if(!r)return!0;if(!t)return!1;function i(e,t,n){try{return e.type===`address`?Qc(t,n):e.type===`string`||e.type===`bytes`?z(yi(t))===n:t===n}catch{return!1}}return Array.isArray(t)&&Array.isArray(r)?r.every((e,r)=>{if(e==null)return!0;let a=n[r];return a?(Array.isArray(e)?e:[e]).some(e=>i(a,e,t[r])):!1}):typeof t==`object`&&!Array.isArray(t)&&typeof r==`object`&&!Array.isArray(r)?Object.entries(r).every(([e,r])=>{if(r==null)return!0;let a=n.find(t=>t.name===e);return a?(Array.isArray(r)?r:[r]).some(n=>i(a,n,t[e])):!1}):!1}async function al(e,{address:t,blockHash:n,fromBlock:r,toBlock:i,event:a,events:o,args:s,strict:c}={}){let l=c??!1,u=o??(a?[a]:void 0),d=[];u&&(d=[u.flatMap(e=>ja({abi:[e],eventName:e.name,args:o?void 0:s}))],a&&(d=d[0]));let f;f=n?await e.request({method:`eth_getLogs`,params:[{address:t,topics:d,blockHash:n}]}):await e.request({method:`eth_getLogs`,params:[{address:t,topics:d,fromBlock:typeof r==`bigint`?L(r):r,toBlock:typeof i==`bigint`?L(i):i}]});let p=f.map(e=>$c(e));return u?rl({abi:u,args:s,logs:p,strict:l}):p}async function ol(e,t){let{abi:n,address:r,args:i,blockHash:a,eventName:o,fromBlock:s,toBlock:c,strict:l}=t,u=o?Da({abi:n,name:o}):void 0,d=u?void 0:n.filter(e=>e.type===`event`);return F(e,al,`getLogs`)({address:r,args:i,blockHash:a,event:u,events:d,fromBlock:s,toBlock:c,strict:l})}var sl=`/docs/contract/decodeFunctionResult`;function cl(e){let{abi:t,args:n,functionName:r,data:i}=e,a=t[0];if(r){let e=Da({abi:t,args:n,name:r});if(!e)throw new zr(r,{docsPath:sl});a=e}if(a.type!==`function`)throw new zr(void 0,{docsPath:sl});if(!a.outputs)throw new Br(a.name,{docsPath:sl});let o=Xa(a.outputs,i);if(o&&o.length>1)return o;if(o&&o.length===1)return o[0]}var ll=`0.1.1`;function ul(){return ll}var W=class e extends Error{static setStaticOptions(t){e.prototype.docsOrigin=t.docsOrigin,e.prototype.showVersion=t.showVersion,e.prototype.version=t.version}constructor(t,n={}){let r=(()=>{if(n.cause instanceof e){if(n.cause.details)return n.cause.details;if(n.cause.shortMessage)return n.cause.shortMessage}return n.cause&&`details`in n.cause&&typeof n.cause.details==`string`?n.cause.details:n.cause?.message?n.cause.message:n.details})(),i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=n.docsOrigin??e.prototype.docsOrigin,o=`${a}${i??``}`,s=!!(n.version??e.prototype.showVersion),c=n.version??e.prototype.version,l=[t||`An error occurred.`,...n.metaMessages?[``,...n.metaMessages]:[],...r||i||s?[``,r?`Details: ${r}`:void 0,i?`See: ${o}`:void 0,s?`Version: ${c}`:void 0]:[]].filter(e=>typeof e==`string`).join(` -`);super(l,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsOrigin`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`showVersion`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.cause=n.cause,this.details=r,this.docs=o,this.docsOrigin=a,this.docsPath=i,this.shortMessage=t,this.showVersion=s,this.version=c}walk(e){return dl(this,e)}};Object.defineProperty(W,`defaultStaticOptions`,{enumerable:!0,configurable:!0,writable:!0,value:{docsOrigin:`https://oxlib.sh`,showVersion:!1,version:`ox@${ul()}`}}),W.setStaticOptions(W.defaultStaticOptions);function dl(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause?dl(e.cause,t):t?null:e}function fl(e,t){if(Ml(e)>t)throw new Bl({givenSize:Ml(e),maxSize:t})}function pl(e,t){if(typeof t==`number`&&t>0&&t>Ml(e)-1)throw new K({offset:t,position:`start`,size:Ml(e)})}function ml(e,t,n){if(typeof t==`number`&&typeof n==`number`&&Ml(e)!==n-t)throw new K({offset:n,position:`end`,size:Ml(e)})}var hl={zero:48,nine:57,A:65,F:70,a:97,f:102};function gl(e){if(e>=hl.zero&&e<=hl.nine)return e-hl.zero;if(e>=hl.A&&e<=hl.F)return e-(hl.A-10);if(e>=hl.a&&e<=hl.f)return e-(hl.a-10)}function _l(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;if(e.length>r)throw new q({size:e.length,targetSize:r,type:`Bytes`});let i=new Uint8Array(r);for(let t=0;tt)throw new iu({givenSize:Zl(e),maxSize:t})}function bl(e,t){if(typeof t==`number`&&t>0&&t>Zl(e)-1)throw new au({offset:t,position:`start`,size:Zl(e)})}function xl(e,t,n){if(typeof t==`number`&&typeof n==`number`&&Zl(e)!==n-t)throw new au({offset:n,position:`end`,size:Zl(e)})}function Sl(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;let i=e.replace(`0x`,``);if(i.length>r*2)throw new ou({size:Math.ceil(i.length/2),targetSize:r,type:`Hex`});return`0x${i[n===`right`?`padEnd`:`padStart`](r*2,`0`)}`}var Cl=`#__bigint`;function wl(e,t,n){return JSON.stringify(e,(e,n)=>typeof t==`function`?t(e,n):typeof n==`bigint`?n.toString()+Cl:n,n)}var Tl=new TextDecoder,El=new TextEncoder;function Dl(e){return e instanceof Uint8Array?e:typeof e==`string`?kl(e):Ol(e)}function Ol(e){return e instanceof Uint8Array?e:new Uint8Array(e)}function kl(e,t={}){let{size:n}=t,r=e;n&&(yl(e,n),r=Yl(e,n));let i=r.slice(2);i.length%2&&(i=`0${i}`);let a=i.length/2,o=new Uint8Array(a);for(let e=0,t=0;e1||r[0]>1)throw new G(r);return!!r[0]}function Il(e,t={}){let{size:n}=t;return n!==void 0&&fl(e,n),$l(Y(e,t),t)}function Ll(e,t={}){let{size:n}=t,r=e;return n!==void 0&&(fl(r,n),r=zl(r)),Tl.decode(r)}function Rl(e){return vl(e,{dir:`left`})}function zl(e){return vl(e,{dir:`right`})}var G=class extends W{constructor(e){super(`Bytes value \`${e}\` is not a valid boolean.`,{metaMessages:["The bytes array must contain a single byte of either a `0` or `1` value."]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.InvalidBytesBooleanError`})}},Bl=class extends W{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \`${t}\` bytes. Given size: \`${e}\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeOverflowError`})}},K=class extends W{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \`${e}\` is out-of-bounds (size: \`${n}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SliceOffsetOutOfBoundsError`})}},q=class extends W{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\`${e}\`) exceeds padding size (\`${t}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeExceedsPaddingSizeError`})}},J=new TextEncoder,Vl=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`));function Hl(e,t={}){let{strict:n=!1}=t;if(!e||typeof e!=`string`)throw new nu(e);if(n&&!/^0x[0-9a-fA-F]*$/.test(e)||!e.startsWith(`0x`))throw new ru(e)}function Ul(...e){return`0x${e.reduce((e,t)=>e+t.replace(`0x`,``),``)}`}function Wl(e){return e instanceof Uint8Array?Y(e):Array.isArray(e)?Y(new Uint8Array(e)):e}function Gl(e,t={}){let n=`0x${Number(e)}`;return typeof t.size==`number`?(yl(n,t.size),Jl(n,t.size)):n}function Y(e,t={}){let n=``;for(let t=0;ta||i>1n?r:r-a-1n}function $l(e,t={}){let{signed:n,size:r}=t;return Number(!n&&!r?e:Ql(e,t))}function eu(e,t={}){let{strict:n=!1}=t;try{return Hl(e,{strict:n}),!0}catch{return!1}}var tu=class extends W{constructor({max:e,min:t,signed:n,size:r,value:i}){super(`Number \`${i}\` is not in safe${r?` ${r*8}-bit`:``}${n?` signed`:` unsigned`} integer range ${e?`(\`${t}\` to \`${e}\`)`:`(above \`${t}\`)`}`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.IntegerOutOfRangeError`})}},nu=class extends W{constructor(e){super(`Value \`${typeof e==`object`?wl(e):e}\` of type \`${typeof e}\` is an invalid hex type.`,{metaMessages:['Hex types must be represented as `"0x${string}"`.']}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.InvalidHexTypeError`})}},ru=class extends W{constructor(e){super(`Value \`${e}\` is an invalid hex value.`,{metaMessages:['Hex values must start with `"0x"` and contain only hexadecimal characters (0-9, a-f, A-F).']}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.InvalidHexValueError`})}},iu=class extends W{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \`${t}\` bytes. Given size: \`${e}\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SizeOverflowError`})}},au=class extends W{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \`${e}\` is out-of-bounds (size: \`${n}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SliceOffsetOutOfBoundsError`})}},ou=class extends W{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\`${e}\`) exceeds padding size (\`${t}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SizeExceedsPaddingSizeError`})}};function su(e){return{address:e.address,amount:Kl(e.amount),index:Kl(e.index),validatorIndex:Kl(e.validatorIndex)}}function cu(e){return{...typeof e.baseFeePerGas==`bigint`&&{baseFeePerGas:Kl(e.baseFeePerGas)},...typeof e.blobBaseFee==`bigint`&&{blobBaseFee:Kl(e.blobBaseFee)},...typeof e.feeRecipient==`string`&&{feeRecipient:e.feeRecipient},...typeof e.gasLimit==`bigint`&&{gasLimit:Kl(e.gasLimit)},...typeof e.number==`bigint`&&{number:Kl(e.number)},...typeof e.prevRandao==`bigint`&&{prevRandao:Kl(e.prevRandao)},...typeof e.time==`bigint`&&{time:Kl(e.time)},...e.withdrawals&&{withdrawals:e.withdrawals.map(su)}}}var lu=[{inputs:[{components:[{name:`target`,type:`address`},{name:`allowFailure`,type:`bool`},{name:`callData`,type:`bytes`}],name:`calls`,type:`tuple[]`}],name:`aggregate3`,outputs:[{components:[{name:`success`,type:`bool`},{name:`returnData`,type:`bytes`}],name:`returnData`,type:`tuple[]`}],stateMutability:`view`,type:`function`},{inputs:[{name:`addr`,type:`address`}],name:`getEthBalance`,outputs:[{name:`balance`,type:`uint256`}],stateMutability:`view`,type:`function`},{inputs:[],name:`getCurrentBlockTimestamp`,outputs:[{internalType:`uint256`,name:`timestamp`,type:`uint256`}],stateMutability:`view`,type:`function`}],uu=[{name:`query`,type:`function`,stateMutability:`view`,inputs:[{type:`tuple[]`,name:`queries`,components:[{type:`address`,name:`sender`},{type:`string[]`,name:`urls`},{type:`bytes`,name:`data`}]}],outputs:[{type:`bool[]`,name:`failures`},{type:`bytes[]`,name:`responses`}]},{name:`HttpError`,type:`error`,inputs:[{type:`uint16`,name:`status`},{type:`string`,name:`message`}]}],du=[{inputs:[{name:`dns`,type:`bytes`}],name:`DNSDecodingFailed`,type:`error`},{inputs:[{name:`ens`,type:`string`}],name:`DNSEncodingFailed`,type:`error`},{inputs:[],name:`EmptyAddress`,type:`error`},{inputs:[{name:`status`,type:`uint16`},{name:`message`,type:`string`}],name:`HttpError`,type:`error`},{inputs:[],name:`InvalidBatchGatewayResponse`,type:`error`},{inputs:[{name:`errorData`,type:`bytes`}],name:`ResolverError`,type:`error`},{inputs:[{name:`name`,type:`bytes`},{name:`resolver`,type:`address`}],name:`ResolverNotContract`,type:`error`},{inputs:[{name:`name`,type:`bytes`}],name:`ResolverNotFound`,type:`error`},{inputs:[{name:`primary`,type:`string`},{name:`primaryAddress`,type:`bytes`}],name:`ReverseAddressMismatch`,type:`error`},{inputs:[{internalType:`bytes4`,name:`selector`,type:`bytes4`}],name:`UnsupportedResolverProfile`,type:`error`}],fu=[...du,{name:`resolveWithGateways`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes`},{name:`data`,type:`bytes`},{name:`gateways`,type:`string[]`}],outputs:[{name:``,type:`bytes`},{name:`address`,type:`address`}]}],pu=[...du,{name:`reverseWithGateways`,type:`function`,stateMutability:`view`,inputs:[{type:`bytes`,name:`reverseName`},{type:`uint256`,name:`coinType`},{type:`string[]`,name:`gateways`}],outputs:[{type:`string`,name:`resolvedName`},{type:`address`,name:`resolver`},{type:`address`,name:`reverseResolver`}]}],mu=[{name:`text`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes32`},{name:`key`,type:`string`}],outputs:[{name:``,type:`string`}]}],hu=[{name:`addr`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes32`}],outputs:[{name:``,type:`address`}]},{name:`addr`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes32`},{name:`coinType`,type:`uint256`}],outputs:[{name:``,type:`bytes`}]}],gu=[{name:`isValidSignature`,type:`function`,stateMutability:`view`,inputs:[{name:`hash`,type:`bytes32`},{name:`signature`,type:`bytes`}],outputs:[{name:``,type:`bytes4`}]}],_u=[{inputs:[{name:`_signer`,type:`address`},{name:`_hash`,type:`bytes32`},{name:`_signature`,type:`bytes`}],stateMutability:`nonpayable`,type:`constructor`},{inputs:[{name:`_signer`,type:`address`},{name:`_hash`,type:`bytes32`},{name:`_signature`,type:`bytes`}],outputs:[{type:`bool`}],stateMutability:`nonpayable`,type:`function`,name:`isValidSig`}],vu=`0x608060405234801561001057600080fd5b5060405161018e38038061018e83398101604081905261002f91610124565b6000808351602085016000f59050803b61004857600080fd5b6000808351602085016000855af16040513d6000823e81610067573d81fd5b3d81f35b634e487b7160e01b600052604160045260246000fd5b600082601f83011261009257600080fd5b81516001600160401b038111156100ab576100ab61006b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156100d9576100d961006b565b6040528181528382016020018510156100f157600080fd5b60005b82811015610110576020818601810151838301820152016100f4565b506000918101602001919091529392505050565b6000806040838503121561013757600080fd5b82516001600160401b0381111561014d57600080fd5b61015985828601610081565b602085015190935090506001600160401b0381111561017757600080fd5b61018385828601610081565b915050925092905056fe`,yu=`0x608060405234801561001057600080fd5b506040516102c03803806102c083398101604081905261002f916101e6565b836001600160a01b03163b6000036100e457600080836001600160a01b03168360405161005c9190610270565b6000604051808303816000865af19150503d8060008114610099576040519150601f19603f3d011682016040523d82523d6000602084013e61009e565b606091505b50915091508115806100b857506001600160a01b0386163b155b156100e1578060405163101bb98d60e01b81526004016100d8919061028c565b60405180910390fd5b50505b6000808451602086016000885af16040513d6000823e81610103573d81fd5b3d81f35b80516001600160a01b038116811461011e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015457818101518382015260200161013c565b50506000910152565b600082601f83011261016e57600080fd5b81516001600160401b0381111561018757610187610123565b604051601f8201601f19908116603f011681016001600160401b03811182821017156101b5576101b5610123565b6040528181528382016020018510156101cd57600080fd5b6101de826020830160208701610139565b949350505050565b600080600080608085870312156101fc57600080fd5b61020585610107565b60208601519094506001600160401b0381111561022157600080fd5b61022d8782880161015d565b93505061023c60408601610107565b60608601519092506001600160401b0381111561025857600080fd5b6102648782880161015d565b91505092959194509250565b60008251610282818460208701610139565b9190910192915050565b60208152600082518060208401526102ab816040850160208701610139565b601f01601f1916919091016040019291505056fe`,bu=`0x608060405234801561001057600080fd5b5060405161069438038061069483398101604081905261002f9161051e565b600061003c848484610048565b9050806000526001601ff35b60007f64926492649264926492649264926492649264926492649264926492649264926100748361040c565b036101e7576000606080848060200190518101906100929190610577565b60405192955090935091506000906001600160a01b038516906100b69085906105dd565b6000604051808303816000865af19150503d80600081146100f3576040519150601f19603f3d011682016040523d82523d6000602084013e6100f8565b606091505b50509050876001600160a01b03163b60000361016057806101605760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90610190908b9087906004016105f9565b602060405180830381865afa1580156101ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d19190610633565b6001600160e01b03191614945050505050610405565b6001600160a01b0384163b1561027a57604051630b135d3f60e11b808252906001600160a01b03861690631626ba7e9061022790879087906004016105f9565b602060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102689190610633565b6001600160e01b031916149050610405565b81516041146102df5760405162461bcd60e51b815260206004820152603a602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e6774680000000000006064820152608401610157565b6102e7610425565b5060208201516040808401518451859392600091859190811061030c5761030c61065d565b016020015160f81c9050601b811480159061032b57508060ff16601c14155b1561038c5760405162461bcd60e51b815260206004820152603b602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c756500000000006064820152608401610157565b60408051600081526020810180835289905260ff83169181019190915260608101849052608081018390526001600160a01b0389169060019060a0016020604051602081039080840390855afa1580156103ea573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149450505050505b9392505050565b600060208251101561041d57600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b038116811461045857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561048c578181015183820152602001610474565b50506000910152565b600082601f8301126104a657600080fd5b81516001600160401b038111156104bf576104bf61045b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104ed576104ed61045b565b60405281815283820160200185101561050557600080fd5b610516826020830160208701610471565b949350505050565b60008060006060848603121561053357600080fd5b835161053e81610443565b6020850151604086015191945092506001600160401b0381111561056157600080fd5b61056d86828701610495565b9150509250925092565b60008060006060848603121561058c57600080fd5b835161059781610443565b60208501519093506001600160401b038111156105b357600080fd5b6105bf86828701610495565b604086015190935090506001600160401b0381111561056157600080fd5b600082516105ef818460208701610471565b9190910192915050565b828152604060208201526000825180604084015261061e816060850160208701610471565b601f01601f1916919091016060019392505050565b60006020828403121561064557600080fd5b81516001600160e01b03198116811461040557600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572`,xu=`0x608060405234801561001057600080fd5b506115b9806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e14610325578063bce38bd714610350578063c3077fa914610380578063ee82ac5e146103b2576100f3565b80634d2301cc1461026257806372425d9d1461029f57806382ad56cb146102ca57806386d516e8146102fa576100f3565b80633408e470116100c65780633408e470146101af578063399542e9146101da5780633e64a6961461020c57806342cbb15c14610237576100f3565b80630f28c97d146100f8578063174dea7114610123578063252dba421461015357806327e86d6e14610184575b600080fd5b34801561010457600080fd5b5061010d6103ef565b60405161011a9190610c0a565b60405180910390f35b61013d60048036038101906101389190610c94565b6103f7565b60405161014a9190610e94565b60405180910390f35b61016d60048036038101906101689190610f0c565b610615565b60405161017b92919061101b565b60405180910390f35b34801561019057600080fd5b506101996107ab565b6040516101a69190611064565b60405180910390f35b3480156101bb57600080fd5b506101c46107b7565b6040516101d19190610c0a565b60405180910390f35b6101f460048036038101906101ef91906110ab565b6107bf565b6040516102039392919061110b565b60405180910390f35b34801561021857600080fd5b506102216107e1565b60405161022e9190610c0a565b60405180910390f35b34801561024357600080fd5b5061024c6107e9565b6040516102599190610c0a565b60405180910390f35b34801561026e57600080fd5b50610289600480360381019061028491906111a7565b6107f1565b6040516102969190610c0a565b60405180910390f35b3480156102ab57600080fd5b506102b4610812565b6040516102c19190610c0a565b60405180910390f35b6102e460048036038101906102df919061122a565b61081a565b6040516102f19190610e94565b60405180910390f35b34801561030657600080fd5b5061030f6109e4565b60405161031c9190610c0a565b60405180910390f35b34801561033157600080fd5b5061033a6109ec565b6040516103479190611286565b60405180910390f35b61036a600480360381019061036591906110ab565b6109f4565b6040516103779190610e94565b60405180910390f35b61039a60048036038101906103959190610f0c565b610ba6565b6040516103a99392919061110b565b60405180910390f35b3480156103be57600080fd5b506103d960048036038101906103d491906112cd565b610bca565b6040516103e69190611064565b60405180910390f35b600042905090565b60606000808484905090508067ffffffffffffffff81111561041c5761041b6112fa565b5b60405190808252806020026020018201604052801561045557816020015b610442610bd5565b81526020019060019003908161043a5790505b5092503660005b828110156105c957600085828151811061047957610478611329565b5b6020026020010151905087878381811061049657610495611329565b5b90506020028101906104a89190611367565b925060008360400135905080860195508360000160208101906104cb91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16818580606001906104f2919061138f565b604051610500929190611431565b60006040518083038185875af1925050503d806000811461053d576040519150601f19603f3d011682016040523d82523d6000602084013e610542565b606091505b5083600001846020018290528215151515815250505081516020850135176105bc577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b826001019250505061045c565b5082341461060c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610603906114a7565b60405180910390fd5b50505092915050565b6000606043915060008484905090508067ffffffffffffffff81111561063e5761063d6112fa565b5b60405190808252806020026020018201604052801561067157816020015b606081526020019060019003908161065c5790505b5091503660005b828110156107a157600087878381811061069557610694611329565b5b90506020028101906106a791906114c7565b92508260000160208101906106bc91906111a7565b73ffffffffffffffffffffffffffffffffffffffff168380602001906106e2919061138f565b6040516106f0929190611431565b6000604051808303816000865af19150503d806000811461072d576040519150601f19603f3d011682016040523d82523d6000602084013e610732565b606091505b5086848151811061074657610745611329565b5b60200260200101819052819250505080610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078c9061153b565b60405180910390fd5b81600101915050610678565b5050509250929050565b60006001430340905090565b600046905090565b6000806060439250434091506107d68686866109f4565b905093509350939050565b600048905090565b600043905090565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b600044905090565b606060008383905090508067ffffffffffffffff81111561083e5761083d6112fa565b5b60405190808252806020026020018201604052801561087757816020015b610864610bd5565b81526020019060019003908161085c5790505b5091503660005b828110156109db57600084828151811061089b5761089a611329565b5b602002602001015190508686838181106108b8576108b7611329565b5b90506020028101906108ca919061155b565b92508260000160208101906108df91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060400190610905919061138f565b604051610913929190611431565b6000604051808303816000865af19150503d8060008114610950576040519150601f19603f3d011682016040523d82523d6000602084013e610955565b606091505b5082600001836020018290528215151515815250505080516020840135176109cf577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b8160010191505061087e565b50505092915050565b600045905090565b600041905090565b606060008383905090508067ffffffffffffffff811115610a1857610a176112fa565b5b604051908082528060200260200182016040528015610a5157816020015b610a3e610bd5565b815260200190600190039081610a365790505b5091503660005b82811015610b9c576000848281518110610a7557610a74611329565b5b60200260200101519050868683818110610a9257610a91611329565b5b9050602002810190610aa491906114c7565b9250826000016020810190610ab991906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060200190610adf919061138f565b604051610aed929190611431565b6000604051808303816000865af19150503d8060008114610b2a576040519150601f19603f3d011682016040523d82523d6000602084013e610b2f565b606091505b508260000183602001829052821515151581525050508715610b90578060000151610b8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b869061153b565b60405180910390fd5b5b81600101915050610a58565b5050509392505050565b6000806060610bb7600186866107bf565b8093508194508295505050509250925092565b600081409050919050565b6040518060400160405280600015158152602001606081525090565b6000819050919050565b610c0481610bf1565b82525050565b6000602082019050610c1f6000830184610bfb565b92915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610c5457610c53610c2f565b5b8235905067ffffffffffffffff811115610c7157610c70610c34565b5b602083019150836020820283011115610c8d57610c8c610c39565b5b9250929050565b60008060208385031215610cab57610caa610c25565b5b600083013567ffffffffffffffff811115610cc957610cc8610c2a565b5b610cd585828601610c3e565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60008115159050919050565b610d2281610d0d565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610d62578082015181840152602081019050610d47565b83811115610d71576000848401525b50505050565b6000601f19601f8301169050919050565b6000610d9382610d28565b610d9d8185610d33565b9350610dad818560208601610d44565b610db681610d77565b840191505092915050565b6000604083016000830151610dd96000860182610d19565b5060208301518482036020860152610df18282610d88565b9150508091505092915050565b6000610e0a8383610dc1565b905092915050565b6000602082019050919050565b6000610e2a82610ce1565b610e348185610cec565b935083602082028501610e4685610cfd565b8060005b85811015610e825784840389528151610e638582610dfe565b9450610e6e83610e12565b925060208a01995050600181019050610e4a565b50829750879550505050505092915050565b60006020820190508181036000830152610eae8184610e1f565b905092915050565b60008083601f840112610ecc57610ecb610c2f565b5b8235905067ffffffffffffffff811115610ee957610ee8610c34565b5b602083019150836020820283011115610f0557610f04610c39565b5b9250929050565b60008060208385031215610f2357610f22610c25565b5b600083013567ffffffffffffffff811115610f4157610f40610c2a565b5b610f4d85828601610eb6565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000610f918383610d88565b905092915050565b6000602082019050919050565b6000610fb182610f59565b610fbb8185610f64565b935083602082028501610fcd85610f75565b8060005b858110156110095784840389528151610fea8582610f85565b9450610ff583610f99565b925060208a01995050600181019050610fd1565b50829750879550505050505092915050565b60006040820190506110306000830185610bfb565b81810360208301526110428184610fa6565b90509392505050565b6000819050919050565b61105e8161104b565b82525050565b60006020820190506110796000830184611055565b92915050565b61108881610d0d565b811461109357600080fd5b50565b6000813590506110a58161107f565b92915050565b6000806000604084860312156110c4576110c3610c25565b5b60006110d286828701611096565b935050602084013567ffffffffffffffff8111156110f3576110f2610c2a565b5b6110ff86828701610eb6565b92509250509250925092565b60006060820190506111206000830186610bfb565b61112d6020830185611055565b818103604083015261113f8184610e1f565b9050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061117482611149565b9050919050565b61118481611169565b811461118f57600080fd5b50565b6000813590506111a18161117b565b92915050565b6000602082840312156111bd576111bc610c25565b5b60006111cb84828501611192565b91505092915050565b60008083601f8401126111ea576111e9610c2f565b5b8235905067ffffffffffffffff81111561120757611206610c34565b5b60208301915083602082028301111561122357611222610c39565b5b9250929050565b6000806020838503121561124157611240610c25565b5b600083013567ffffffffffffffff81111561125f5761125e610c2a565b5b61126b858286016111d4565b92509250509250929050565b61128081611169565b82525050565b600060208201905061129b6000830184611277565b92915050565b6112aa81610bf1565b81146112b557600080fd5b50565b6000813590506112c7816112a1565b92915050565b6000602082840312156112e3576112e2610c25565b5b60006112f1848285016112b8565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160800383360303811261138357611382611358565b5b80830191505092915050565b600080833560016020038436030381126113ac576113ab611358565b5b80840192508235915067ffffffffffffffff8211156113ce576113cd61135d565b5b6020830192506001820236038313156113ea576113e9611362565b5b509250929050565b600081905092915050565b82818337600083830152505050565b600061141883856113f2565b93506114258385846113fd565b82840190509392505050565b600061143e82848661140c565b91508190509392505050565b600082825260208201905092915050565b7f4d756c746963616c6c333a2076616c7565206d69736d61746368000000000000600082015250565b6000611491601a8361144a565b915061149c8261145b565b602082019050919050565b600060208201905081810360008301526114c081611484565b9050919050565b6000823560016040038336030381126114e3576114e2611358565b5b80830191505092915050565b7f4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000600082015250565b600061152560178361144a565b9150611530826114ef565b602082019050919050565b6000602082019050818103600083015261155481611518565b9050919050565b60008235600160600383360303811261157757611576611358565b5b8083019150509291505056fea264697066735822122020c1bc9aacf8e4a6507193432a895a8e77094f45a1395583f07b24e860ef06cd64736f6c634300080c0033`,Su=class extends I{constructor({blockNumber:e,chain:t,contract:n}){super(`Chain "${t.name}" does not support contract "${n.name}".`,{metaMessages:[`This could be due to any of the following:`,...e&&n.blockCreated&&n.blockCreated>e?[`- The contract "${n.name}" was not deployed until block ${n.blockCreated} (current block ${e}).`]:[`- The chain does not have the contract "${n.name}" configured.`]],name:`ChainDoesNotSupportContract`})}},Cu=class extends I{constructor({chain:e,currentChainId:t}){super(`The current chain of the wallet (id: ${t}) does not match the target chain for the transaction (id: ${e.id} – ${e.name}).`,{metaMessages:[`Current Chain ID: ${t}`,`Expected Chain ID: ${e.id} – ${e.name}`],name:`ChainMismatchError`})}},wu=class extends I{constructor(){super([`No chain was provided to the request.`,"Please provide a chain with the `chain` argument on the Action, or by supplying a `chain` to WalletClient."].join(` -`),{name:`ChainNotFoundError`})}},Tu=class extends I{constructor(){super(`No chain was provided to the Client.`,{name:`ClientChainNotConfiguredError`})}},Eu=class extends I{constructor({chainId:e}){super(typeof e==`number`?`Chain ID "${e}" is invalid.`:`Chain ID is invalid.`,{name:`InvalidChainIdError`})}},Du=`/docs/contract/encodeDeployData`;function Ou(e){let{abi:t,args:n,bytecode:r}=e;if(!n||n.length===0)return r;let i=t.find(e=>`type`in e&&e.type===`constructor`);if(!i)throw new Er({docsPath:Du});if(!(`inputs`in i)||!i.inputs||i.inputs.length===0)throw new Dr({docsPath:Du});return oa([r,ma(i.inputs,n)])}function ku({blockNumber:e,chain:t,contract:n}){let r=t?.contracts?.[n];if(!r)throw new Su({chain:t,contract:{name:n}});if(e&&r.blockCreated&&r.blockCreated>e)throw new Su({blockNumber:e,chain:t,contract:{name:n,blockCreated:r.blockCreated}});return r.address}function Au(e,{docsPath:t,...n}){return new ko((()=>{let t=Ws(e,n);return t instanceof Us?e:t})(),{docsPath:t,...n})}function ju(){let e=()=>void 0,t=()=>void 0;return{promise:new Promise((n,r)=>{e=n,t=r}),resolve:e,reject:t}}var Mu=new Map;function Nu({fn:e,id:t,shouldSplitBatch:n,wait:r=0,sort:i}){let a=async()=>{let t=c();o();let n=t.map(({args:e})=>e);n.length!==0&&e(n).then(e=>{i&&Array.isArray(e)&&e.sort(i);for(let n=0;n{for(let n=0;nMu.delete(t),s=()=>c().map(({args:e})=>e),c=()=>Mu.get(t)||[],l=e=>Mu.set(t,[...c(),e]);return{flush:o,async schedule(e){let{promise:t,resolve:i,reject:o}=ju();return n?.([...s(),e])&&a(),c().length>0?(l({args:e,resolve:i,reject:o}),t):(l({args:e,resolve:i,reject:o}),setTimeout(a,r),t)}}}async function Pu(e,t){let{account:n=e.account,authorizationList:r,batch:i=!!e.batch?.multicall,blockNumber:a,blockTag:o=e.experimental_blockTag??`latest`,accessList:s,blobs:c,blockOverrides:l,code:u,data:d,factory:f,factoryData:p,gas:m,gasPrice:h,maxFeePerBlobGas:g,maxFeePerGas:_,maxPriorityFeePerGas:v,nonce:y,to:b,value:x,stateOverride:S,...ee}=t,C=n?B(n):void 0;if(u&&(f||p))throw new I("Cannot provide both `code` & `factory`/`factoryData` as parameters.");if(u&&b)throw new I("Cannot provide both `code` & `to` as parameters.");let te=u&&d,ne=f&&p&&b&&d,w=te||ne,re=te?Lu({code:u,data:d}):ne?Ru({data:d,factory:f,factoryData:p,to:b}):d;try{ec(t);let n=(typeof a==`bigint`?L(a):void 0)||o,u=l?cu(l):void 0,d=Qs(S),f=e.chain?.formatters?.transactionRequest?.format,p=(f||Js)({...Ks(ee,{format:f}),accessList:s,account:C,authorizationList:r,blobs:c,data:re,gas:m,gasPrice:h,maxFeePerBlobGas:g,maxFeePerGas:_,maxPriorityFeePerGas:v,nonce:y,to:w?void 0:b,value:x},`call`);if(i&&Fu({request:p})&&!d&&!u)try{return await Iu(e,{...p,blockNumber:a,blockTag:o})}catch(e){if(!(e instanceof Tu)&&!(e instanceof Su))throw e}let te=(()=>{let e=[p,n];return d&&u?[...e,d,u]:d?[...e,d]:u?[...e,{},u]:e})(),ne=await e.request({method:`eth_call`,params:te});return ne===`0x`?{data:void 0}:{data:ne}}catch(n){let r=zu(n),{offchainLookup:i,offchainLookupSignature:a}=await bs(async()=>{let{offchainLookup:e,offchainLookupSignature:t}=await import(`./ccip-CrugWtXU.js`);return{offchainLookup:e,offchainLookupSignature:t}},[]);if(e.ccipRead!==!1&&r?.slice(0,10)===a&&b)return{data:await i(e,{data:r,to:b})};throw w&&r?.slice(0,10)===`0x101bb98d`?new No({factory:f}):Au(n,{...t,account:C,chain:e.chain})}}function Fu({request:e}){let{data:t,to:n,...r}=e;return!(!t||t.startsWith(`0x82ad56cb`)||!n||Object.values(r).filter(e=>e!==void 0).length>0)}async function Iu(e,t){let{batchSize:n=1024,deployless:r=!1,wait:i=0}=typeof e.batch?.multicall==`object`?e.batch.multicall:{},{blockNumber:a,blockTag:o=e.experimental_blockTag??`latest`,data:s,to:c}=t,l=(()=>{if(r)return null;if(t.multicallAddress)return t.multicallAddress;if(e.chain)return ku({blockNumber:a,chain:e.chain,contract:`multicall3`});throw new Tu})(),u=(typeof a==`bigint`?L(a):void 0)||o,{schedule:d}=Nu({id:`${e.uid}.${u}`,wait:i,shouldSplitBatch(e){return e.reduce((e,{data:t})=>e+(t.length-2),0)>n*2},fn:async t=>{let n=t.map(e=>({allowFailure:!0,callData:e.data,target:e.to})),r=La({abi:lu,args:[n],functionName:`aggregate3`}),i=await e.request({method:`eth_call`,params:[{...l===null?{data:Lu({code:xu,data:r})}:{to:l,data:r}},u]});return cl({abi:lu,args:[n],functionName:`aggregate3`,data:i||`0x`})}}),[{returnData:f,success:p}]=await d({data:s,to:c});if(!p)throw new Po({data:f});return f===`0x`?{data:void 0}:{data:f}}function Lu(e){let{code:t,data:n}=e;return Ou({abi:_r([`constructor(bytes, bytes)`]),bytecode:vu,args:[t,n]})}function Ru(e){let{data:t,factory:n,factoryData:r,to:i}=e;return Ou({abi:_r([`constructor(address, bytes, address, bytes)`]),bytecode:yu,args:[i,t,n,r]})}function zu(e){if(!(e instanceof I))return;let t=e.walk();return typeof t?.data==`object`?t.data?.data:t.data}async function Bu(e,t){let{abi:n,address:r,args:i,functionName:a,...o}=t,s=La({abi:n,args:i,functionName:a});try{let{data:t}=await F(e,Pu,`call`)({...o,data:s,to:r});return cl({abi:n,args:i,functionName:a,data:t||`0x`})}catch(e){throw hs(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/readContract`,functionName:a})}}async function Vu(e,t){let{abi:n,address:r,args:i,functionName:a,dataSuffix:o=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,...s}=t,c=s.account?B(s.account):e.account,l=La({abi:n,args:i,functionName:a});try{let{data:u}=await F(e,Pu,`call`)({batch:!1,data:`${l}${o?o.replace(`0x`,``):``}`,to:r,...s,account:c});return{result:cl({abi:n,args:i,functionName:a,data:u||`0x`}),request:{abi:n.filter(e=>`name`in e&&e.name===t.functionName),address:r,args:i,dataSuffix:o,functionName:a,...s,account:c}}}catch(e){throw hs(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/simulateContract`,functionName:a,sender:c?.address})}}var Hu=new Map,Uu=new Map,Wu=0;function Gu(e,t,n){let r=++Wu,i=()=>Hu.get(e)||[],a=()=>{let t=i();Hu.set(e,t.filter(e=>e.id!==r))},o=()=>{let t=i();if(!t.some(e=>e.id===r))return;let n=Uu.get(e);if(t.length===1&&n){let e=n();e instanceof Promise&&e.catch(()=>{})}a()},s=i();if(Hu.set(e,[...s,{id:r,fns:t}]),s&&s.length>0)return o;let c={};for(let e in t)c[e]=((...t)=>{let n=i();if(n.length!==0)for(let r of n)r.fns[e]?.(...t)});let l=n(c);return typeof l==`function`&&Uu.set(e,l),o}async function X(e){return new Promise(t=>setTimeout(t,e))}function Ku(e,{emitOnBegin:t,initialWaitTime:n,interval:r}){let i=!0,a=()=>i=!1;return(async()=>{let o;t&&(o=await e({unpoll:a})),await X(await n?.(o)??r);let s=async()=>{i&&(await e({unpoll:a}),await X(r),s())};s()})(),a}var qu=new Map,Ju=new Map;function Yu(e){let t=(e,t)=>({clear:()=>t.delete(e),get:()=>t.get(e),set:n=>t.set(e,n)}),n=t(e,qu),r=t(e,Ju);return{clear:()=>{n.clear(),r.clear()},promise:n,response:r}}async function Xu(e,{cacheKey:t,cacheTime:n=1/0}){let r=Yu(t),i=r.response.get();if(i&&n>0&&Date.now()-i.created.getTime()`blockNumber.${e}`;async function Qu(e,{cacheTime:t=e.cacheTime}={}){let n=await Xu(()=>e.request({method:`eth_blockNumber`}),{cacheKey:Zu(e.uid),cacheTime:t});return BigInt(n)}async function $u(e,{filter:t}){let n=`strict`in t&&t.strict,r=await t.request({method:`eth_getFilterChanges`,params:[t.id]});if(typeof r[0]==`string`)return r;let i=r.map(e=>$c(e));return!(`abi`in t)||!t.abi?i:rl({abi:t.abi,logs:i,strict:n})}async function ed(e,{filter:t}){return t.request({method:`eth_uninstallFilter`,params:[t.id]})}function td(e,t){let{abi:n,address:r,args:i,batch:a=!0,eventName:o,fromBlock:s,onError:c,onLogs:l,poll:u,pollingInterval:d=e.pollingInterval,strict:f}=t;return(u===void 0?typeof s==`bigint`||!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):u)?(()=>{let t=f??!1;return Gu(V([`watchContractEvent`,r,i,a,e.uid,o,d,t,s]),{onLogs:l,onError:c},c=>{let l;s!==void 0&&(l=s-1n);let u,f=!1,p=Ku(async()=>{if(!f){try{u=await F(e,Pa,`createContractEventFilter`)({abi:n,address:r,args:i,eventName:o,strict:t,fromBlock:s})}catch{}f=!0;return}try{let s;if(u)s=await F(e,$u,`getFilterChanges`)({filter:u});else{let a=await F(e,Qu,`getBlockNumber`)({});s=l&&l{u&&await F(e,ed,`uninstallFilter`)({filter:u}),p()}})})():(()=>{let t=f??!1,s=V([`watchContractEvent`,r,i,a,e.uid,o,d,t]),u=!0,p=()=>u=!1;return Gu(s,{onLogs:l,onError:c},t=>((async()=>{try{let a=(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})(),s=o?ja({abi:n,eventName:o,args:i}):[],{unsubscribe:c}=await a.subscribe({params:[`logs`,{address:r,topics:s}],onData(e){if(!u)return;let r=e.result;try{let{eventName:e,args:i}=tl({abi:n,data:r.data,topics:r.topics,strict:f}),a=$c(r,{args:i,eventName:e});t.onLogs([a])}catch(e){let n,i;if(e instanceof Wr||e instanceof Gr){if(f)return;n=e.abiItem.name,i=e.abiItem.inputs?.some(e=>!(`name`in e&&e.name))}let a=$c(r,{args:i?[]:{},eventName:n});t.onLogs([a])}},onError(e){t.onError?.(e)}});p=c,u||p()}catch(e){c?.(e)}})(),()=>p()))})()}var nd=class extends I{constructor({docsPath:e}={}){super([`Could not find an Account to execute with this Action.`,"Please provide an Account with the `account` argument on the Action, or by supplying an `account` to the Client."].join(` -`),{docsPath:e,docsSlug:`account`,name:`AccountNotFoundError`})}},rd=class extends I{constructor({docsPath:e,metaMessages:t,type:n}){super(`Account type "${n}" is not supported.`,{docsPath:e,metaMessages:t,name:`AccountTypeNotSupportedError`})}};function id({chain:e,currentChainId:t}){if(!e)throw new wu;if(t!==e.id)throw new Cu({chain:e,currentChainId:t})}async function ad(e,{serializedTransaction:t}){return e.request({method:`eth_sendRawTransaction`,params:[t]},{retryCount:0})}var od=new Zi(128);async function sd(e,t){let{account:n=e.account,assertChainId:r=!0,chain:i=e.chain,accessList:a,authorizationList:o,blobs:s,data:c,dataSuffix:l=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,type:g,value:_,...v}=t;if(n===void 0)throw new nd({docsPath:`/docs/actions/wallet/sendTransaction`});let y=n?B(n):null;try{ec(t);let n=await(async()=>{if(t.to)return t.to;if(t.to!==null&&o&&o.length>0)return await As({authorization:o[0]}).catch(()=>{throw new I("`to` is required. Could not infer from `authorizationList`.")})})();if(y?.type===`json-rpc`||y===null){let t;i!==null&&(t=await F(e,Wc,`getChainId`)({}),r&&id({currentChainId:t,chain:i}));let b=e.chain?.formatters?.transactionRequest?.format,x=(b||Js)({...Ks(v,{format:b}),accessList:a,account:y,authorizationList:o,blobs:s,chainId:t,data:l?ia([c??`0x`,l]):c,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,to:n,type:g,value:_},`sendTransaction`),S=od.get(e.uid),ee=S?`wallet_sendTransaction`:`eth_sendTransaction`;try{return await e.request({method:ee,params:[x]},{retryCount:0})}catch(t){if(S===!1)throw t;let n=t;if(n.name===`InvalidInputRpcError`||n.name===`InvalidParamsRpcError`||n.name===`MethodNotFoundRpcError`||n.name===`MethodNotSupportedRpcError`)return await e.request({method:`wallet_sendTransaction`,params:[x]},{retryCount:0}).then(t=>(od.set(e.uid,!0),t)).catch(t=>{let r=t;throw r.name===`MethodNotFoundRpcError`||r.name===`MethodNotSupportedRpcError`?(od.set(e.uid,!1),n):r});throw n}}if(y?.type===`local`){let t=await F(e,Yc,`prepareTransactionRequest`)({account:y,accessList:a,authorizationList:o,blobs:s,chain:i,data:l?ia([c??`0x`,l]):c,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,nonceManager:y.nonceManager,parameters:[...Kc,`sidecars`],type:g,value:_,...v,to:n}),r=i?.serializers?.transaction,b=await y.signTransaction(t,{serializer:r});return await F(e,ad,`sendRawTransaction`)({serializedTransaction:b})}throw y?.type===`smart`?new rd({metaMessages:["Consider using the `sendUserOperation` Action instead."],docsPath:`/docs/actions/bundler/sendUserOperation`,type:`smart`}):new rd({docsPath:`/docs/actions/wallet/sendTransaction`,type:y?.type})}catch(e){throw e instanceof rd?e:Uc(e,{...t,account:y,chain:t.chain||void 0})}}async function cd(e,t){return cd.internal(e,sd,`sendTransaction`,t)}(function(e){async function t(e,t,n,r){let{abi:i,account:a=e.account,address:o,args:s,functionName:c,...l}=r;if(a===void 0)throw new nd({docsPath:`/docs/contract/writeContract`});let u=a?B(a):null,d=La({abi:i,args:s,functionName:c});try{return await F(e,t,n)({data:d,to:o,account:u,...l})}catch(e){throw hs(e,{abi:i,address:o,args:s,docsPath:`/docs/contract/writeContract`,functionName:c,sender:u?.address})}}e.internal=t})(cd||={});var ld=class extends I{constructor(e){super(`Call bundle failed with status: ${e.statusCode}`,{name:`BundleFailedError`}),Object.defineProperty(this,`result`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.result=e}};function ud(e,{delay:t=100,retryCount:n=2,shouldRetry:r=()=>!0}={}){return new Promise((i,a)=>{let o=async({count:s=0}={})=>{let c=async({error:e})=>{let n=typeof t==`function`?t({count:s,error:e}):t;n&&await X(n),o({count:s+1})};try{i(await e())}catch(e){if(s$c(e)):null,to:e.to?e.to:null,transactionIndex:e.transactionIndex?di(e.transactionIndex):null,status:e.status?dd[e.status]:null,type:e.type?ac[e.type]||e.type:null};return e.blobGasPrice&&(n.blobGasPrice=BigInt(e.blobGasPrice)),e.blobGasUsed&&(n.blobGasUsed=BigInt(e.blobGasUsed)),n}var pd=`0x5792579257925792579257925792579257925792579257925792579257925792`,md=L(0,{size:32});async function hd(e,t){let{account:n=e.account,chain:r=e.chain,experimental_fallback:i,experimental_fallbackDelay:a=32,forceAtomic:o=!1,id:s,version:c=`2.0.0`}=t,l=n?B(n):null,u=t.capabilities;e.dataSuffix&&!t.capabilities?.dataSuffix&&(u=typeof e.dataSuffix==`string`?{...t.capabilities,dataSuffix:{value:e.dataSuffix,optional:!0}}:{...t.capabilities,dataSuffix:{value:e.dataSuffix.value,...e.dataSuffix.required?{}:{optional:!0}}});let d=t.calls.map(e=>{let t=e,n=t.abi?La({abi:t.abi,functionName:t.functionName,args:t.args}):t.data;return{data:t.dataSuffix&&n?ia([n,t.dataSuffix]):n,to:t.to,value:t.value?L(t.value):void 0}});try{let t=await e.request({method:`wallet_sendCalls`,params:[{atomicRequired:o,calls:d,capabilities:u,chainId:L(r.id),from:l?.address,id:s,version:c}]},{retryCount:0});return typeof t==`string`?{id:t}:t}catch(n){let s=n;if(i&&(s.name===`MethodNotFoundRpcError`||s.name===`MethodNotSupportedRpcError`||s.name===`UnknownRpcError`||s.details.toLowerCase().includes(`does not exist / is not available`)||s.details.toLowerCase().includes(`missing or invalid. request()`)||s.details.toLowerCase().includes(`did not match any variant of untagged enum`)||s.details.toLowerCase().includes(`account upgraded to unsupported contract`)||s.details.toLowerCase().includes(`eip-7702 not supported`)||s.details.toLowerCase().includes(`unsupported wc_ method`)||s.details.toLowerCase().includes(`feature toggled misconfigured`)||s.details.toLowerCase().includes(`jsonrpcengine: response has no error or result for request`))){if(u&&Object.values(u).some(e=>!e.optional)){let e="non-optional `capabilities` are not supported on fallback to `eth_sendTransaction`.";throw new as(new I(e,{details:e}))}if(o&&d.length>1){let e="`forceAtomic` is not supported on fallback to `eth_sendTransaction`.";throw new ds(new I(e,{details:e}))}let t=[];for(let n of d){let i=sd(e,{account:l,chain:r,data:n.data,to:n.to,value:n.value?li(n.value):void 0});t.push(i),a>0&&await new Promise(e=>setTimeout(e,a))}let n=await Promise.allSettled(t);if(n.every(e=>e.status===`rejected`))throw n[0].reason;return{id:ia([...n.map(e=>e.status===`fulfilled`?e.value:md),L(r.id,{size:32}),pd])}}throw Uc(n,{...t,account:l,chain:t.chain})}}async function gd(e,t){async function n(t){if(t.endsWith(`5792579257925792579257925792579257925792579257925792579257925792`)){let n=si(da(t,-64,-32)),r=da(t,0,-64).slice(2).match(/.{1,64}/g),i=await Promise.all(r.map(t=>md.slice(2)===t?void 0:e.request({method:`eth_getTransactionReceipt`,params:[`0x${t}`]},{dedupe:!0}))),a=i.some(e=>e===null)?100:i.every(e=>e?.status===`0x1`)?200:i.every(e=>e?.status===`0x0`)?500:600;return{atomic:!1,chainId:di(n),receipts:i.filter(Boolean),status:a,version:`2.0.0`}}return e.request({method:`wallet_getCallsStatus`,params:[t]})}let{atomic:r=!1,chainId:i,receipts:a,version:o=`2.0.0`,...s}=await n(t.id),[c,l]=(()=>{let e=s.status;return e>=100&&e<200?[`pending`,e]:e>=200&&e<300?[`success`,e]:e>=300&&e<700?[`failure`,e]:e===`CONFIRMED`?[`success`,200]:e===`PENDING`?[`pending`,100]:[void 0,e]})();return{...s,atomic:r,chainId:i?di(i):void 0,receipts:a?.map(e=>({...e,blockNumber:li(e.blockNumber),gasUsed:li(e.gasUsed),status:dd[e.status]}))??[],statusCode:l,status:c,version:o}}async function _d(e,t){let{id:n,pollingInterval:r=e.pollingInterval,status:i=({statusCode:e})=>e===200||e>=300,retryCount:a=4,retryDelay:o=({count:e})=>~~(1<{let s=Ku(async()=>{let r=e=>{clearTimeout(p),s(),e(),m()};try{let s=await ud(async()=>{let t=await F(e,gd,`getCallsStatus`)({id:n});if(c&&t.status===`failure`)throw new ld(t);return t},{retryCount:a,delay:o});if(!i(s))return;r(()=>t.resolve(s))}catch(e){r(()=>t.reject(e))}},{interval:r,emitOnBegin:!0});return s});return p=s?setTimeout(()=>{m(),clearTimeout(p),f(new vd({id:n}))},s):void 0,await u}var vd=class extends I{constructor({id:e}){super(`Timed out while waiting for call bundle with id "${e}" to be confirmed.`,{name:`WaitForCallsStatusTimeoutError`})}},yd=256,bd=yd,Z;function xd(e=11){if(!Z||bd+e>yd*2){Z=``,bd=0;for(let e=0;e{let n=t(e);for(let e in _)delete n[e];let r={...e,...n};return Object.assign(r,{extend:v(r)})}}return Object.assign(_,{extend:v(_)})}function Cd(e){if(!(e instanceof I))return!1;let t=e.walk(e=>e instanceof jo);return t instanceof jo?t.data?.errorName===`HttpError`||t.data?.errorName===`ResolverError`||t.data?.errorName===`ResolverNotContract`||t.data?.errorName===`ResolverNotFound`||t.data?.errorName===`ReverseAddressMismatch`||t.data?.errorName===`UnsupportedResolverProfile`:!1}function wd(e){let{abi:t,data:n}=e,r=sa(n,0,4),i=t.find(e=>e.type===`function`&&r===Ea(vr(e)));if(!i)throw new Vr(r,{docsPath:`/docs/contract/decodeFunctionData`});return{functionName:i.name,args:`inputs`in i&&i.inputs&&i.inputs.length>0?Xa(i.inputs,sa(n,4)):void 0}}var Td=`/docs/contract/encodeErrorResult`;function Ed(e){let{abi:t,errorName:n,args:r}=e,i=t[0];if(n){let e=Da({abi:t,args:r,name:n});if(!e)throw new Pr(n,{docsPath:Td});i=e}if(i.type!==`error`)throw new Pr(void 0,{docsPath:Td});let a=Ea(vr(i)),o=`0x`;if(r&&r.length>0){if(!i.inputs)throw new Nr(i.name,{docsPath:Td});o=ma(i.inputs,r)}return oa([a,o])}var Dd=`/docs/contract/encodeFunctionResult`;function Od(e){let{abi:t,functionName:n,result:r}=e,i=t[0];if(n){let e=Da({abi:t,name:n});if(!e)throw new zr(n,{docsPath:Dd});i=e}if(i.type!==`function`)throw new zr(void 0,{docsPath:Dd});if(!i.outputs)throw new Br(i.name,{docsPath:Dd});let a=(()=>{if(i.outputs.length===0)return[];if(i.outputs.length===1)return[r];if(Array.isArray(r))return r;throw new Jr(r)})();return ma(i.outputs,a)}var kd=`x-batch-gateway:true`;async function Ad(e){let{data:t,ccipRequest:n}=e,{args:[r]}=wd({abi:uu,data:t}),i=[],a=[];return await Promise.all(r.map(async(e,t)=>{try{a[t]=e.urls.includes(`x-batch-gateway:true`)?await Ad({data:e.data,ccipRequest:n}):await n(e),i[t]=!1}catch(e){i[t]=!0,a[t]=jd(e)}})),Od({abi:uu,functionName:`query`,result:[i,a]})}function jd(e){return e.name===`HttpRequestError`&&e.status?Ed({abi:uu,errorName:`HttpError`,args:[e.status,e.shortMessage]}):Ed({abi:[za],errorName:`Error`,args:[`shortMessage`in e?e.shortMessage:e.message]})}function Md(e){if(e.length!==66||e.indexOf(`[`)!==0||e.indexOf(`]`)!==65)return null;let t=`0x${e.slice(1,65)}`;return xr(t)?t:null}function Nd(e){let t=new Uint8Array(32).fill(0);if(!e)return hi(t);let n=e.split(`.`);for(let e=n.length-1;e>=0;--e){let r=Md(n[e]),i=r?yi(r):z(Ti(n[e]),`bytes`);t=z(ia([t,i]),`bytes`)}return hi(t)}function Pd(e){return`[${e.slice(2)}]`}function Fd(e){let t=new Uint8Array(32).fill(0);return e?Md(e)||z(Ti(e)):hi(t)}function Id(e){let t=e.replace(/^\.|\.$/gm,``);if(t.length===0)return new Uint8Array(1);let n=new Uint8Array(Ti(t).byteLength+2),r=0,i=t.split(`.`);for(let e=0;e255&&(t=Ti(Pd(Fd(i[e])))),n[r]=t.length,n.set(t,r+1),r+=t.length+1}return n.byteLength===r+1?n:n.slice(0,r+1)}async function Ld(e,t){let{blockNumber:n,blockTag:r,coinType:i,name:a,gatewayUrls:o,strict:s}=t,{chain:c}=e,l=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw Error(`client chain not configured. universalResolverAddress is required.`);return ku({blockNumber:n,chain:c,contract:`ensUniversalResolver`})})(),u=c?.ensTlds;if(u&&!u.some(e=>a.endsWith(e)))return null;let d=i==null?[Nd(a)]:[Nd(a),BigInt(i)];try{let t=La({abi:hu,functionName:`addr`,args:d}),i={address:l,abi:fu,functionName:`resolveWithGateways`,args:[pi(Id(a)),t,o??[`x-batch-gateway:true`]],blockNumber:n,blockTag:r},s=await F(e,Bu,`readContract`)(i);if(s[0]===`0x`)return null;let c=cl({abi:hu,args:d,functionName:`addr`,data:s[0]});return c===`0x`||si(c)===`0x00`?null:c}catch(e){if(s)throw e;if(Cd(e))return null;throw e}}var Rd=class extends I{constructor({data:e}){super(`Unable to extract image from metadata. The metadata may be malformed or invalid.`,{metaMessages:["- Metadata must be a JSON object with at least an `image`, `image_url` or `image_data` property.",``,`Provided data: ${JSON.stringify(e)}`],name:`EnsAvatarInvalidMetadataError`})}},zd=class extends I{constructor({reason:e}){super(`ENS NFT avatar URI is invalid. ${e}`,{name:`EnsAvatarInvalidNftUriError`})}},Bd=class extends I{constructor({uri:e}){super(`Unable to resolve ENS avatar URI "${e}". The URI may be malformed, invalid, or does not respond with a valid image.`,{name:`EnsAvatarUriResolutionError`})}},Vd=class extends I{constructor({namespace:e}){super(`ENS NFT avatar namespace "${e}" is not supported. Must be "erc721" or "erc1155".`,{name:`EnsAvatarUnsupportedNamespaceError`})}},Hd=/(?https?:\/\/[^/]*|ipfs:\/|ipns:\/|ar:\/)?(?\/)?(?ipfs\/|ipns\/)?(?[\w\-.]+)(?\/.*)?/,Ud=/^(Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,})(\/(?[\w\-.]+))?(?\/.*)?$/,Wd=/^data:([a-zA-Z\-/+]*);base64,([^"].*)/,Gd=/^data:([a-zA-Z\-/+]*)?(;[a-zA-Z0-9].*?)?(,)/;async function Kd(e){try{let t=await fetch(e,{method:`HEAD`});return t.status===200?t.headers.get(`content-type`)?.startsWith(`image/`):!1}catch(t){return typeof t==`object`&&t.response!==void 0||!Object.hasOwn(globalThis,`Image`)?!1:new Promise(t=>{let n=new Image;n.onload=()=>{t(!0)},n.onerror=()=>{t(!1)},n.src=e})}}function qd(e,t){return e?e.endsWith(`/`)?e.slice(0,-1):e:t}function Jd({uri:e,gatewayUrls:t}){let n=Wd.test(e);if(n)return{uri:e,isOnChain:!0,isEncoded:n};let r=qd(t?.ipfs,`https://ipfs.io`),i=qd(t?.arweave,`https://arweave.net`),{protocol:a,subpath:o,target:s,subtarget:c=``}=e.match(Hd)?.groups||{},l=a===`ipns:/`||o===`ipns/`,u=a===`ipfs:/`||o===`ipfs/`||Ud.test(e);if(e.startsWith(`http`)&&!l&&!u){let n=e;return t?.arweave&&(n=e.replace(/https:\/\/arweave.net/g,t?.arweave)),{uri:n,isOnChain:!1,isEncoded:!1}}if((l||u)&&s)return{uri:`${r}/${l?`ipns`:`ipfs`}/${s}${c}`,isOnChain:!1,isEncoded:!1};if(a===`ar:/`&&s)return{uri:`${i}/${s}${c||``}`,isOnChain:!1,isEncoded:!1};let d=e.replace(Gd,``);if(d.startsWith(`e.json()))})}catch{throw new Bd({uri:t})}}async function Zd({gatewayUrls:e,uri:t}){let{uri:n,isOnChain:r}=Jd({uri:t,gatewayUrls:e});if(r||await Kd(n))return n;throw new Bd({uri:t})}function Qd(e){let t=e;t.startsWith(`did:nft:`)&&(t=t.replace(`did:nft:`,``).replace(/_/g,`/`));let[n,r,i]=t.split(`/`),[a,o]=n.split(`:`),[s,c]=r.split(`:`);if(!a||a.toLowerCase()!==`eip155`)throw new zd({reason:`Only EIP-155 supported`});if(!o)throw new zd({reason:`Chain ID not found`});if(!c)throw new zd({reason:`Contract address not found`});if(!i)throw new zd({reason:`Token ID not found`});if(!s)throw new zd({reason:`ERC namespace not found`});return{chainID:Number.parseInt(o,10),namespace:s.toLowerCase(),contractAddress:c,tokenID:i}}async function $d(e,{nft:t}){if(t.namespace===`erc721`)return Bu(e,{address:t.contractAddress,abi:[{name:`tokenURI`,type:`function`,stateMutability:`view`,inputs:[{name:`tokenId`,type:`uint256`}],outputs:[{name:``,type:`string`}]}],functionName:`tokenURI`,args:[BigInt(t.tokenID)]});if(t.namespace===`erc1155`)return Bu(e,{address:t.contractAddress,abi:[{name:`uri`,type:`function`,stateMutability:`view`,inputs:[{name:`_id`,type:`uint256`}],outputs:[{name:``,type:`string`}]}],functionName:`uri`,args:[BigInt(t.tokenID)]});throw new Vd({namespace:t.namespace})}async function ef(e,{gatewayUrls:t,record:n}){return/eip155:/i.test(n)?tf(e,{gatewayUrls:t,record:n}):Zd({uri:n,gatewayUrls:t})}async function tf(e,{gatewayUrls:t,record:n}){let r=Qd(n),{uri:i,isOnChain:a,isEncoded:o}=Jd({uri:await $d(e,{nft:r}),gatewayUrls:t});if(a&&(i.includes(`data:application/json;base64,`)||i.startsWith(`{`))){let e=o?atob(i.replace(`data:application/json;base64,`,``)):i;return Zd({uri:Yd(JSON.parse(e)),gatewayUrls:t})}let s=r.tokenID;return r.namespace===`erc1155`&&(s=s.replace(`0x`,``).padStart(64,`0`)),Xd({gatewayUrls:t,uri:i.replace(/(?:0x)?{id}/,s)})}async function nf(e,t){let{blockNumber:n,blockTag:r,key:i,name:a,gatewayUrls:o,strict:s}=t,{chain:c}=e,l=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw Error(`client chain not configured. universalResolverAddress is required.`);return ku({blockNumber:n,chain:c,contract:`ensUniversalResolver`})})(),u=c?.ensTlds;if(u&&!u.some(e=>a.endsWith(e)))return null;try{let t={address:l,abi:fu,args:[pi(Id(a)),La({abi:mu,functionName:`text`,args:[Nd(a),i]}),o??[`x-batch-gateway:true`]],functionName:`resolveWithGateways`,blockNumber:n,blockTag:r},s=await F(e,Bu,`readContract`)(t);if(s[0]===`0x`)return null;let c=cl({abi:mu,functionName:`text`,data:s[0]});return c===``?null:c}catch(e){if(s)throw e;if(Cd(e))return null;throw e}}async function rf(e,{blockNumber:t,blockTag:n,assetGatewayUrls:r,name:i,gatewayUrls:a,strict:o,universalResolverAddress:s}){let c=await F(e,nf,`getEnsText`)({blockNumber:t,blockTag:n,key:`avatar`,name:i,universalResolverAddress:s,gatewayUrls:a,strict:o});if(!c)return null;try{return await ef(e,{record:c,gatewayUrls:r})}catch{return null}}async function af(e,t){let{address:n,blockNumber:r,blockTag:i,coinType:a=60n,gatewayUrls:o,strict:s}=t,{chain:c}=e,l=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw Error(`client chain not configured. universalResolverAddress is required.`);return ku({blockNumber:r,chain:c,contract:`ensUniversalResolver`})})();try{let t={address:l,abi:pu,args:[n,a,o??[`x-batch-gateway:true`]],functionName:`reverseWithGateways`,blockNumber:r,blockTag:i},[s]=await F(e,Bu,`readContract`)(t);return s||null}catch(e){if(s)throw e;if(Cd(e))return null;throw e}}async function of(e,t){let{blockNumber:n,blockTag:r,name:i}=t,{chain:a}=e,o=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!a)throw Error(`client chain not configured. universalResolverAddress is required.`);return ku({blockNumber:n,chain:a,contract:`ensUniversalResolver`})})(),s=a?.ensTlds;if(s&&!s.some(e=>i.endsWith(e)))throw Error(`${i} is not a valid ENS TLD (${s?.join(`, `)}) for chain "${a.name}" (id: ${a.id}).`);let[c]=await F(e,Bu,`readContract`)({address:o,abi:[{inputs:[{type:`bytes`}],name:`findResolver`,outputs:[{type:`address`},{type:`bytes32`},{type:`uint256`}],stateMutability:`view`,type:`function`}],functionName:`findResolver`,args:[pi(Id(i))],blockNumber:n,blockTag:r});return c}async function sf(e,t){let{account:n=e.account,blockNumber:r,blockTag:i=`latest`,blobs:a,data:o,gas:s,gasPrice:c,maxFeePerBlobGas:l,maxFeePerGas:u,maxPriorityFeePerGas:d,to:f,value:p,...m}=t,h=n?B(n):void 0;try{ec(t);let n=(typeof r==`bigint`?L(r):void 0)||i,g=e.chain?.formatters?.transactionRequest?.format,_=(g||Js)({...Ks(m,{format:g}),account:h,blobs:a,data:o,gas:s,gasPrice:c,maxFeePerBlobGas:l,maxFeePerGas:u,maxPriorityFeePerGas:d,to:f,value:p},`createAccessList`),v=await e.request({method:`eth_createAccessList`,params:[_,n]});return{accessList:v.accessList,gasUsed:BigInt(v.gasUsed)}}catch(n){throw Au(n,{...t,account:h,chain:e.chain})}}async function cf(e){let t=Na(e,{method:`eth_newBlockFilter`}),n=await e.request({method:`eth_newBlockFilter`});return{id:n,request:t(n),type:`block`}}async function lf(e,{address:t,args:n,event:r,events:i,fromBlock:a,strict:o,toBlock:s}={}){let c=i??(r?[r]:void 0),l=Na(e,{method:`eth_newFilter`}),u=[];c&&(u=[c.flatMap(e=>ja({abi:[e],eventName:e.name,args:n}))],r&&(u=u[0]));let d=await e.request({method:`eth_newFilter`,params:[{address:t,fromBlock:typeof a==`bigint`?L(a):a,toBlock:typeof s==`bigint`?L(s):s,...u.length?{topics:u}:{}}]});return{abi:c,args:n,eventName:r?r.name:void 0,fromBlock:a,id:d,request:l(d),strict:!!o,toBlock:s,type:`event`}}async function uf(e){let t=Na(e,{method:`eth_newPendingTransactionFilter`}),n=await e.request({method:`eth_newPendingTransactionFilter`});return{id:n,request:t(n),type:`transaction`}}async function df(e,{address:t,blockNumber:n,blockTag:r=e.experimental_blockTag??`latest`}){if(e.batch?.multicall&&e.chain?.contracts?.multicall3){let i=e.chain.contracts.multicall3.address,a=La({abi:lu,functionName:`getEthBalance`,args:[t]}),{data:o}=await F(e,Pu,`call`)({to:i,data:a,blockNumber:n,blockTag:r});return cl({abi:lu,functionName:`getEthBalance`,args:[t],data:o||`0x`})}let i=typeof n==`bigint`?L(n):void 0,a=await e.request({method:`eth_getBalance`,params:[t,i||r]});return BigInt(a)}async function ff(e){let t=await e.request({method:`eth_blobBaseFee`});return BigInt(t)}async function pf(e,{blockHash:t,blockNumber:n,blockTag:r=`latest`}={}){let i=n===void 0?void 0:L(n),a;return a=t?await e.request({method:`eth_getBlockTransactionCountByHash`,params:[t]},{dedupe:!0}):await e.request({method:`eth_getBlockTransactionCountByNumber`,params:[i||r]},{dedupe:!!i}),di(a)}async function mf(e,{address:t,blockNumber:n,blockTag:r=`latest`}){let i=n===void 0?void 0:L(n),a=await e.request({method:`eth_getCode`,params:[t,i||r]},{dedupe:!!i});if(a!==`0x`)return a}async function hf(e,{address:t,blockNumber:n,blockTag:r=`latest`}){let i=await mf(e,{address:t,...n===void 0?{blockTag:r}:{blockNumber:n}});if(i&&Sr(i)===23&&i.startsWith(`0xef0100`))return ea(sa(i,3,23))}var gf=class extends I{constructor({address:e}){super(`No EIP-712 domain found on contract "${e}".`,{metaMessages:[`Ensure that:`,`- The contract is deployed at the address "${e}".`,"- `eip712Domain()` function exists on the contract.","- `eip712Domain()` function matches signature to ERC-5267 specification."],name:`Eip712DomainNotFoundError`})}};async function _f(e,t){let{address:n,factory:r,factoryData:i}=t;try{let[t,a,o,s,c,l,u]=await F(e,Bu,`readContract`)({abi:vf,address:n,functionName:`eip712Domain`,factory:r,factoryData:i});return{domain:{name:a,version:o,chainId:Number(s),verifyingContract:c,salt:l},extensions:u,fields:t}}catch(e){let t=e;throw t.name===`ContractFunctionExecutionError`&&t.cause.name===`ContractFunctionZeroDataError`?new gf({address:n}):t}}var vf=[{inputs:[],name:`eip712Domain`,outputs:[{name:`fields`,type:`bytes1`},{name:`name`,type:`string`},{name:`version`,type:`string`},{name:`chainId`,type:`uint256`},{name:`verifyingContract`,type:`address`},{name:`salt`,type:`bytes32`},{name:`extensions`,type:`uint256[]`}],stateMutability:`view`,type:`function`}];function yf(e){return{baseFeePerGas:e.baseFeePerGas.map(e=>BigInt(e)),gasUsedRatio:e.gasUsedRatio,oldestBlock:BigInt(e.oldestBlock),reward:e.reward?.map(e=>e.map(e=>BigInt(e)))}}async function bf(e,{blockCount:t,blockNumber:n,blockTag:r=`latest`,rewardPercentiles:i}){let a=typeof n==`bigint`?L(n):void 0;return yf(await e.request({method:`eth_feeHistory`,params:[L(t),a||r,i]},{dedupe:!!a}))}async function xf(e,{filter:t}){let n=t.strict??!1,r=(await t.request({method:`eth_getFilterLogs`,params:[t.id]})).map(e=>$c(e));return t.abi?rl({abi:t.abi,logs:r,strict:n}):r}function Sf(e){let{authorizationList:t}=e;if(t)for(let e of t){let{chainId:t}=e,n=e.address;if(!ra(n))throw new Xi({address:n});if(t<0)throw new Eu({chainId:t})}wf(e)}function Cf(e){let{blobVersionedHashes:t}=e;if(t){if(t.length===0)throw new Lc;for(let e of t){let t=Sr(e),n=di(sa(e,0,1));if(t!==32)throw new Rc({hash:e,size:t});if(n!==1)throw new zc({hash:e,version:n})}}wf(e)}function wf(e){let{chainId:t,maxPriorityFeePerGas:n,maxFeePerGas:r,to:i}=e;if(t<=0)throw new Eu({chainId:t});if(i&&!ra(i))throw new Xi({address:i});if(r&&r>$s)throw new Ns({maxFeePerGas:r});if(n&&r&&n>r)throw new Hs({maxFeePerGas:r,maxPriorityFeePerGas:n})}function Tf(e){let{chainId:t,maxPriorityFeePerGas:n,gasPrice:r,maxFeePerGas:i,to:a}=e;if(t<=0)throw new Eu({chainId:t});if(a&&!ra(a))throw new Xi({address:a});if(n||i)throw new I("`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid EIP-2930 Transaction attribute.");if(r&&r>$s)throw new Ns({maxFeePerGas:r})}function Ef(e){let{chainId:t,maxPriorityFeePerGas:n,gasPrice:r,maxFeePerGas:i,to:a}=e;if(a&&!ra(a))throw new Xi({address:a});if(t!==void 0&&t<=0)throw new Eu({chainId:t});if(n||i)throw new I("`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid Legacy Transaction attribute.");if(r&&r>$s)throw new Ns({maxFeePerGas:r})}function Df(e){if(!e||e.length===0)return[];let t=[];for(let n=0;nhi(e)),n=e.kzg,r=gc({blobs:t,kzg:n});f===void 0&&(f=jc({commitments:r})),p===void 0&&(p=Vc({blobs:t,commitments:r,proofs:_c({blobs:t,commitments:r,kzg:n})}))}let m=Df(u),h=[L(n),i?L(i):`0x`,l?L(l):`0x`,c?L(c):`0x`,r?L(r):`0x`,a??`0x`,o?L(o):`0x`,d??`0x`,m,s?L(s):`0x`,f??[],...Pf(e,t)],g=[],_=[],v=[];if(p)for(let e=0;e{if(t.v>=35n)return(t.v-35n)/2n>0?t.v:27n+(t.v===35n?0n:1n);if(n>0)return BigInt(n*2)+BigInt(35n+t.v-27n);let e=27n+(t.v===27n?0n:1n);if(t.v!==e)throw new yo({v:t.v});return e})(),r=si(t.r),i=si(t.s);l=[...l,L(e),r===`0x00`?`0x`:r,i===`0x00`?`0x`:i]}else n>0&&(l=[...l,L(n),`0x`,`0x`]);return ws(l)}function Pf(e,t){let n=t??e,{v:r,yParity:i}=n;if(n.r===void 0||n.s===void 0||r===void 0&&i===void 0)return[];let a=si(n.r),o=si(n.s);return[typeof i==`number`?i?L(1):`0x`:r===0n?`0x`:r===1n?L(1):r===27n?`0x`:L(1),a===`0x00`?`0x`:a,o===`0x00`?`0x`:o]}function Ff(e){if(!e||e.length===0)return[];let t=[];for(let n of e){let{chainId:e,nonce:r,...i}=n,a=n.address;t.push([e?pi(e):`0x`,a,r?pi(r):`0x`,...Pf({},i)])}return t}async function If({address:e,authorization:t,signature:n}){return Qc(ea(e),await As({authorization:t,signature:n}))}var Lf=new Zi(8192);function Rf(e,{enabled:t=!0,id:n}){if(!t||!n)return e();if(Lf.get(n))return Lf.get(n);let r=e().finally(()=>Lf.delete(n));return Lf.set(n,r),r}function zf(e,t={}){return async(n,r={})=>{let{dedupe:i=!1,methods:a,retryDelay:o=150,retryCount:s=3,uid:c}={...t,...r},{method:l}=n;if(a?.exclude?.includes(l)||a?.include&&!a.include.includes(l))throw new Xo(Error(`method not supported`),{method:l});return Rf(()=>ud(async()=>{try{return await e(n)}catch(e){let t=e;switch(t.code){case Vo.code:throw new Vo(t);case Ho.code:throw new Ho(t);case Uo.code:throw new Uo(t,{method:n.method});case Wo.code:throw new Wo(t);case Go.code:throw new Go(t);case Ko.code:throw new Ko(t);case qo.code:throw new qo(t);case Jo.code:throw new Jo(t);case Yo.code:throw new Yo(t);case Xo.code:throw new Xo(t,{method:n.method});case Zo.code:throw new Zo(t);case Qo.code:throw new Qo(t);case $o.code:throw new $o(t);case es.code:throw new es(t);case ts.code:throw new ts(t);case ns.code:throw new ns(t);case rs.code:throw new rs(t);case is.code:throw new is(t);case as.code:throw new as(t);case os.code:throw new os(t);case ss.code:throw new ss(t);case cs.code:throw new cs(t);case ls.code:throw new ls(t);case us.code:throw new us(t);case ds.code:throw new ds(t);case 5e3:throw new $o(t);case fs.code:throw new fs(t);default:throw e instanceof I?e:new ps(t)}}},{delay:({count:e,error:t})=>{if(t&&t instanceof Fo){let e=t?.headers?.get(`Retry-After`);if(e?.match(/\d/))return Number.parseInt(e,10)*1e3}return~~(1<Bf(e)}),{enabled:i,id:i?Vf(`${c}.${V(n)}`):void 0})}}function Bf(e){return`code`in e&&typeof e.code==`number`?e.code===-1||e.code===Zo.code||e.code===Go.code||e.code===429:e instanceof Fo&&e.status?e.status===403||e.status===408||e.status===413||e.status===429||e.status===500||e.status===502||e.status===503||e.status===504:!0}function Vf(e,t=0){let n=3735928559^t,r=1103547991^t;for(let t=0;t>>16,2246822507),n^=Math.imul(r^r>>>16,3266489909),r=Math.imul(r^r>>>16,2246822507),r^=Math.imul(n^n>>>16,3266489909),(4294967296*(2097151&r)+(n>>>0)).toString(36)}function Hf(e){let t={formatters:void 0,fees:void 0,serializers:void 0,...e};function n(e){return t=>{let r=typeof t==`function`?t(e):t,i={...e,...r};return Object.assign(i,{extend:n(i)})}}return Object.assign(t,{extend:n(t)})}function Uf(e,{errorInstance:t=Error(`timed out`),timeout:n,signal:r}){return new Promise((i,a)=>{(async()=>{let o;try{let s=new AbortController;n>0&&(o=setTimeout(()=>{r?s.abort():a(t)},n)),i(await e({signal:s?.signal||null}))}catch(e){e?.name===`AbortError`&&a(t),a(e)}finally{clearTimeout(o)}})()})}function Wf(){return{current:0,take(){return this.current++},reset(){this.current=0}}}var Gf=Wf();function Kf(e,t={}){let{url:n,headers:r}=qf(e);return{async request(e){let{body:i,fetchFn:a=t.fetchFn??fetch,onRequest:o=t.onRequest,onResponse:s=t.onResponse,timeout:c=t.timeout??1e4}=e,l={...t.fetchOptions??{},...e.fetchOptions??{}},{headers:u,method:d,signal:f}=l;try{let e=await Uf(async({signal:e})=>{let t={...l,body:V(Array.isArray(i)?i.map(e=>({jsonrpc:`2.0`,id:e.id??Gf.take(),...e})):{jsonrpc:`2.0`,id:i.id??Gf.take(),...i}),headers:{...r,"Content-Type":`application/json`,...u},method:d||`POST`,signal:f||(c>0?e:null)},s=new Request(n,t),p=await o?.(s,t)??{...t,url:n};return await a(p.url??n,p)},{errorInstance:new Lo({body:i,url:n}),timeout:c,signal:!0});s&&await s(e);let t;if(e.headers.get(`Content-Type`)?.startsWith(`application/json`))t=await e.json();else{t=await e.text();try{t=JSON.parse(t||`{}`)}catch(n){if(e.ok)throw n;t={error:t}}}if(!e.ok){if(typeof t.error?.code==`number`&&typeof t.error?.message==`string`)return t;throw new Fo({body:i,details:V(t.error)||e.statusText,headers:e.headers,status:e.status,url:n})}return t}catch(e){throw e instanceof Fo||e instanceof Lo?e:new Fo({body:i,cause:e,url:n})}}}}function qf(e){try{let t=new URL(e),n=(()=>{if(t.username){let e=`${decodeURIComponent(t.username)}:${decodeURIComponent(t.password)}`;return t.username=``,t.password=``,{url:t.toString(),headers:{Authorization:`Basic ${btoa(e)}`}}}})();return{url:t.toString(),...n}}catch{return{url:e}}}var Jf=`Ethereum Signed Message: -`;function Yf(e){let t=typeof e==`string`?_i(e):typeof e.raw==`string`?e.raw:hi(e.raw);return ia([_i(`${Jf}${Sr(t)}`),t])}function Xf(e,t){return z(Yf(e),t)}var Zf=class extends I{constructor({domain:e}){super(`Invalid domain "${V(e)}".`,{metaMessages:[`Must be a valid EIP-712 domain.`]})}},Qf=class extends I{constructor({primaryType:e,types:t}){super(`Invalid primary type \`${e}\` must be one of \`${JSON.stringify(Object.keys(t))}\`.`,{docsPath:`/api/glossary/Errors#typeddatainvalidprimarytypeerror`,metaMessages:["Check that the primary type is a key in `types`."]})}},$f=class extends I{constructor({type:e}){super(`Struct type "${e}" is invalid.`,{metaMessages:[`Struct type must not be a Solidity type.`],name:`InvalidStructTypeError`})}};function ep(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{let n={...t};for(let t of e){let{name:e,type:r}=t;r===`address`&&(n[e]=n[e].toLowerCase())}return n};return V({domain:!i.EIP712Domain||!t?{}:a(i.EIP712Domain,t),message:(()=>{if(r!==`EIP712Domain`)return a(i[r],n)})(),primaryType:r,types:i})}function tp(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{for(let n of e){let{name:e,type:r}=n,o=t[e],s=r.match(pa);if(s&&(typeof o==`number`||typeof o==`bigint`)){let[e,t,n]=s;L(o,{signed:t===`int`,size:Number.parseInt(n,10)/8})}if(r===`address`&&typeof o==`string`&&!ra(o))throw new Xi({address:o});let c=r.match(fa);if(c){let[e,t]=c;if(t&&Sr(o)!==Number.parseInt(t,10))throw new Ur({expectedSize:Number.parseInt(t,10),givenSize:Sr(o)})}let l=i[r];l&&(rp(r),a(l,o))}};if(i.EIP712Domain&&t){if(typeof t!=`object`)throw new Zf({domain:t});a(i.EIP712Domain,t)}if(r!==`EIP712Domain`)if(i[r])a(i[r],n);else throw new Qf({primaryType:r,types:i})}function np({domain:e}){return[typeof e?.name==`string`&&{name:`name`,type:`string`},e?.version&&{name:`version`,type:`string`},(typeof e?.chainId==`number`||typeof e?.chainId==`bigint`)&&{name:`chainId`,type:`uint256`},e?.verifyingContract&&{name:`verifyingContract`,type:`address`},e?.salt&&{name:`salt`,type:`bytes32`}].filter(Boolean)}function rp(e){if(e===`address`||e===`bool`||e===`string`||e.startsWith(`bytes`)||e.startsWith(`uint`)||e.startsWith(`int`))throw new $f({type:e})}function ip(e){let{domain:t={},message:n,primaryType:r}=e,i={EIP712Domain:np({domain:t}),...e.types};tp({domain:t,message:n,primaryType:r,types:i});let a=[`0x1901`];return t&&a.push(ap({domain:t,types:i})),r!==`EIP712Domain`&&a.push(op({data:n,primaryType:r,types:i})),z(ia(a))}function ap({domain:e,types:t}){return op({data:e,primaryType:`EIP712Domain`,types:t})}function op({data:e,primaryType:t,types:n}){return z(sp({data:e,primaryType:t,types:n}))}function sp({data:e,primaryType:t,types:n}){let r=[{type:`bytes32`}],i=[cp({primaryType:t,types:n})];for(let a of n[t]){let[t,o]=dp({types:n,name:a.name,type:a.type,value:e[a.name]});r.push(t),i.push(o)}return ma(r,i)}function cp({primaryType:e,types:t}){return z(pi(lp({primaryType:e,types:t})))}function lp({primaryType:e,types:t}){let n=``,r=up({primaryType:e,types:t});r.delete(e);let i=[e,...Array.from(r).sort()];for(let e of i)n+=`${e}(${t[e].map(({name:e,type:t})=>`${t} ${e}`).join(`,`)})`;return n}function up({primaryType:e,types:t},n=new Set){let r=e.match(/^\w*/u)?.[0];if(n.has(r)||t[r]===void 0)return n;n.add(r);for(let e of t[r])up({primaryType:e.type,types:t},n);return n}function dp({types:e,name:t,type:n,value:r}){if(e[n]!==void 0)return[{type:`bytes32`},z(sp({data:r,primaryType:n,types:e}))];if(n===`bytes`)return[{type:`bytes32`},z(r)];if(n===`string`)return[{type:`bytes32`},z(pi(r))];if(n.lastIndexOf(`]`)===n.length-1){let i=n.slice(0,n.lastIndexOf(`[`)),a=r.map(n=>dp({name:t,type:i,types:e,value:n}));return[{type:`bytes32`},z(ma(a.map(([e])=>e),a.map(([,e])=>e)))]}return[{type:n},r]}var fp=`1.2.4`,pp=class e extends Error{constructor(t,n={}){let r=n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details,i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...i?[`Docs: https://abitype.dev${i}`]:[],...r?[`Details: ${r}`]:[],`Version: abitype@${fp}`].join(` -`);super(a),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiTypeError`}),n.cause&&(this.cause=n.cause),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.shortMessage=t}};function mp(e,t){return e.exec(t)?.groups}var hp=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,gp=/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/,_p=/^\(.+?\).*?$/,vp=/^tuple(?(\[(\d*)\])*)$/;function yp(e){let t=e.type;if(vp.test(e.type)&&`components`in e){t=`(`;let n=e.components.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function Cp(e){return Sp.test(e)}function wp(e){return mp(Sp,e)}var Tp=/^event (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function Ep(e){return Tp.test(e)}function Dp(e){return mp(Tp,e)}var Op=/^function (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)(?: (?external|public{1}))?(?: (?pure|view|nonpayable|payable{1}))?(?: returns\s?\((?.*?)\))?$/;function kp(e){return Op.test(e)}function Ap(e){return mp(Op,e)}var jp=/^struct (?[a-zA-Z$_][a-zA-Z0-9$_]*) \{(?.*?)\}$/;function Mp(e){return jp.test(e)}function Np(e){return mp(jp,e)}var Pp=/^constructor\((?.*?)\)(?:\s(?payable{1}))?$/;function Fp(e){return Pp.test(e)}function Ip(e){return mp(Pp,e)}var Lp=/^fallback\(\) external(?:\s(?payable{1}))?$/;function Rp(e){return Lp.test(e)}function zp(e){return mp(Lp,e)}var Bp=/^receive\(\) external payable$/;function Vp(e){return Bp.test(e)}var Hp=new Set([`memory`,`indexed`,`storage`,`calldata`]),Up=new Set([`indexed`]),Wp=new Set([`calldata`,`memory`,`storage`]),Gp=class extends pp{constructor({signature:e}){super(`Failed to parse ABI item.`,{details:`parseAbiItem(${JSON.stringify(e,null,2)})`,docsPath:`/api/human#parseabiitem-1`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiItemError`})}},Kp=class extends pp{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownTypeError`})}},qp=class extends pp{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSolidityTypeError`})}},Jp=class extends pp{constructor({params:e}){super(`Failed to parse ABI parameters.`,{details:`parseAbiParameters(${JSON.stringify(e,null,2)})`,docsPath:`/api/human#parseabiparameters-1`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiParametersError`})}},Yp=class extends pp{constructor({param:e}){super(`Invalid ABI parameter.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParameterError`})}},Xp=class extends pp{constructor({param:e,name:t}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`"${t}" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SolidityProtectedKeywordError`})}},Zp=class extends pp{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidModifierError`})}},Qp=class extends pp{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`,`Data location can only be specified for array, struct, or mapping types, but "${n}" was given.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidFunctionModifierError`})}},$p=class extends pp{constructor({abiParameter:e}){super(`Invalid ABI parameter.`,{details:JSON.stringify(e,null,2),metaMessages:[`ABI parameter type is invalid.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiTypeParameterError`})}},em=class extends pp{constructor({signature:e,type:t}){super(`Invalid ${t} signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidSignatureError`})}},tm=class extends pp{constructor({signature:e}){super(`Unknown signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSignatureError`})}},nm=class extends pp{constructor({signature:e}){super(`Invalid struct signature.`,{details:e,metaMessages:[`No properties exist.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidStructSignatureError`})}},rm=class extends pp{constructor({type:e}){super(`Circular reference detected.`,{metaMessages:[`Struct "${e}" is a circular reference.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`CircularReferenceError`})}},im=class extends pp{constructor({current:e,depth:t}){super(`Unbalanced parentheses.`,{metaMessages:[`"${e.trim()}" has too many ${t>0?`opening`:`closing`} parentheses.`],details:`Depth "${t}"`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParenthesisError`})}};function am(e,t,n){let r=``;if(n)for(let e of Object.entries(n)){if(!e)continue;let t=``;for(let n of e[1])t+=`[${n.type}${n.name?`:${n.name}`:``}]`;r+=`(${e[0]}{${t}})`}return t?`${t}:${e}${r}`:`${e}${r}`}var om=new Map([[`address`,{type:`address`}],[`bool`,{type:`bool`}],[`bytes`,{type:`bytes`}],[`bytes32`,{type:`bytes32`}],[`int`,{type:`int256`}],[`int256`,{type:`int256`}],[`string`,{type:`string`}],[`uint`,{type:`uint256`}],[`uint8`,{type:`uint8`}],[`uint16`,{type:`uint16`}],[`uint24`,{type:`uint24`}],[`uint32`,{type:`uint32`}],[`uint64`,{type:`uint64`}],[`uint96`,{type:`uint96`}],[`uint112`,{type:`uint112`}],[`uint160`,{type:`uint160`}],[`uint192`,{type:`uint192`}],[`uint256`,{type:`uint256`}],[`address owner`,{type:`address`,name:`owner`}],[`address to`,{type:`address`,name:`to`}],[`bool approved`,{type:`bool`,name:`approved`}],[`bytes _data`,{type:`bytes`,name:`_data`}],[`bytes data`,{type:`bytes`,name:`data`}],[`bytes signature`,{type:`bytes`,name:`signature`}],[`bytes32 hash`,{type:`bytes32`,name:`hash`}],[`bytes32 r`,{type:`bytes32`,name:`r`}],[`bytes32 root`,{type:`bytes32`,name:`root`}],[`bytes32 s`,{type:`bytes32`,name:`s`}],[`string name`,{type:`string`,name:`name`}],[`string symbol`,{type:`string`,name:`symbol`}],[`string tokenURI`,{type:`string`,name:`tokenURI`}],[`uint tokenId`,{type:`uint256`,name:`tokenId`}],[`uint8 v`,{type:`uint8`,name:`v`}],[`uint256 balance`,{type:`uint256`,name:`balance`}],[`uint256 tokenId`,{type:`uint256`,name:`tokenId`}],[`uint256 value`,{type:`uint256`,name:`value`}],[`event:address indexed from`,{type:`address`,name:`from`,indexed:!0}],[`event:address indexed to`,{type:`address`,name:`to`,indexed:!0}],[`event:uint indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}],[`event:uint256 indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}]]);function sm(e,t={}){if(kp(e))return cm(e,t);if(Ep(e))return lm(e,t);if(Cp(e))return um(e,t);if(Fp(e))return dm(e,t);if(Rp(e))return fm(e);if(Vp(e))return{type:`receive`,stateMutability:`payable`};throw new tm({signature:e})}function cm(e,t={}){let n=Ap(e);if(!n)throw new em({signature:e,type:`function`});let r=_m(n.parameters),i=[],a=r.length;for(let e=0;e[a-zA-Z$_][a-zA-Z0-9$_]*(?:\spayable)?)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,mm=/^\((?.+?)\)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,hm=/^u?int$/;function gm(e,t){let n=am(e,t?.type,t?.structs);if(om.has(n))return om.get(n);let r=_p.test(e),i=mp(r?mm:pm,e);if(!i)throw new Yp({param:e});if(i.name&&bm(i.name))throw new Xp({param:e,name:i.name});let a=i.name?{name:i.name}:{},o=i.modifier===`indexed`?{indexed:!0}:{},s=t?.structs??{},c,l={};if(r){c=`tuple`;let e=_m(i.type),t=[],n=e.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?$/;function wm(e=[],t={},n=new Set){let r=[],i=e.length;for(let a=0;athis.maxSize){let e=this.keys().next().value;e&&this.delete(e)}return this}}(8192)}.checksum,Om=class extends le{constructor(e,t){super(),this.finished=!1,this.destroyed=!1,ce(e);let n=a(t);if(this.iHash=e.create(),typeof this.iHash.update!=`function`)throw Error(`Expected instance of class which extends utils.Hash`);this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let i=this.blockLen,o=new Uint8Array(i);o.set(n.length>i?e.create().update(n).digest():n);for(let e=0;enew Om(e,t).update(n).digest();km.create=(e,t)=>new Om(e,t);function Am(e,t={}){let{as:n=typeof e==`string`?`Hex`:`Bytes`}=t,r=Hi(Dl(e));return n===`Bytes`?r:Y(r)}var jm=/^0x[a-fA-F0-9]{40}$/;function Mm(e,t={}){let{strict:n=!0}=t;if(!jm.test(e))throw new Fm({address:e,cause:new Im});if(n){if(e.toLowerCase()===e)return;if(Nm(e)!==e)throw new Fm({address:e,cause:new Lm})}}function Nm(e){if(Dm.has(e))return Dm.get(e);Mm(e,{strict:!1});let t=e.substring(2).toLowerCase(),n=Am(Al(t),{as:`Bytes`}),r=t.split(``);for(let e=0;e<40;e+=2)n[e>>1]>>4>=8&&r[e]&&(r[e]=r[e].toUpperCase()),(n[e>>1]&15)>=8&&r[e+1]&&(r[e+1]=r[e+1].toUpperCase());let i=`0x${r.join(``)}`;return Dm.set(e,i),i}function Pm(e,t={}){let{strict:n=!0}=t??{};try{return Mm(e,{strict:n}),!0}catch{return!1}}var Fm=class extends W{constructor({address:e,cause:t}){super(`Address "${e}" is invalid.`,{cause:t}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidAddressError`})}},Im=class extends W{constructor(){super(`Address is not a 20 byte (40 hexadecimal character) value.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidInputError`})}},Lm=class extends W{constructor(){super(`Address does not match its checksum counterpart.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidChecksumError`})}},Rm=/^(.*)\[([0-9]*)\]$/,zm=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,Bm=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;2n**(8n-1n)-1n,2n**(16n-1n)-1n,2n**(24n-1n)-1n,2n**(32n-1n)-1n,2n**(40n-1n)-1n,2n**(48n-1n)-1n,2n**(56n-1n)-1n,2n**(64n-1n)-1n,2n**(72n-1n)-1n,2n**(80n-1n)-1n,2n**(88n-1n)-1n,2n**(96n-1n)-1n,2n**(104n-1n)-1n,2n**(112n-1n)-1n,2n**(120n-1n)-1n,2n**(128n-1n)-1n,2n**(136n-1n)-1n,2n**(144n-1n)-1n,2n**(152n-1n)-1n,2n**(160n-1n)-1n,2n**(168n-1n)-1n,2n**(176n-1n)-1n,2n**(184n-1n)-1n,2n**(192n-1n)-1n,2n**(200n-1n)-1n,2n**(208n-1n)-1n,2n**(216n-1n)-1n,2n**(224n-1n)-1n,2n**(232n-1n)-1n,2n**(240n-1n)-1n,2n**(248n-1n)-1n,2n**(256n-1n)-1n,-(2n**(8n-1n)),-(2n**(16n-1n)),-(2n**(24n-1n)),-(2n**(32n-1n)),-(2n**(40n-1n)),-(2n**(48n-1n)),-(2n**(56n-1n)),-(2n**(64n-1n)),-(2n**(72n-1n)),-(2n**(80n-1n)),-(2n**(88n-1n)),-(2n**(96n-1n)),-(2n**(104n-1n)),-(2n**(112n-1n)),-(2n**(120n-1n)),-(2n**(128n-1n)),-(2n**(136n-1n)),-(2n**(144n-1n)),-(2n**(152n-1n)),-(2n**(160n-1n)),-(2n**(168n-1n)),-(2n**(176n-1n)),-(2n**(184n-1n)),-(2n**(192n-1n)),-(2n**(200n-1n)),-(2n**(208n-1n)),-(2n**(216n-1n)),-(2n**(224n-1n)),-(2n**(232n-1n)),-(2n**(240n-1n)),-(2n**(248n-1n)),-(2n**(256n-1n));var Vm=2n**256n-1n;function Hm(e,t,n){let{checksumAddress:r,staticPosition:i}=n,a=ch(t.type);if(a){let[n,o]=a;return Km(e,{...t,type:o},{checksumAddress:r,length:n,staticPosition:i})}if(t.type===`tuple`)return Xm(e,t,{checksumAddress:r,staticPosition:i});if(t.type===`address`)return Gm(e,{checksum:r});if(t.type===`bool`)return qm(e);if(t.type.startsWith(`bytes`))return Jm(e,t,{staticPosition:i});if(t.type.startsWith(`uint`)||t.type.startsWith(`int`))return Ym(e,t);if(t.type===`string`)return Zm(e,{staticPosition:i});throw new Th(t.type)}var Um=32,Wm=32;function Gm(e,t={}){let{checksum:n=!1}=t;return[(e=>n?Nm(e):e)(Y(Nl(e.readBytes(32),-20))),32]}function Km(e,t,n){let{checksumAddress:r,length:i,staticPosition:a}=n;if(!i){let n=a+Il(e.readBytes(Wm)),i=n+Um;e.setPosition(n);let o=Il(e.readBytes(Um)),s=lh(t),c=0,l=[];for(let n=0;n48?Pl(i,{signed:n}):Il(i,{signed:n}),32]}function Xm(e,t,n){let{checksumAddress:r,staticPosition:i}=n,a=t.components.length===0||t.components.some(({name:e})=>!e),o=a?[]:{},s=0;if(lh(t)){let n=i+Il(e.readBytes(Wm));for(let i=0;i0?Ul(t,e):t}}if(o)return{dynamic:!0,encoded:e}}return{dynamic:!1,encoded:Ul(...s.map(({encoded:e})=>e))}}function rh(e,{type:t}){let[,n]=t.split(`bytes`),r=Zl(e);if(!n){let t=e;return r%32!=0&&(t=Yl(t,Math.ceil((e.length-2)/2/32)*32)),{dynamic:!0,encoded:Ul(Jl(Kl(r,{size:32})),t)}}if(r!==Number.parseInt(n,10))throw new Sh({expectedSize:Number.parseInt(n,10),value:e});return{dynamic:!1,encoded:Yl(e)}}function ih(e){if(typeof e!=`boolean`)throw new W(`Invalid boolean value: "${e}" (type: ${typeof e}). Expected: \`true\` or \`false\`.`);return{dynamic:!1,encoded:Jl(Gl(e))}}function ah(e,{signed:t,size:n}){if(typeof n==`number`){let r=2n**(BigInt(n)-(t?1n:0n))-1n,i=t?-r-1n:0n;if(e>r||ee))}}function ch(e){let t=e.match(/^(.*)\[(\d+)?\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}function lh(e){let{type:t}=e;if(t===`string`||t===`bytes`||t.endsWith(`[]`))return!0;if(t===`tuple`)return e.components?.some(lh);let n=ch(e.type);return!!(n&&lh({...e,type:n[1]}))}var uh={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:1/0,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new mh({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new ph({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new fh({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new fh({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let n=t??this.position;return this.assertPosition(n+e-1),this.bytes.subarray(n,n+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let n=this.inspectBytes(e);return this.position+=t??e,n},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===1/0)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}};function dh(e,{recursiveReadLimit:t=8192}={}){let n=Object.create(uh);return n.bytes=e,n.dataView=new DataView(e.buffer,e.byteOffset,e.byteLength),n.positionReadCount=new Map,n.recursiveReadLimit=t,n}var fh=class extends W{constructor({offset:e}){super(`Offset \`${e}\` cannot be negative.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.NegativeOffsetError`})}},ph=class extends W{constructor({length:e,position:t}){super(`Position \`${t}\` is out of bounds (\`0 < position < ${e}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.PositionOutOfBoundsError`})}},mh=class extends W{constructor({count:e,limit:t}){super(`Recursive read limit of \`${t}\` exceeded (recursive read count: \`${e}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.RecursiveReadLimitExceededError`})}};function hh(e,t,n={}){let{as:r=`Array`,checksumAddress:i=!1}=n,a=typeof t==`string`?kl(t):t,o=dh(a);if(Ml(a)===0&&e.length>0)throw new bh;if(Ml(a)&&Ml(a)<32)throw new yh({data:typeof t==`string`?t:Y(t),parameters:e,size:Ml(a)});let s=0,c=r===`Array`?[]:{};for(let t=0;t=Eh?n:t+n}function Ph(e,t,n){let r=e;for(;t-- >Eh;)r*=r,r%=n;return r}function Fh(e,t){if(e===Eh)throw Error(`invert: expected non-zero number`);if(t<=Eh)throw Error(`invert: expected positive modulus, got `+t);let n=Nh(e,t),r=t,i=Eh,a=Dh,o=Dh,s=Eh;for(;n!==Eh;){let e=r/n,t=r%n,c=i-o*e,l=a-s*e;r=n,n=t,i=o,a=s,o=c,s=l}if(r!==Dh)throw Error(`invert: does not exist`);return Nh(i,t)}function Ih(e,t){let n=(e.ORDER+Dh)/Ah,r=e.pow(t,n);if(!e.eql(e.sqr(r),t))throw Error(`Cannot find square root`);return r}function Lh(e,t){let n=(e.ORDER-jh)/Mh,r=e.mul(t,Oh),i=e.pow(r,n),a=e.mul(t,i),o=e.mul(e.mul(a,Oh),i),s=e.mul(a,e.sub(o,e.ONE));if(!e.eql(e.sqr(s),t))throw Error(`Cannot find square root`);return s}function Rh(e){if(e1e3)throw Error(`Cannot find square root: probably non-prime P`);if(n===1)return Ih;let a=i.pow(r,t),o=(t+Dh)/Oh;return function(e,r){if(e.is0(r))return r;if(Wh(e,r)!==1)throw Error(`Cannot find square root`);let i=n,s=e.mul(e.ONE,a),c=e.pow(r,t),l=e.pow(r,o);for(;!e.eql(c,e.ONE);){if(e.is0(c))return e.ZERO;let t=1,n=e.sqr(c);for(;!e.eql(n,e.ONE);)if(t++,n=e.sqr(n),t===i)throw Error(`Cannot find square root`);let r=Dh<(e[t]=`function`,e),{ORDER:`bigint`,MASK:`bigint`,BYTES:`isSafeInteger`,BITS:`isSafeInteger`}))}function Hh(e,t,n){if(nEh;)n&Dh&&(r=e.mul(r,i)),i=e.sqr(i),n>>=Dh;return r}function Uh(e,t,n=!1){let r=Array(t.length).fill(n?e.ZERO:void 0),i=t.reduce((t,n,i)=>e.is0(n)?t:(r[i]=t,e.mul(t,n)),e.ONE),a=e.inv(i);return t.reduceRight((t,n,i)=>e.is0(n)?t:(r[i]=e.mul(t,r[i]),e.mul(t,n)),a),r}function Wh(e,t){let n=(e.ORDER-Dh)/Oh,r=e.pow(t,n),i=e.eql(r,e.ONE),a=e.eql(r,e.ZERO),o=e.eql(r,e.neg(e.ONE));if(!i&&!a&&!o)throw Error(`invalid Legendre symbol result`);return i?1:a?0:-1}function Gh(e,t){t!==void 0&&m(t);let n=t===void 0?e.toString(2).length:t;return{nBitLength:n,nByteLength:Math.ceil(n/8)}}function Kh(e,t,n=!1,r={}){if(e<=Eh)throw Error(`invalid field: expected ORDER > 0, got `+e);let{nBitLength:i,nByteLength:a}=Gh(e,t);if(a>2048)throw Error(`invalid field: expected ORDER of <= 2048 bytes`);let o,s=Object.freeze({ORDER:e,isLE:n,BITS:i,BYTES:a,MASK:_(i),ZERO:Eh,ONE:Dh,create:t=>Nh(t,e),isValid:t=>{if(typeof t!=`bigint`)throw Error(`invalid field element: expected bigint, got `+typeof t);return Eh<=t&&te===Eh,isOdd:e=>(e&Dh)===Dh,neg:t=>Nh(-t,e),eql:(e,t)=>e===t,sqr:t=>Nh(t*t,e),add:(t,n)=>Nh(t+n,e),sub:(t,n)=>Nh(t-n,e),mul:(t,n)=>Nh(t*n,e),pow:(e,t)=>Hh(s,e,t),div:(t,n)=>Nh(t*Fh(n,e),e),sqrN:e=>e*e,addN:(e,t)=>e+t,subN:(e,t)=>e-t,mulN:(e,t)=>e*t,inv:t=>Fh(t,e),sqrt:r.sqrt||(t=>(o||=zh(e),o(s,t))),toBytes:e=>n?g(e,a):S(e,a),fromBytes:e=>{if(e.length!==a)throw Error(`Field.fromBytes: expected `+a+` bytes, got `+e.length);return n?y(e):D(e)},invertBatch:e=>Uh(s,e),cmov:(e,t,n)=>n?t:e});return Object.freeze(s)}function qh(e){if(typeof e!=`bigint`)throw Error(`field order must be bigint`);let t=e.toString(2).length;return Math.ceil(t/8)}function Jh(e){let t=qh(e);return t+Math.ceil(t/2)}function Yh(e,t,n=!1){let r=e.length,i=qh(t),a=Jh(t);if(r<16||r1024)throw Error(`expected `+a+`-1024 bytes of input, got `+r);let o=Nh(n?y(e):D(e),t-Dh)+Dh;return n?g(o,i):S(o,i)}var Xh=BigInt(0),Zh=BigInt(1);function Qh(e,t){let n=t.negate();return e?n:t}function $h(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw Error(`invalid window size, expected [1..`+t+`], got W=`+e)}function eg(e,t){$h(e,t);let n=Math.ceil(t/e)+1,r=2**(e-1),i=2**e;return{windows:n,windowSize:r,mask:_(e),maxNumber:i,shiftBy:BigInt(e)}}function tg(e,t,n){let{windowSize:r,mask:i,maxNumber:a,shiftBy:o}=n,s=Number(e&i),c=e>>o;s>r&&(s-=a,c+=Zh);let l=t*r,u=l+Math.abs(s)-1,d=s===0,f=s<0,p=t%2!=0;return{nextN:c,offset:u,isZero:d,isNeg:f,isNegF:p,offsetF:l}}function ng(e,t){if(!Array.isArray(e))throw Error(`array expected`);e.forEach((e,n)=>{if(!(e instanceof t))throw Error(`invalid point at index `+n)})}function rg(e,t){if(!Array.isArray(e))throw Error(`array of scalars expected`);e.forEach((e,n)=>{if(!t.isValid(e))throw Error(`invalid scalar at index `+n)})}var ig=new WeakMap,ag=new WeakMap;function og(e){return ag.get(e)||1}function sg(e,t){return{constTimeNegate:Qh,hasPrecomputes(e){return og(e)!==1},unsafeLadder(t,n,r=e.ZERO){let i=t;for(;n>Xh;)n&Zh&&(r=r.add(i)),i=i.double(),n>>=Zh;return r},precomputeWindow(e,n){let{windows:r,windowSize:i}=eg(n,t),a=[],o=e,s=o;for(let e=0;e12?c=s-3:s>4?c=s-2:s>0&&(c=2);let l=_(c),u=Array(Number(l)+1).fill(o),d=Math.floor((t.BITS-1)/c)*c,f=o;for(let e=d;e>=0;e-=c){u.fill(o);for(let t=0;t>BigInt(e)&l);u[a]=u[a].add(n[t])}let t=o;for(let e=u.length-1,n=o;e>0;e--)n=n.add(u[e]),t=t.add(n);if(f=f.add(t),e!==0)for(let e=0;e{let{Err:n}=fg;if(e<0||e>256)throw new n(`tlv.encode: wrong tag`);if(t.length&1)throw new n(`tlv.encode: unpadded data`);let r=t.length/2,i=se(r);if(i.length/2&128)throw new n(`tlv.encode: long form length too big`);let a=r>127?se(i.length/2|128):``;return se(e)+a+i+t},decode(e,t){let{Err:n}=fg,r=0;if(e<0||e>256)throw new n(`tlv.encode: wrong tag`);if(t.length<2||t[r++]!==e)throw new n(`tlv.decode: wrong tlv`);let i=t[r++],a=!!(i&128),o=0;if(!a)o=i;else{let e=i&127;if(!e)throw new n(`tlv.decode(long): indefinite length not supported`);if(e>4)throw new n(`tlv.decode(long): byte length is too big`);let a=t.subarray(r,r+e);if(a.length!==e)throw new n(`tlv.decode: length bytes not complete`);if(a[0]===0)throw new n(`tlv.decode(long): zero leftmost byte`);for(let e of a)o=o<<8|e;if(r+=e,o<128)throw new n(`tlv.decode(long): not minimal encoding`)}let s=t.subarray(r,r+o);if(s.length!==o)throw new n(`tlv.decode: wrong value length`);return{v:s,l:t.subarray(r+o)}}},_int:{encode(e){let{Err:t}=fg;if(e{let i=t.toAffine();return w(Uint8Array.from([4]),n.toBytes(i.x),n.toBytes(i.y))}),a=t.fromBytes||(e=>{let t=e.subarray(1);return{x:n.fromBytes(t.subarray(0,n.BYTES)),y:n.fromBytes(t.subarray(n.BYTES,2*n.BYTES))}});function o(e){let{a:r,b:i}=t,a=n.sqr(e),o=n.mul(a,e);return n.add(n.add(o,n.mul(e,r)),i)}function s(e,t){let r=n.sqr(t),i=o(e);return n.eql(r,i)}if(!s(t.Gx,t.Gy))throw Error(`bad curve params: generator point`);let c=n.mul(n.pow(t.a,_g),vg),l=n.mul(n.sqr(t.b),BigInt(27));if(n.is0(n.add(c,l)))throw Error(`bad curve params: a or b`);function u(e){return T(e,hg,t.n)}function d(e){let{allowedPrivateKeyLengths:n,nByteLength:r,wrapPrivateKey:i,n:a}=t;if(n&&typeof e!=`bigint`){if(re(e)&&(e=ae(e)),typeof e!=`string`||!n.includes(e.length))throw Error(`invalid private key`);e=e.padStart(r*2,`0`)}let o;try{o=typeof e==`bigint`?e:D(b(`private key`,e,r))}catch{throw Error(`invalid private key, expected hex or `+r+` bytes, got `+typeof e)}return i&&(o=Nh(o,a)),O(`private key`,o,hg,a),o}function f(e){if(!(e instanceof h))throw Error(`ProjectivePoint expected`)}let p=ee((e,t)=>{let{px:r,py:i,pz:a}=e;if(n.eql(a,n.ONE))return{x:r,y:i};let o=e.is0();t??=o?n.ONE:n.inv(a);let s=n.mul(r,t),c=n.mul(i,t),l=n.mul(a,t);if(o)return{x:n.ZERO,y:n.ZERO};if(!n.eql(l,n.ONE))throw Error(`invZ was invalid`);return{x:s,y:c}}),m=ee(e=>{if(e.is0()){if(t.allowInfinityPoint&&!n.is0(e.py))return;throw Error(`bad point: ZERO`)}let{x:r,y:i}=e.toAffine();if(!n.isValid(r)||!n.isValid(i))throw Error(`bad point: x or y not FE`);if(!s(r,i))throw Error(`bad point: equation left != right`);if(!e.isTorsionFree())throw Error(`bad point: not in prime-order subgroup`);return!0});class h{constructor(e,t,r){if(e==null||!n.isValid(e))throw Error(`x required`);if(t==null||!n.isValid(t)||n.is0(t))throw Error(`y required`);if(r==null||!n.isValid(r))throw Error(`z required`);this.px=e,this.py=t,this.pz=r,Object.freeze(this)}static fromAffine(e){let{x:t,y:r}=e||{};if(!e||!n.isValid(t)||!n.isValid(r))throw Error(`invalid affine point`);if(e instanceof h)throw Error(`projective point not allowed`);let i=e=>n.eql(e,n.ZERO);return i(t)&&i(r)?h.ZERO:new h(t,r,n.ONE)}get x(){return this.toAffine().x}get y(){return this.toAffine().y}static normalizeZ(e){let t=Uh(n,e.map(e=>e.pz));return e.map((e,n)=>e.toAffine(t[n])).map(h.fromAffine)}static fromHex(e){let t=h.fromAffine(a(b(`pointHex`,e)));return t.assertValidity(),t}static fromPrivateKey(e){return h.BASE.multiply(d(e))}static msm(e,t){return cg(h,r,e,t)}_setWindowSize(e){v.setWindowSize(this,e)}assertValidity(){m(this)}hasEvenY(){let{y:e}=this.toAffine();if(n.isOdd)return!n.isOdd(e);throw Error(`Field doesn't support isOdd`)}equals(e){f(e);let{px:t,py:r,pz:i}=this,{px:a,py:o,pz:s}=e,c=n.eql(n.mul(t,s),n.mul(a,i)),l=n.eql(n.mul(r,s),n.mul(o,i));return c&&l}negate(){return new h(this.px,n.neg(this.py),this.pz)}double(){let{a:e,b:r}=t,i=n.mul(r,_g),{px:a,py:o,pz:s}=this,c=n.ZERO,l=n.ZERO,u=n.ZERO,d=n.mul(a,a),f=n.mul(o,o),p=n.mul(s,s),m=n.mul(a,o);return m=n.add(m,m),u=n.mul(a,s),u=n.add(u,u),c=n.mul(e,u),l=n.mul(i,p),l=n.add(c,l),c=n.sub(f,l),l=n.add(f,l),l=n.mul(c,l),c=n.mul(m,c),u=n.mul(i,u),p=n.mul(e,p),m=n.sub(d,p),m=n.mul(e,m),m=n.add(m,u),u=n.add(d,d),d=n.add(u,d),d=n.add(d,p),d=n.mul(d,m),l=n.add(l,d),p=n.mul(o,s),p=n.add(p,p),d=n.mul(p,m),c=n.sub(c,d),u=n.mul(p,f),u=n.add(u,u),u=n.add(u,u),new h(c,l,u)}add(e){f(e);let{px:r,py:i,pz:a}=this,{px:o,py:s,pz:c}=e,l=n.ZERO,u=n.ZERO,d=n.ZERO,p=t.a,m=n.mul(t.b,_g),g=n.mul(r,o),_=n.mul(i,s),v=n.mul(a,c),y=n.add(r,i),b=n.add(o,s);y=n.mul(y,b),b=n.add(g,_),y=n.sub(y,b),b=n.add(r,a);let x=n.add(o,c);return b=n.mul(b,x),x=n.add(g,v),b=n.sub(b,x),x=n.add(i,a),l=n.add(s,c),x=n.mul(x,l),l=n.add(_,v),x=n.sub(x,l),d=n.mul(p,b),l=n.mul(m,v),d=n.add(l,d),l=n.sub(_,d),d=n.add(_,d),u=n.mul(l,d),_=n.add(g,g),_=n.add(_,g),v=n.mul(p,v),b=n.mul(m,b),_=n.add(_,v),v=n.sub(g,v),v=n.mul(p,v),b=n.add(b,v),g=n.mul(_,b),u=n.add(u,g),g=n.mul(x,b),l=n.mul(y,l),l=n.sub(l,g),g=n.mul(y,_),d=n.mul(x,d),d=n.add(d,g),new h(l,u,d)}subtract(e){return this.add(e.negate())}is0(){return this.equals(h.ZERO)}wNAF(e){return v.wNAFCached(this,e,h.normalizeZ)}multiplyUnsafe(e){let{endo:r,n:i}=t;O(`scalar`,e,mg,i);let a=h.ZERO;if(e===mg)return a;if(this.is0()||e===hg)return this;if(!r||v.hasPrecomputes(this))return v.wNAFCachedUnsafe(this,e,h.normalizeZ);let{k1neg:o,k1:s,k2neg:c,k2:l}=r.splitScalar(e),u=a,d=a,f=this;for(;s>mg||l>mg;)s&hg&&(u=u.add(f)),l&hg&&(d=d.add(f)),f=f.double(),s>>=hg,l>>=hg;return o&&(u=u.negate()),c&&(d=d.negate()),d=new h(n.mul(d.px,r.beta),d.py,d.pz),u.add(d)}multiply(e){let{endo:r,n:i}=t;O(`scalar`,e,hg,i);let a,o;if(r){let{k1neg:t,k1:i,k2neg:s,k2:c}=r.splitScalar(e),{p:l,f:u}=this.wNAF(i),{p:d,f}=this.wNAF(c);l=v.constTimeNegate(t,l),d=v.constTimeNegate(s,d),d=new h(n.mul(d.px,r.beta),d.py,d.pz),a=l.add(d),o=u.add(f)}else{let{p:t,f:n}=this.wNAF(e);a=t,o=n}return h.normalizeZ([a,o])[0]}multiplyAndAddUnsafe(e,t,n){let r=h.BASE,i=(e,t)=>t===mg||t===hg||!e.equals(r)?e.multiplyUnsafe(t):e.multiply(t),a=i(this,t).add(i(e,n));return a.is0()?void 0:a}toAffine(e){return p(this,e)}isTorsionFree(){let{h:e,isTorsionFree:n}=t;if(e===hg)return!0;if(n)return n(h,this);throw Error(`isTorsionFree() has not been declared for the elliptic curve`)}clearCofactor(){let{h:e,clearCofactor:n}=t;return e===hg?this:n?n(h,this):this.multiplyUnsafe(t.h)}toRawBytes(e=!0){return ie(`isCompressed`,e),this.assertValidity(),i(h,this,e)}toHex(e=!0){return ie(`isCompressed`,e),ae(this.toRawBytes(e))}}h.BASE=new h(t.Gx,t.Gy,n.ONE),h.ZERO=new h(n.ZERO,n.ONE,n.ZERO);let{endo:g,nBitLength:_}=t,v=sg(h,g?Math.ceil(_/2):_);return{CURVE:t,ProjectivePoint:h,normPrivateKeyToScalar:d,weierstrassEquation:o,isWithinCurveOrder:u}}function bg(e){let t=lg(e);return v(t,{hash:`hash`,hmac:`function`,randomBytes:`function`},{bits2int:`function`,bits2int_modN:`function`,lowS:`boolean`}),Object.freeze({lowS:!0,...t})}function xg(e){let t=bg(e),{Fp:n,n:r,nByteLength:i,nBitLength:a}=t,o=n.BYTES+1,s=2*n.BYTES+1;function c(e){return Nh(e,r)}function l(e){return Fh(e,r)}let{ProjectivePoint:u,normPrivateKeyToScalar:d,weierstrassEquation:f,isWithinCurveOrder:p}=yg({...t,toBytes(e,t,r){let i=t.toAffine(),a=n.toBytes(i.x),o=w;return ie(`isCompressed`,r),r?o(Uint8Array.from([t.hasEvenY()?2:3]),a):o(Uint8Array.from([4]),a,n.toBytes(i.y))},fromBytes(e){let t=e.length,r=e[0],i=e.subarray(1);if(t===o&&(r===2||r===3)){let e=D(i);if(!T(e,hg,n.ORDER))throw Error(`Point is not on curve`);let t=f(e),a;try{a=n.sqrt(t)}catch(e){let t=e instanceof Error?`: `+e.message:``;throw Error(`Point is not on curve`+t)}let o=(a&hg)===hg;return(r&1)==1!==o&&(a=n.neg(a)),{x:e,y:a}}else if(t===s&&r===4)return{x:n.fromBytes(i.subarray(0,n.BYTES)),y:n.fromBytes(i.subarray(n.BYTES,2*n.BYTES))};else{let e=o,n=s;throw Error(`invalid Point, expected length of `+e+`, or uncompressed `+n+`, got `+t)}}});function m(e){return e>r>>hg}function h(e){return m(e)?c(-e):e}let g=(e,t,n)=>D(e.slice(t,n));class v{constructor(e,t,n){O(`r`,e,hg,r),O(`s`,t,hg,r),this.r=e,this.s=t,n!=null&&(this.recovery=n),Object.freeze(this)}static fromCompact(e){let t=i;return e=b(`compactSignature`,e,t*2),new v(g(e,0,t),g(e,t,2*t))}static fromDER(e){let{r:t,s:n}=fg.toSig(b(`DER`,e));return new v(t,n)}assertValidity(){}addRecoveryBit(e){return new v(this.r,this.s,e)}recoverPublicKey(e){let{r,s:i,recovery:a}=this,o=ae(b(`msgHash`,e));if(a==null||![0,1,2,3].includes(a))throw Error(`recovery id invalid`);let s=a===2||a===3?r+t.n:r;if(s>=n.ORDER)throw Error(`recovery id 2 or 3 invalid`);let d=a&1?`03`:`02`,f=u.fromHex(d+pg(s,n.BYTES)),p=l(s),m=c(-o*p),h=c(i*p),g=u.BASE.multiplyAndAddUnsafe(f,m,h);if(!g)throw Error(`point at infinify`);return g.assertValidity(),g}hasHighS(){return m(this.s)}normalizeS(){return this.hasHighS()?new v(this.r,c(-this.s),this.recovery):this}toDERRawBytes(){return x(this.toDERHex())}toDERHex(){return fg.hexFromSig(this)}toCompactRawBytes(){return x(this.toCompactHex())}toCompactHex(){let e=i;return pg(this.r,e)+pg(this.s,e)}}let y={isValidPrivateKey(e){try{return d(e),!0}catch{return!1}},normPrivateKeyToScalar:d,randomPrivateKey:()=>{let e=Jh(t.n);return Yh(t.randomBytes(e),t.n)},precompute(e=8,t=u.BASE){return t._setWindowSize(e),t.multiply(BigInt(3)),t}};function ee(e,t=!0){return u.fromPrivateKey(e).toRawBytes(t)}function C(e){if(typeof e==`bigint`)return!1;if(e instanceof u)return!0;let r=b(`key`,e).length,a=n.BYTES,o=a+1,s=2*a+1;if(!(t.allowedPrivateKeyLengths||i===o))return r===o||r===s}function te(e,t,n=!0){if(C(e)===!0)throw Error(`first arg must be private key`);if(C(t)===!1)throw Error(`second arg must be public key`);return u.fromHex(t).multiply(d(e)).toRawBytes(n)}let ne=t.bits2int||function(e){if(e.length>8192)throw Error(`input is too large`);let t=D(e),n=e.length*8-a;return n>0?t>>BigInt(n):t},ae=t.bits2int_modN||function(e){return c(ne(e))},E=_(a);function se(e){return O(`num < 2^`+a,e,mg,E),S(e,i)}function ce(e,r,i=le){if([`recovered`,`canonical`].some(e=>e in i))throw Error(`sign() legacy options not supported`);let{hash:a,randomBytes:o}=t,{lowS:s,prehash:f,extraEntropy:g}=i;s??=!0,e=b(`msgHash`,e),ug(i),f&&(e=b(`prehashed msgHash`,a(e)));let _=ae(e),y=d(r),x=[se(y),se(_)];if(g!=null&&g!==!1){let e=g===!0?o(n.BYTES):g;x.push(b(`extraEntropy`,e))}let S=w(...x),ee=_;function C(e){let t=ne(e);if(!p(t))return;let n=l(t),r=u.BASE.multiply(t).toAffine(),i=c(r.x);if(i===mg)return;let a=c(n*c(ee+i*y));if(a===mg)return;let o=(r.x===i?0:2)|Number(r.y&hg),d=a;return s&&m(a)&&(d=h(a),o^=1),new v(i,d,o)}return{seed:S,k2sig:C}}let le={lowS:t.lowS,prehash:!1},ue={lowS:t.lowS,prehash:!1};function de(e,n,r=le){let{seed:i,k2sig:a}=ce(e,n,r),o=t;return oe(o.hash.outputLen,o.nByteLength,o.hmac)(i,a)}u.BASE._setWindowSize(8);function fe(e,n,r,i=ue){let a=e;n=b(`msgHash`,n),r=b(`publicKey`,r);let{lowS:o,prehash:s,format:d}=i;if(ug(i),`strict`in i)throw Error(`options.strict was renamed to lowS`);if(d!==void 0&&d!==`compact`&&d!==`der`)throw Error(`format must be compact or der`);let f=typeof a==`string`||re(a),p=!f&&!d&&typeof a==`object`&&!!a&&typeof a.r==`bigint`&&typeof a.s==`bigint`;if(!f&&!p)throw Error(`invalid signature, expected Uint8Array, hex string or Signature instance`);let m,h;try{if(p&&(m=new v(a.r,a.s)),f){try{d!==`compact`&&(m=v.fromDER(a))}catch(e){if(!(e instanceof fg.Err))throw e}!m&&d!==`der`&&(m=v.fromCompact(a))}h=u.fromHex(r)}catch{return!1}if(!m||o&&m.hasHighS())return!1;s&&(n=t.hash(n));let{r:g,s:_}=m,y=ae(n),x=l(_),S=c(y*x),ee=c(g*x),C=u.BASE.multiplyAndAddUnsafe(h,S,ee)?.toAffine();return C?c(C.x)===g:!1}return{CURVE:t,getPublicKey:ee,getSharedSecret:te,sign:de,verify:fe,ProjectivePoint:u,Signature:v,utils:y}}function Sg(e,t){let n=e.ORDER,r=mg;for(let e=n-hg;e%gg===mg;e/=gg)r+=hg;let i=r,a=gg<{let r=d,a=e.pow(n,l),o=e.sqr(a);o=e.mul(o,n);let s=e.mul(t,o);s=e.pow(s,c),s=e.mul(s,a),a=e.mul(s,n),o=e.mul(s,t);let p=e.mul(o,a);s=e.pow(p,u);let m=e.eql(s,e.ONE);a=e.mul(o,f),s=e.mul(p,r),o=e.cmov(a,o,m),p=e.cmov(s,p,m);for(let t=i;t>hg;t--){let n=t-gg;n=gg<{let a=e.sqr(i),o=e.mul(t,i);a=e.mul(a,o);let s=e.pow(a,n);s=e.mul(s,o);let c=e.mul(s,r),l=e.mul(e.sqr(s),i),u=e.eql(l,t);return{isValid:u,value:e.cmov(c,s,u)}}}return p}function Cg(e,t){if(Vh(e),!e.isValid(t.A)||!e.isValid(t.B)||!e.isValid(t.Z))throw Error(`mapToCurveSimpleSWU: invalid opts`);let n=Sg(e,t.Z);if(!e.isOdd)throw Error(`Fp.isOdd is not implemented!`);return r=>{let i,a,o,s,c,l,u,d;i=e.sqr(r),i=e.mul(i,t.Z),a=e.sqr(i),a=e.add(a,i),o=e.add(a,e.ONE),o=e.mul(o,t.B),s=e.cmov(t.Z,e.neg(a),!e.eql(a,e.ZERO)),s=e.mul(s,t.A),a=e.sqr(o),l=e.sqr(s),c=e.mul(l,t.A),a=e.add(a,c),a=e.mul(a,o),l=e.mul(l,s),c=e.mul(l,t.B),a=e.add(a,c),u=e.mul(i,o);let{isValid:f,value:p}=n(a,l);d=e.mul(i,r),d=e.mul(d,p),u=e.cmov(u,o,f),d=e.cmov(d,p,f);let m=e.isOdd(r)===e.isOdd(d);d=e.cmov(e.neg(d),d,m);let h=Uh(e,[s],!0)[0];return u=e.mul(u,h),{x:u,y:d}}}function wg(e){return{hash:e,hmac:(t,...n)=>km(e,t,u(...n)),randomBytes:c}}function Tg(e,t){let n=t=>xg({...e,...wg(t)});return{...n(t),create:n}}var Eg=D;function Dg(e,t){if(kg(e),kg(t),e<0||e>=1<<8*t)throw Error(`invalid I2OSP input: `+e);let n=Array.from({length:t}).fill(0);for(let r=t-1;r>=0;r--)n[r]=e&255,e>>>=8;return new Uint8Array(n)}function Og(e,t){let n=new Uint8Array(e.length);for(let r=0;r255&&(t=r(w(ue(`H2C-OVERSIZE-DST-`),t)));let{outputLen:i,blockLen:a}=r,o=Math.ceil(n/i);if(n>65535||o>255)throw Error(`expand_message_xmd: invalid lenInBytes`);let s=w(t,Dg(t.length,1)),c=Dg(0,a),l=Dg(n,2),u=Array(o),d=r(w(c,e,l,Dg(0,1),s));u[0]=r(w(d,Dg(1,1),s));for(let e=1;e<=o;e++)u[e]=r(w(Og(d,u[e-1]),Dg(e+1,1),s));return w(...u).slice(0,n)}function jg(e,t,n,r,i){if(E(e),E(t),kg(n),t.length>255){let e=Math.ceil(2*r/8);t=i.create({dkLen:e}).update(ue(`H2C-OVERSIZE-DST-`)).update(t).digest()}if(n>65535||t.length>255)throw Error(`expand_message_xof: invalid lenInBytes`);return i.create({dkLen:n}).update(e).update(Dg(n,2)).update(t).update(Dg(t.length,1)).digest()}function Mg(e,t,n){v(n,{DST:`stringOrUint8Array`,p:`bigint`,m:`isSafeInteger`,k:`isSafeInteger`,hash:`hash`});let{p:r,k:i,m:a,hash:o,expand:s,DST:c}=n;E(e),kg(t);let l=typeof c==`string`?ue(c):c,u=r.toString(2).length,d=Math.ceil((u+i)/8),f=t*a*d,p;if(s===`xmd`)p=Ag(e,l,f,o);else if(s===`xof`)p=jg(e,l,f,i,o);else if(s===`_internal_pass`)p=e;else throw Error(`expand must be "xmd" or "xof"`);let m=Array(t);for(let e=0;eArray.from(e).reverse());return(t,r)=>{let[i,a,o,s]=n.map(n=>n.reduce((n,r)=>e.add(e.mul(n,t),r))),[c,l]=Uh(e,[a,s],!0);return t=e.mul(i,c),r=e.mul(r,e.mul(o,l)),{x:t,y:r}}}function Pg(e,t,n){if(typeof t!=`function`)throw Error(`mapToCurve() must be defined`);function r(n){return e.fromAffine(t(n))}function i(t){let n=t.clearCofactor();return n.equals(e.ZERO)?e.ZERO:(n.assertValidity(),n)}return{defaults:n,hashToCurve(e,t){let a=Mg(e,2,{...n,DST:n.DST,...t}),o=r(a[0]),s=r(a[1]);return i(o.add(s))},encodeToCurve(e,t){return i(r(Mg(e,1,{...n,DST:n.encodeDST,...t})[0]))},mapToCurve(e){if(!Array.isArray(e))throw Error(`expected array of bigints`);for(let t of e)if(typeof t!=`bigint`)throw Error(`expected array of bigints`);return i(r(e))}}}var Fg=me({secp256k1:()=>Wg,secp256k1_hasher:()=>qg}),Ig=BigInt(`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f`),Lg=BigInt(`0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141`),Rg=BigInt(0),zg=BigInt(1),Bg=BigInt(2),Vg=(e,t)=>(e+t/Bg)/t;function Hg(e){let t=Ig,n=BigInt(3),r=BigInt(6),i=BigInt(11),a=BigInt(22),o=BigInt(23),s=BigInt(44),c=BigInt(88),l=e*e*e%t,u=l*l*e%t,d=Ph(Ph(Ph(u,n,t)*u%t,n,t)*u%t,Bg,t)*l%t,f=Ph(d,i,t)*d%t,p=Ph(f,a,t)*f%t,m=Ph(p,s,t)*p%t,h=Ph(Ph(Ph(Ph(Ph(Ph(m,c,t)*m%t,s,t)*p%t,n,t)*u%t,o,t)*f%t,r,t)*l%t,Bg,t);if(!Ug.eql(Ug.sqr(h),e))throw Error(`Cannot find square root`);return h}var Ug=Kh(Ig,void 0,void 0,{sqrt:Hg}),Wg=Tg({a:Rg,b:BigInt(7),Fp:Ug,n:Lg,Gx:BigInt(`55066263022277343669578718895168534326250603453777594175500187360389116729240`),Gy:BigInt(`32670510020758816978083085130507043184471273380659243275938904335757337482424`),h:BigInt(1),lowS:!0,endo:{beta:BigInt(`0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee`),splitScalar:e=>{let t=Lg,n=BigInt(`0x3086d221a7d46bcde86c90e49284eb15`),r=-zg*BigInt(`0xe4437ed6010e88286f547fa90abfe4c3`),i=BigInt(`0x114ca50f7a8e2f3f657c1108d9d44cfd8`),a=n,o=BigInt(`0x100000000000000000000000000000000`),s=Vg(a*e,t),c=Vg(-r*e,t),l=Nh(e-s*n-c*i,t),u=Nh(-s*r-c*a,t),d=l>o,f=u>o;if(d&&(l=t-l),f&&(u=t-u),l>o||u>o)throw Error(`splitScalar: Endomorphism failed, k=`+e);return{k1neg:d,k1:l,k2neg:f,k2:u}}}},Dc);Wg.ProjectivePoint,Wg.utils.randomPrivateKey;var Gg=Ng(Ug,[[`0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7`,`0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581`,`0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262`,`0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c`],[`0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b`,`0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14`,`0x0000000000000000000000000000000000000000000000000000000000000001`],[`0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c`,`0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3`,`0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931`,`0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84`],[`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b`,`0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573`,`0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f`,`0x0000000000000000000000000000000000000000000000000000000000000001`]].map(e=>e.map(e=>BigInt(e)))),Kg=Cg(Ug,{A:BigInt(`0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533`),B:BigInt(`1771`),Z:Ug.create(BigInt(`-11`))}),qg=Pg(Wg.ProjectivePoint,e=>{let{x:t,y:n}=Kg(Ug.create(e[0]));return Gg(t,n)},{DST:`secp256k1_XMD:SHA-256_SSWU_RO_`,encodeDST:`secp256k1_XMD:SHA-256_SSWU_NU_`,p:Ug.ORDER,m:1,k:128,expand:`xmd`,hash:Dc});qg.hashToCurve,qg.encodeToCurve;function Jg(e,t={}){let{recovered:n}=t;if(e.r===void 0||e.s===void 0||n&&e.yParity===void 0)throw new r_({signature:e});if(e.r<0n||e.r>Vm)throw new i_({value:e.r});if(e.s<0n||e.s>Vm)throw new a_({value:e.s});if(typeof e.yParity==`number`&&e.yParity!==0&&e.yParity!==1)throw new o_({value:e.yParity})}function Yg(e){return Xg(Y(e))}function Xg(e){if(e.length!==130&&e.length!==132)throw new n_({signature:e});let t=BigInt(Xl(e,0,32)),n=BigInt(Xl(e,32,64)),r=(()=>{let t=Number(`0x${e.slice(130)}`);if(!Number.isNaN(t))try{return t_(t)}catch{throw new o_({value:t})}})();return r===void 0?{r:t,s:n}:{r:t,s:n,yParity:r}}function Zg(e){if(e.r!==void 0&&e.s!==void 0)return Qg(e)}function Qg(e){let t=typeof e==`string`?Xg(e):e instanceof Uint8Array?Yg(e):typeof e.r==`string`?e_(e):e.v?$g(e):{r:e.r,s:e.s,...e.yParity===void 0?{}:{yParity:e.yParity}};return Jg(t),t}function $g(e){return{r:e.r,s:e.s,yParity:t_(e.v)}}function e_(e){let t=(()=>{let t=e.v?Number(e.v):void 0,n=e.yParity?Number(e.yParity):void 0;if(typeof t==`number`&&typeof n!=`number`&&(n=t_(t)),typeof n!=`number`)throw new o_({value:e.yParity});return n})();return{r:BigInt(e.r),s:BigInt(e.s),yParity:t}}function t_(e){if(e===0||e===27)return 0;if(e===1||e===28)return 1;if(e>=35)return+(e%2==0);throw new s_({value:e})}var n_=class extends W{constructor({signature:e}){super(`Value \`${e}\` is an invalid signature size.`,{metaMessages:[`Expected: 64 bytes or 65 bytes.`,`Received ${Zl(Wl(e))} bytes.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidSerializedSizeError`})}},r_=class extends W{constructor({signature:e}){super(`Signature \`${wl(e)}\` is missing either an \`r\`, \`s\`, or \`yParity\` property.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.MissingPropertiesError`})}},i_=class extends W{constructor({value:e}){super(`Value \`${e}\` is an invalid r value. r must be a positive integer less than 2^256.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidRError`})}},a_=class extends W{constructor({value:e}){super(`Value \`${e}\` is an invalid s value. s must be a positive integer less than 2^256.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidSError`})}},o_=class extends W{constructor({value:e}){super(`Value \`${e}\` is an invalid y-parity value. Y-parity must be 0 or 1.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidYParityError`})}},s_=class extends W{constructor({value:e}){super(`Value \`${e}\` is an invalid v value. v must be 27, 28 or >=35.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidVError`})}};function c_(e,t={}){return typeof e.chainId==`string`?l_(e):{...e,...t.signature}}function l_(e){let{address:t,chainId:n,nonce:r}=e,i=Zg(e);return{address:t,chainId:Number(n),nonce:BigInt(r),...i}}var u_=vh(`(uint256 chainId, address delegation, uint256 nonce, uint8 yParity, uint256 r, uint256 s), address to, bytes data`);function d_(e){if(typeof e==`string`){if(Xl(e,-32)!==`0x8010801080108010801080108010801080108010801080108010801080108010`)throw new m_(e)}else Jg(e.authorization)}function f_(e){d_(e);let t=$l(Xl(e,-64,-32)),n=Xl(e,-t-64,-64),r=Xl(e,0,-t-64),[i,a,o]=hh(u_,n);return{authorization:c_({address:i.delegation,chainId:Number(i.chainId),nonce:i.nonce,yParity:i.yParity,r:i.r,s:i.s}),signature:r,...o&&o!==`0x`?{data:o,to:a}:{}}}function p_(e){try{return d_(e),!0}catch{return!1}}var m_=class extends W{constructor(e){super(`Value \`${e}\` is an invalid ERC-8010 wrapped signature.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SignatureErc8010.InvalidWrappedSignatureError`})}};async function h_({message:e,signature:t}){return Cs({hash:Xf(e),signature:t})}async function g_({address:e,message:t,signature:n}){return Qc(ea(e),await h_({message:t,signature:n}))}var __=class extends I{constructor({value:e}){super(`Number \`${e}\` is not a valid decimal number.`,{name:`InvalidDecimalNumberError`})}};function v_(e,t){if(!/^(-?)([0-9]*)\.?([0-9]*)$/.test(e))throw new __({value:e});let[n,r=`0`]=e.split(`.`),i=n.startsWith(`-`);if(i&&(n=n.slice(1)),r=r.replace(/(0+)$/,``),t===0)Math.round(Number(`.${r}`))===1&&(n=`${BigInt(n)+1n}`),r=``;else if(r.length>t){let[e,i,a]=[r.slice(0,t-1),r.slice(t-1,t),r.slice(t)],o=Math.round(Number(`${i}.${a}`));r=o>9?`${BigInt(e)+BigInt(1)}0`.padStart(e.length+1,`0`):`${e}${o}`,r.length>t&&(r=r.slice(1),n=`${BigInt(n)+1n}`),r=r.slice(0,t)}else r=r.padEnd(t,`0`);return BigInt(`${i?`-`:``}${n}${r}`)}function y_(e){return e.map(e=>({...e,value:BigInt(e.value)}))}function b_(e){return{...e,balance:e.balance?BigInt(e.balance):void 0,nonce:e.nonce?di(e.nonce):void 0,storageProof:e.storageProof?y_(e.storageProof):void 0}}async function x_(e,{address:t,blockNumber:n,blockTag:r,storageKeys:i}){let a=r??`latest`,o=n===void 0?void 0:L(n);return b_(await e.request({method:`eth_getProof`,params:[t,i,o||a]}))}async function S_(e,{address:t,blockNumber:n,blockTag:r=`latest`,slot:i}){let a=n===void 0?void 0:L(n);return await e.request({method:`eth_getStorageAt`,params:[t,i,a||r]})}async function C_(e,{blockHash:t,blockNumber:n,blockTag:r,hash:i,index:a,sender:o,nonce:s}){let c=r||`latest`,l=n===void 0?void 0:L(n),u=null;if(i?u=await e.request({method:`eth_getTransactionByHash`,params:[i]},{dedupe:!0}):t?u=await e.request({method:`eth_getTransactionByBlockHashAndIndex`,params:[t,L(a)]},{dedupe:!0}):(l||c)&&typeof a==`number`?u=await e.request({method:`eth_getTransactionByBlockNumberAndIndex`,params:[l||c,L(a)]},{dedupe:!!l}):o&&typeof s==`number`&&(u=await e.request({method:`eth_getTransactionBySenderAndNonce`,params:[o,L(s)]},{dedupe:!0})),!u)throw new Co({blockHash:t,blockNumber:n,blockTag:c,hash:i,index:a});return(e.chain?.formatters?.transaction?.format||oc)(u,`getTransaction`)}async function w_(e,{hash:t,transactionReceipt:n}){let[r,i]=await Promise.all([F(e,Qu,`getBlockNumber`)({}),t?F(e,C_,`getTransaction`)({hash:t}):void 0]),a=n?.blockNumber||i?.blockNumber;return a?r-a+1n:0n}async function T_(e,{hash:t}){let n=await e.request({method:`eth_getTransactionReceipt`,params:[t]},{dedupe:!0});if(!n)throw new wo({hash:t});return(e.chain?.formatters?.transactionReceipt?.format||fd)(n,`getTransactionReceipt`)}async function E_(e,t){let{account:n,authorizationList:r,allowFailure:i=!0,blockNumber:a,blockOverrides:o,blockTag:s,stateOverride:c}=t,l=t.contracts,{batchSize:u=t.batchSize??1024,deployless:d=t.deployless??!1}=typeof e.batch?.multicall==`object`?e.batch.multicall:{},f=(()=>{if(t.multicallAddress)return t.multicallAddress;if(d)return null;if(e.chain)return ku({blockNumber:a,chain:e.chain,contract:`multicall3`});throw Error(`client chain not configured. multicallAddress is required.`)})(),p=[[]],m=0,h=0;for(let e=0;e0&&h>u&&p[m].length>0&&(m++,h=(e.length-2)/2,p[m]=[]),p[m]=[...p[m],{allowFailure:!0,callData:e,target:r}]}catch(e){let s=hs(e,{abi:t,address:r,args:a,docsPath:`/docs/contract/multicall`,functionName:o,sender:n});if(!i)throw s;p[m]=[...p[m],{allowFailure:!0,callData:`0x`,target:r}]}}let g=await Promise.allSettled(p.map(t=>F(e,Bu,`readContract`)({...f===null?{code:xu}:{address:f},abi:lu,account:n,args:[t],authorizationList:r,blockNumber:a,blockOverrides:o,blockTag:s,functionName:`aggregate3`,stateOverride:c}))),_=[];for(let e=0;e{let t=e,n=t.account?B(t.account):void 0,r=t.abi?La(t):t.data,i={...t,account:n,data:t.dataSuffix?ia([r||`0x`,t.dataSuffix]):r,from:t.from??n?.address};return ec(i),Js(i)}),i=e.stateOverrides?Qs(e.stateOverrides):void 0;t.push({blockOverrides:n,calls:r,stateOverrides:i})}let c=(typeof n==`bigint`?L(n):void 0)||r;return(await e.request({method:`eth_simulateV1`,params:[{blockStateCalls:t,returnFullTransactions:a,traceTransfers:o,validation:s},c]})).map((e,t)=>({...cc(e),calls:e.calls.map((e,n)=>{let{abi:r,args:a,functionName:o,to:s}=i[t].calls[n],c=e.error?.data??e.returnData,l=BigInt(e.gasUsed),u=e.logs?.map(e=>$c(e)),d=e.status===`0x1`?`success`:`failure`,f=r&&d===`success`&&c!==`0x`?cl({abi:r,data:c,functionName:o}):null,p=(()=>{if(d===`success`)return;let e;if(c===`0x`?e=new kr:c&&(e=new Po({data:c})),e)return hs(e,{abi:r??[],address:s??`0x`,args:a,functionName:o??``})})();return{data:c,gasUsed:l,logs:u,status:d,...d===`success`?{result:f}:{error:p}}})}))}catch(e){let t=e,n=Ws(t,{});throw n instanceof Us?t:n}}function O_(e){let t=!0,n=``,r=0,i=``,a=!1;for(let o=0;ok_(Object.values(e)[n],t)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(r)?n===`number`||n===`bigint`:/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(r)?n===`string`||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(r)?Array.isArray(e)&&e.every(e=>k_(e,{...t,type:r.replace(/(\[[0-9]{0,}\])$/,``)})):!1}}function A_(e,t,n){for(let r in e){let i=e[r],a=t[r];if(i.type===`tuple`&&a.type===`tuple`&&`components`in i&&`components`in a)return A_(i.components,a.components,n[r]);let o=[i.type,a.type];if(o.includes(`address`)&&o.includes(`bytes20`)||(o.includes(`address`)&&o.includes(`string`)||o.includes(`address`)&&o.includes(`bytes`))&&Pm(n[r],{strict:!1}))return o}}function j_(e,t={}){let{prepare:n=!0}=t,r=Array.isArray(e)||typeof e==`string`?Tm(e):e;return{...r,...n?{hash:F_(r)}:{}}}function M_(e,t,n){let{args:r=[],prepare:i=!0}=n??{},a=eu(t,{strict:!1}),o=e.filter(e=>a?e.type===`function`||e.type===`error`?N_(e)===Xl(t,0,4):e.type===`event`?F_(e)===t:!1:`name`in e&&e.name===t);if(o.length===0)throw new L_({name:t});if(o.length===1)return{...o[0],...i?{hash:F_(o[0])}:{}};let s;for(let e of o)if(`inputs`in e){if(!r||r.length===0){if(!e.inputs||e.inputs.length===0)return{...e,...i?{hash:F_(e)}:{}};continue}if(e.inputs&&e.inputs.length!==0&&e.inputs.length===r.length&&r.every((t,n)=>{let r=`inputs`in e&&e.inputs[n];return r?k_(t,r):!1})){if(s&&`inputs`in s&&s.inputs){let t=A_(e.inputs,s.inputs,r);if(t)throw new I_({abiItem:e,type:t[0]},{abiItem:s,type:t[1]})}s=e}}let c=(()=>{if(s)return s;let[e,...t]=o;return{...e,overloads:t}})();if(!c)throw new L_({name:t});return{...c,...i?{hash:F_(c)}:{}}}function N_(...e){return Xl(F_((()=>{if(Array.isArray(e[0])){let[t,n]=e;return M_(t,n)}return e[0]})()),0,4)}function P_(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return M_(t,n)}return e[0]})();return O_(typeof t==`string`?t:xp(t))}function F_(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return M_(t,n)}return e[0]})();return typeof t!=`string`&&`hash`in t&&t.hash?t.hash:Am(ql(P_(t)))}var I_=class extends W{constructor(e,t){super(`Found ambiguous types in overloaded ABI Items.`,{metaMessages:[`\`${e.type}\` in \`${O_(xp(e.abiItem))}\`, and`,`\`${t.type}\` in \`${O_(xp(t.abiItem))}\``,``,`These types encode differently and cannot be distinguished at runtime.`,`Remove one of the ambiguous items in the ABI.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiItem.AmbiguityError`})}},L_=class extends W{constructor({name:e,data:t,type:n=`item`}){let r=e?` with name "${e}"`:t?` with data "${t}"`:``;super(`ABI ${n}${r} not found.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiItem.NotFoundError`})}};function R_(...e){let[t,n]=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return[B_(t),n]}return e})(),{bytecode:r,args:i}=n;return Ul(r,t.inputs?.length&&i?.length?gh(t.inputs,i):`0x`)}function z_(e){return j_(e)}function B_(e){let t=e.find(e=>e.type===`constructor`);if(!t)throw new L_({name:`constructor`});return t}function V_(...e){let[t,n=[]]=(()=>{if(Array.isArray(e[0])){let[t,n,r]=e;return[U_(t,n,{args:r}),r]}let[t,n]=e;return[t,n]})(),{overloads:r}=t,i=r?U_([t,...r],t.name,{args:n}):t,a=W_(i),o=n.length>0?gh(i.inputs,n):void 0;return o?Ul(a,o):a}function H_(e,t={}){return j_(e,t)}function U_(e,t,n){let r=M_(e,t,n);if(r.type!==`function`)throw new L_({name:t,type:`function`});return r}function W_(e){return N_(e)}var G_=`0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`,K_=`0x0000000000000000000000000000000000000000`,q_=`0x6080604052348015600e575f80fd5b5061016d8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063f8b2cb4f1461002d575b5f80fd5b610047600480360381019061004291906100db565b61005d565b604051610054919061011e565b60405180910390f35b5f8173ffffffffffffffffffffffffffffffffffffffff16319050919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100aa82610081565b9050919050565b6100ba816100a0565b81146100c4575f80fd5b50565b5f813590506100d5816100b1565b92915050565b5f602082840312156100f0576100ef61007d565b5b5f6100fd848285016100c7565b91505092915050565b5f819050919050565b61011881610106565b82525050565b5f6020820190506101315f83018461010f565b9291505056fea26469706673582212203b9fe929fe995c7cf9887f0bdba8a36dd78e8b73f149b17d2d9ad7cd09d2dc6264736f6c634300081a0033`;async function J_(e,t){let{blockNumber:n,blockTag:r,calls:i,stateOverrides:a,traceAssetChanges:o,traceTransfers:s,validation:c}=t,l=t.account?B(t.account):void 0;if(o&&!l)throw new I("`account` is required when `traceAssetChanges` is true");let u=l?R_(z_(`constructor(bytes, bytes)`),{bytecode:vu,args:[q_,V_(H_(`function getBalance(address)`),[l.address])]}):void 0,d=o?await Promise.all(t.calls.map(async t=>{if(!t.data&&!t.abi)return;let{accessList:n}=await sf(e,{account:l.address,...t,data:t.abi?La(t):t.data});return n.map(({address:e,storageKeys:t})=>t.length>0?e:null)})).then(e=>e.flat().filter(Boolean)):[],f=await D_(e,{blockNumber:n,blockTag:r,blocks:[...o?[{calls:[{data:u}],stateOverrides:a},{calls:d.map((e,t)=>({abi:[H_(`function balanceOf(address) returns (uint256)`)],functionName:`balanceOf`,args:[l.address],to:e,from:K_,nonce:t})),stateOverrides:[{address:K_,nonce:0}]}]:[],{calls:[...i,{to:K_}].map(e=>({...e,from:l?.address})),stateOverrides:a},...o?[{calls:[{data:u}]},{calls:d.map((e,t)=>({abi:[H_(`function balanceOf(address) returns (uint256)`)],functionName:`balanceOf`,args:[l.address],to:e,from:K_,nonce:t})),stateOverrides:[{address:K_,nonce:0}]},{calls:d.map((e,t)=>({to:e,abi:[H_(`function decimals() returns (uint256)`)],functionName:`decimals`,from:K_,nonce:t})),stateOverrides:[{address:K_,nonce:0}]},{calls:d.map((e,t)=>({to:e,abi:[H_(`function tokenURI(uint256) returns (string)`)],functionName:`tokenURI`,args:[0n],from:K_,nonce:t})),stateOverrides:[{address:K_,nonce:0}]},{calls:d.map((e,t)=>({to:e,abi:[H_(`function symbol() returns (string)`)],functionName:`symbol`,from:K_,nonce:t})),stateOverrides:[{address:K_,nonce:0}]}]:[]],traceTransfers:s,validation:c}),p=o?f[2]:f[0],[m,h,,g,_,v,y,b]=o?f:[],{calls:x,...S}=p,ee=x.slice(0,-1)??[],C=m?.calls??[],te=h?.calls??[],ne=[...C,...te].map(e=>e.status===`success`?li(e.data):null),w=g?.calls??[],re=_?.calls??[],ie=[...w,...re].map(e=>e.status===`success`?li(e.data):null),ae=(v?.calls??[]).map(e=>e.status===`success`?e.result:null),T=(b?.calls??[]).map(e=>e.status===`success`?e.result:null),E=(y?.calls??[]).map(e=>e.status===`success`?e.result:null),D=[];for(let[e,t]of ie.entries()){let n=ne[e];if(typeof t!=`bigint`||typeof n!=`bigint`)continue;let r=ae[e-1],i=T[e-1],a=E[e-1],o=e===0?{address:G_,decimals:18,symbol:`ETH`}:{address:d[e-1],decimals:a||r?Number(r??1):void 0,symbol:i??void 0};D.some(e=>e.token.address===o.address)||D.push({token:o,value:{pre:n,post:t,diff:t-n}})}return{assetChanges:D,block:S,results:ee}}var Y_=`0x6492649264926492649264926492649264926492649264926492649264926492`;function X_(e){if(Xl(e,-32)!==`0x6492649264926492649264926492649264926492649264926492649264926492`)throw new $_(e)}function Z_(e){let{data:t,signature:n,to:r}=e;return Ul(gh(vh(`address, bytes, bytes`),[r,t,n]),Y_)}function Q_(e){try{return X_(e),!0}catch{return!1}}var $_=class extends W{constructor(e){super(`Value \`${e}\` is an invalid ERC-6492 wrapped signature.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SignatureErc6492.InvalidWrappedSignatureError`})}};function ev({r:e,s:t,to:n=`hex`,v:r,yParity:i}){let a=(()=>{if(i===0||i===1)return i;if(r&&(r===27n||r===28n||r>=35n))return+(r%2n==0n);throw Error("Invalid `v` or `yParity` value")})(),o=`0x${new Wg.Signature(li(e),li(t)).toCompactHex()}${a===0?`1b`:`1c`}`;return n===`hex`?o:Ci(o)}async function tv(e,t){let{address:n,chain:r=e.chain,hash:i,erc6492VerifierAddress:a=t.universalSignatureVerifierAddress??r?.contracts?.erc6492Verifier?.address,multicallAddress:o=t.multicallAddress??r?.contracts?.multicall3?.address,mode:s=`auto`}=t;if(r?.verifyHash)return await r.verifyHash(e,t);let c=(()=>{let e=t.signature;return xr(e)?e:typeof e==`object`&&`r`in e&&`s`in e?ev(e):hi(e)})();try{if(s===`eoa`)try{if(Qc(ea(n),await Cs({hash:i,signature:c})))return!0}catch{}return p_(c)?await nv(e,{...t,multicallAddress:o,signature:c}):await rv(e,{...t,verifierAddress:a,signature:c})}catch(e){if(s!==`eoa`)try{if(Qc(ea(n),await Cs({hash:i,signature:c})))return!0}catch{}if(e instanceof av)return!1;throw e}}async function nv(e,t){let{address:n,blockNumber:r,blockTag:i,hash:a,multicallAddress:o}=t,{authorization:s,data:c,signature:l,to:u}=f_(t.signature);if(await mf(e,{address:n,blockNumber:r,blockTag:i})===oa([`0xef0100`,s.address]))return await iv(e,{address:n,blockNumber:r,blockTag:i,hash:a,signature:l});let d={address:s.address,chainId:Number(s.chainId),nonce:Number(s.nonce),r:L(s.r,{size:32}),s:L(s.s,{size:32}),yParity:s.yParity};if(!await If({address:n,authorization:d}))throw new av;let f=await F(e,Bu,`readContract`)({...o?{address:o}:{code:xu},authorizationList:[d],abi:lu,blockNumber:r,blockTag:`pending`,functionName:`aggregate3`,args:[[...c?[{allowFailure:!0,target:u??n,callData:c}]:[],{allowFailure:!0,target:n,callData:La({abi:gu,functionName:`isValidSignature`,args:[a,l]})}]]});if((f[f.length-1]?.returnData)?.startsWith(`0x1626ba7e`))return!0;throw new av}async function rv(e,t){let{address:n,factory:r,factoryData:i,hash:a,signature:o,verifierAddress:s,...c}=t,l=await(async()=>!r&&!i||Q_(o)?o:Z_({data:i,signature:o,to:r}))(),u=s?{to:s,data:La({abi:_u,functionName:`isValidSig`,args:[n,a,l]}),...c}:{data:Ou({abi:_u,args:[n,a,l],bytecode:bu}),...c},{data:d}=await F(e,Pu,`call`)(u).catch(e=>{throw e instanceof ko?new av:e});if(ui(d??`0x0`))return!0;throw new av}async function iv(e,t){let{address:n,blockNumber:r,blockTag:i,hash:a,signature:o}=t;if((await F(e,Bu,`readContract`)({address:n,abi:gu,args:[a,o],blockNumber:r,blockTag:i,functionName:`isValidSignature`}).catch(e=>{throw e instanceof Ao?new av:e})).startsWith(`0x1626ba7e`))return!0;throw new av}var av=class extends Error{};async function ov(e,{address:t,message:n,factory:r,factoryData:i,signature:a,...o}){let s=Xf(n);return F(e,tv,`verifyHash`)({address:t,factory:r,factoryData:i,hash:s,signature:a,...o})}async function sv(e,t){let{address:n,factory:r,factoryData:i,signature:a,message:o,primaryType:s,types:c,domain:l,...u}=t,d=ip({message:o,primaryType:s,types:c,domain:l});return F(e,tv,`verifyHash`)({address:n,factory:r,factoryData:i,hash:d,signature:a,...u})}function cv(e,{emitOnBegin:t=!1,emitMissed:n=!1,onBlockNumber:r,onError:i,poll:a,pollingInterval:o=e.pollingInterval}){let s=a===void 0?!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):a,c;return s?Gu(V([`watchBlockNumber`,e.uid,t,n,o]),{onBlockNumber:r,onError:i},r=>Ku(async()=>{try{let t=await F(e,Qu,`getBlockNumber`)({cacheTime:0});if(c!==void 0){if(t===c)return;if(t-c>1&&n)for(let e=c+1n;ec)&&(r.onBlockNumber(t,c),c=t)}catch(e){r.onError?.(e)}},{emitOnBegin:t,interval:o})):Gu(V([`watchBlockNumber`,e.uid,t,n]),{onBlockNumber:r,onError:i},t=>{let n=!0,r=()=>n=!1;return(async()=>{try{let{unsubscribe:i}=await(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})().subscribe({params:[`newHeads`],onData(e){if(!n)return;let r=li(e.result?.number);t.onBlockNumber(r,c),c=r},onError(e){t.onError?.(e)}});r=i,n||r()}catch(e){i?.(e)}})(),()=>r()})}async function lv(e,t){let{checkReplacement:n=!0,confirmations:r=1,hash:i,onReplaced:a,retryCount:o=6,retryDelay:s=({count:e})=>~~(1<{g?.(),h?.(),y(new Eo({hash:i}))},c):void 0;return h=Gu(l,{onReplaced:a,resolve:v,reject:y},async t=>{if(p=await F(e,T_,`getTransactionReceipt`)({hash:i}).catch(()=>void 0),p&&r<=1){clearTimeout(b),t.resolve(p),h?.();return}g=F(e,cv,`watchBlockNumber`)({emitMissed:!0,emitOnBegin:!0,poll:!0,pollingInterval:u,async onBlockNumber(a){let c=e=>{clearTimeout(b),g?.(),e(),h?.()},l=a;if(!m)try{if(p){if(r>1&&(!p.blockNumber||l-p.blockNumber+1nt.resolve(p));return}if(n&&!d&&(m=!0,await ud(async()=>{d=await F(e,C_,`getTransaction`)({hash:i}),d.blockNumber&&(l=d.blockNumber)},{delay:s,retryCount:o}),m=!1),p=await F(e,T_,`getTransactionReceipt`)({hash:i}),r>1&&(!p.blockNumber||l-p.blockNumber+1nt.resolve(p))}catch(n){if(n instanceof Co||n instanceof wo){if(!d){m=!1;return}try{f=d,m=!0;let n=await ud(()=>F(e,lc,`getBlock`)({blockNumber:l,includeTransactions:!0}),{delay:s,retryCount:o,shouldRetry:({error:e})=>e instanceof ic});m=!1;let i=n.transactions.find(({from:e,nonce:t})=>e===f.from&&t===f.nonce);if(!i||(p=await F(e,T_,`getTransactionReceipt`)({hash:i.hash}),r>1&&(!p.blockNumber||l-p.blockNumber+1n{t.onReplaced?.({reason:a,replacedTransaction:f,transaction:i,transactionReceipt:p}),t.resolve(p)})}catch(e){c(()=>t.reject(e))}}else c(()=>t.reject(n))}}})}),_}function uv(e,{blockTag:t=e.experimental_blockTag??`latest`,emitMissed:n=!1,emitOnBegin:r=!1,onBlock:i,onError:a,includeTransactions:o,poll:s,pollingInterval:c=e.pollingInterval}){let l=s===void 0?!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):s,u=o??!1,d;return l?Gu(V([`watchBlocks`,e.uid,t,n,r,u,c]),{onBlock:i,onError:a},i=>Ku(async()=>{try{let r=await F(e,lc,`getBlock`)({blockTag:t,includeTransactions:u});if(r.number!==null&&d?.number!=null){if(r.number===d.number)return;if(r.number-d.number>1&&n)for(let t=d?.number+1n;td.number)&&(i.onBlock(r,d),d=r)}catch(e){i.onError?.(e)}},{emitOnBegin:r,interval:c})):(()=>{let n=!0,o=!0,s=()=>n=!1;return(async()=>{try{r&&F(e,lc,`getBlock`)({blockTag:t,includeTransactions:u}).then(e=>{n&&(o&&=(i(e,void 0),!1))}).catch(a);let{unsubscribe:c}=await(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})().subscribe({params:[`newHeads`],async onData(t){if(!n)return;let r=await F(e,lc,`getBlock`)({blockNumber:t.result?.number,includeTransactions:u}).catch(()=>{});n&&(i(r,d),o=!1,d=r)},onError(e){a?.(e)}});s=c,n||s()}catch(e){a?.(e)}})(),()=>s()})()}function dv(e,{address:t,args:n,batch:r=!0,event:i,events:a,fromBlock:o,onError:s,onLogs:c,poll:l,pollingInterval:u=e.pollingInterval,strict:d}){let f=l===void 0?typeof o==`bigint`?!0:!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):l,p=d??!1;return f?Gu(V([`watchEvent`,t,n,r,e.uid,i,u,o]),{onLogs:c,onError:s},s=>{let c;o!==void 0&&(c=o-1n);let l,d=!1,f=Ku(async()=>{if(!d){try{l=await F(e,lf,`createEventFilter`)({address:t,args:n,event:i,events:a,strict:p,fromBlock:o})}catch{}d=!0;return}try{let o;if(l)o=await F(e,$u,`getFilterChanges`)({filter:l});else{let r=await F(e,Qu,`getBlockNumber`)({});o=c&&c!==r?await F(e,al,`getLogs`)({address:t,args:n,event:i,events:a,fromBlock:c+1n,toBlock:r}):[],c=r}if(o.length===0)return;if(r)s.onLogs(o);else for(let e of o)s.onLogs([e])}catch(e){l&&e instanceof Ko&&(d=!1),s.onError?.(e)}},{emitOnBegin:!0,interval:u});return async()=>{l&&await F(e,ed,`uninstallFilter`)({filter:l}),f()}}):(()=>{let r=!0,o=()=>r=!1;return(async()=>{try{let l=(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})(),u=a??(i?[i]:void 0),f=[];u&&(f=[u.flatMap(e=>ja({abi:[e],eventName:e.name,args:n}))],i&&(f=f[0]));let{unsubscribe:m}=await l.subscribe({params:[`logs`,{address:t,topics:f}],onData(e){if(!r)return;let t=e.result;try{let{eventName:e,args:n}=tl({abi:u??[],data:t.data,topics:t.topics,strict:p});c([$c(t,{args:n,eventName:e})])}catch(e){let n,r;if(e instanceof Wr||e instanceof Gr){if(d)return;n=e.abiItem.name,r=e.abiItem.inputs?.some(e=>!(`name`in e&&e.name))}c([$c(t,{args:r?[]:{},eventName:n})])}},onError(e){s?.(e)}});o=m,r||o()}catch(e){s?.(e)}})(),()=>o()})()}function fv(e,{batch:t=!0,onError:n,onTransactions:r,poll:i,pollingInterval:a=e.pollingInterval}){return(i===void 0?e.transport.type!==`webSocket`&&e.transport.type!==`ipc`:i)?Gu(V([`watchPendingTransactions`,e.uid,t,a]),{onTransactions:r,onError:n},n=>{let r,i=Ku(async()=>{try{if(!r)try{r=await F(e,uf,`createPendingTransactionFilter`)({});return}catch(e){throw i(),e}let a=await F(e,$u,`getFilterChanges`)({filter:r});if(a.length===0)return;if(t)n.onTransactions(a);else for(let e of a)n.onTransactions([e])}catch(e){n.onError?.(e)}},{emitOnBegin:!0,interval:a});return async()=>{r&&await F(e,ed,`uninstallFilter`)({filter:r}),i()}}):(()=>{let t=!0,i=()=>t=!1;return(async()=>{try{let{unsubscribe:a}=await e.transport.subscribe({params:[`newPendingTransactions`],onData(e){if(!t)return;let n=e.result;r([n])},onError(e){n?.(e)}});i=a,t||i()}catch(e){n?.(e)}})(),()=>i()})()}function pv(e){let{scheme:t,statement:n,...r}=e.match(mv)?.groups??{},{chainId:i,expirationTime:a,issuedAt:o,notBefore:s,requestId:c,...l}=e.match(hv)?.groups??{},u=e.split(`Resources:`)[1]?.split(` -- `).slice(1);return{...r,...l,...i?{chainId:Number(i)}:{},...a?{expirationTime:new Date(a)}:{},...o?{issuedAt:new Date(o)}:{},...s?{notBefore:new Date(s)}:{},...c?{requestId:c}:{},...u?{resources:u}:{},...t?{scheme:t}:{},...n?{statement:n}:{}}}var mv=/^(?:(?[a-zA-Z][a-zA-Z0-9+-.]*):\/\/)?(?[a-zA-Z0-9+-.]*(?::[0-9]{1,5})?) (?:wants you to sign in with your Ethereum account:\n)(?
0x[a-fA-F0-9]{40})\n\n(?:(?.*)\n\n)?/,hv=/(?:URI: (?.+))\n(?:Version: (?.+))\n(?:Chain ID: (?\d+))\n(?:Nonce: (?[a-zA-Z0-9]+))\n(?:Issued At: (?.+))(?:\nExpiration Time: (?.+))?(?:\nNot Before: (?.+))?(?:\nRequest ID: (?.+))?/;function gv(e){let{address:t,domain:n,message:r,nonce:i,scheme:a,time:o=new Date}=e;if(n&&r.domain!==n||i&&r.nonce!==i||a&&r.scheme!==a||r.expirationTime&&o>=r.expirationTime||r.notBefore&&oPu(e,t),createAccessList:t=>sf(e,t),createBlockFilter:()=>cf(e),createContractEventFilter:t=>Pa(e,t),createEventFilter:t=>lf(e,t),createPendingTransactionFilter:()=>uf(e),estimateContractGas:t=>Zc(e,t),estimateGas:t=>Xc(e,t),getBalance:t=>df(e,t),getBlobBaseFee:()=>ff(e),getBlock:t=>lc(e,t),getBlockNumber:t=>Qu(e,t),getBlockTransactionCount:t=>pf(e,t),getBytecode:t=>mf(e,t),getChainId:()=>Wc(e),getCode:t=>mf(e,t),getContractEvents:t=>ol(e,t),getDelegation:t=>hf(e,t),getEip712Domain:t=>_f(e,t),getEnsAddress:t=>Ld(e,t),getEnsAvatar:t=>rf(e,t),getEnsName:t=>af(e,t),getEnsResolver:t=>of(e,t),getEnsText:t=>nf(e,t),getFeeHistory:t=>bf(e,t),estimateFeesPerGas:t=>pc(e,t),getFilterChanges:t=>$u(e,t),getFilterLogs:t=>xf(e,t),getGasPrice:()=>uc(e),getLogs:t=>al(e,t),getProof:t=>x_(e,t),estimateMaxPriorityFeePerGas:t=>dc(e,t),fillTransaction:t=>Gc(e,t),getStorageAt:t=>S_(e,t),getTransaction:t=>C_(e,t),getTransactionConfirmations:t=>w_(e,t),getTransactionCount:t=>hc(e,t),getTransactionReceipt:t=>T_(e,t),multicall:t=>E_(e,t),prepareTransactionRequest:t=>Yc(e,t),readContract:t=>Bu(e,t),sendRawTransaction:t=>ad(e,t),sendRawTransactionSync:t=>vv(e,t),simulate:t=>D_(e,t),simulateBlocks:t=>D_(e,t),simulateCalls:t=>J_(e,t),simulateContract:t=>Vu(e,t),verifyHash:t=>tv(e,t),verifyMessage:t=>ov(e,t),verifySiweMessage:t=>_v(e,t),verifyTypedData:t=>sv(e,t),uninstallFilter:t=>ed(e,t),waitForTransactionReceipt:t=>lv(e,t),watchBlocks:t=>uv(e,t),watchBlockNumber:t=>cv(e,t),watchContractEvent:t=>td(e,t),watchEvent:t=>dv(e,t),watchPendingTransactions:t=>fv(e,t)}}function bv(e){let{key:t=`public`,name:n=`Public Client`}=e;return Sd({...e,key:t,name:n,type:`publicClient`}).extend(yv)}async function xv(e,{chain:t}){let{id:n,name:r,nativeCurrency:i,rpcUrls:a,blockExplorers:o}=t;await e.request({method:`wallet_addEthereumChain`,params:[{chainId:L(n),chainName:r,nativeCurrency:i,rpcUrls:a.default.http,blockExplorerUrls:o?Object.values(o).map(({url:e})=>e):void 0}]},{dedupe:!0,retryCount:0})}function Sv(e,t){let{abi:n,args:r,bytecode:i,...a}=t,o=Ou({abi:n,args:r,bytecode:i});return sd(e,{...a,...a.authorizationList?{to:null}:{},data:o})}async function Cv(e){return e.account?.type===`local`?[e.account.address]:(await e.request({method:`eth_accounts`},{dedupe:!0})).map(e=>$i(e))}async function wv(e,t={}){let{account:n=e.account,chainId:r}=t,i=n?B(n):void 0,a=r?[i?.address,[L(r)]]:[i?.address],o=await e.request({method:`wallet_getCapabilities`,params:a}),s={};for(let[e,t]of Object.entries(o)){s[Number(e)]={};for(let[n,r]of Object.entries(t))n===`addSubAccount`&&(n=`unstable_addSubAccount`),s[Number(e)][n]=r}return typeof r==`number`?s[r]:s}async function Tv(e){return await e.request({method:`wallet_getPermissions`},{dedupe:!0})}async function Ev(e,t){let{account:n=e.account,chainId:r,nonce:i}=t;if(!n)throw new nd({docsPath:`/docs/eip7702/prepareAuthorization`});let a=B(n),o=(()=>{if(t.executor)return t.executor===`self`?t.executor:B(t.executor)})(),s={address:t.contractAddress??t.address,chainId:r,nonce:i};return s.chainId===void 0&&(s.chainId=e.chain?.id??await F(e,Wc,`getChainId`)({})),s.nonce===void 0&&(s.nonce=await F(e,hc,`getTransactionCount`)({address:a.address,blockTag:`pending`}),(o===`self`||o?.address&&Qc(o.address,a.address))&&(s.nonce+=1)),s}async function Dv(e){return(await e.request({method:`eth_requestAccounts`},{dedupe:!0,retryCount:0})).map(e=>ea(e))}async function Ov(e,t){return e.request({method:`wallet_requestPermissions`,params:[t]},{retryCount:0})}async function kv(e,t){let{chain:n=e.chain}=t,r=t.timeout??Math.max((n?.blockTime??0)*3,5e3),i=await F(e,hd,`sendCalls`)(t);return await F(e,_d,`waitForCallsStatus`)({...t,id:i.id,timeout:r})}var Av=new Zi(128);async function jv(e,t){let{account:n=e.account,assertChainId:r=!0,chain:i=e.chain,accessList:a,authorizationList:o,blobs:s,data:c,dataSuffix:l=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,pollingInterval:g,throwOnReceiptRevert:_,type:v,value:y,...b}=t,x=t.timeout??Math.max((i?.blockTime??0)*3,5e3);if(n===void 0)throw new nd({docsPath:`/docs/actions/wallet/sendTransactionSync`});let S=n?B(n):null;try{ec(t);let n=await(async()=>{if(t.to)return t.to;if(t.to!==null&&o&&o.length>0)return await As({authorization:o[0]}).catch(()=>{throw new I("`to` is required. Could not infer from `authorizationList`.")})})();if(S?.type===`json-rpc`||S===null){let t;i!==null&&(t=await F(e,Wc,`getChainId`)({}),r&&id({currentChainId:t,chain:i}));let ee=e.chain?.formatters?.transactionRequest?.format,C=(ee||Js)({...Ks(b,{format:ee}),accessList:a,account:S,authorizationList:o,blobs:s,chainId:t,data:c&&ia([c,l??`0x`]),gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,to:n,type:v,value:y},`sendTransaction`),te=Av.get(e.uid),ne=te?`wallet_sendTransaction`:`eth_sendTransaction`,w=await(async()=>{try{return await e.request({method:ne,params:[C]},{retryCount:0})}catch(t){if(te===!1)throw t;let n=t;if(n.name===`InvalidInputRpcError`||n.name===`InvalidParamsRpcError`||n.name===`MethodNotFoundRpcError`||n.name===`MethodNotSupportedRpcError`)return await e.request({method:`wallet_sendTransaction`,params:[C]},{retryCount:0}).then(t=>(Av.set(e.uid,!0),t)).catch(t=>{let r=t;throw r.name===`MethodNotFoundRpcError`||r.name===`MethodNotSupportedRpcError`?(Av.set(e.uid,!1),n):r});throw n}})(),re=await F(e,lv,`waitForTransactionReceipt`)({checkReplacement:!1,hash:w,pollingInterval:g,timeout:x});if(_&&re.status===`reverted`)throw new To({receipt:re});return re}if(S?.type===`local`){let r=await F(e,Yc,`prepareTransactionRequest`)({account:S,accessList:a,authorizationList:o,blobs:s,chain:i,data:c&&ia([c,l??`0x`]),gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,nonceManager:S.nonceManager,parameters:[...Kc,`sidecars`],type:v,value:y,...b,to:n}),g=i?.serializers?.transaction,x=await S.signTransaction(r,{serializer:g});return await F(e,vv,`sendRawTransactionSync`)({serializedTransaction:x,throwOnReceiptRevert:_,timeout:t.timeout})}throw S?.type===`smart`?new rd({metaMessages:["Consider using the `sendUserOperation` Action instead."],docsPath:`/docs/actions/bundler/sendUserOperation`,type:`smart`}):new rd({docsPath:`/docs/actions/wallet/sendTransactionSync`,type:S?.type})}catch(e){throw e instanceof rd?e:Uc(e,{...t,account:S,chain:t.chain||void 0})}}async function Mv(e,t){let{id:n}=t;await e.request({method:`wallet_showCallsStatus`,params:[n]})}async function Nv(e,t){let{account:n=e.account}=t;if(!n)throw new nd({docsPath:`/docs/eip7702/signAuthorization`});let r=B(n);if(!r.signAuthorization)throw new rd({docsPath:`/docs/eip7702/signAuthorization`,metaMessages:["The `signAuthorization` Action does not support JSON-RPC Accounts."],type:r.type});let i=await Ev(e,t);return r.signAuthorization(i)}async function Pv(e,{account:t=e.account,message:n}){if(!t)throw new nd({docsPath:`/docs/actions/wallet/signMessage`});let r=B(t);if(r.signMessage)return r.signMessage({message:n});let i=typeof n==`string`?_i(n):n.raw instanceof Uint8Array?pi(n.raw):n.raw;return e.request({method:`personal_sign`,params:[i,r.address]},{retryCount:0})}async function Fv(e,t){let{account:n=e.account,chain:r=e.chain,...i}=t;if(!n)throw new nd({docsPath:`/docs/actions/wallet/signTransaction`});let a=B(n);ec({account:a,...t});let o=await F(e,Wc,`getChainId`)({});r!==null&&id({currentChainId:o,chain:r});let s=(r?.formatters||e.chain?.formatters)?.transactionRequest?.format||Js;return a.signTransaction?a.signTransaction({...i,account:a,chainId:o},{serializer:e.chain?.serializers?.transaction}):await e.request({method:`eth_signTransaction`,params:[{...s({...i,account:a},`signTransaction`),chainId:L(o),from:a.address}]},{retryCount:0})}async function Iv(e,t){let{account:n=e.account,domain:r,message:i,primaryType:a}=t;if(!n)throw new nd({docsPath:`/docs/actions/wallet/signTypedData`});let o=B(n),s={EIP712Domain:np({domain:r}),...t.types};if(tp({domain:r,message:i,primaryType:a,types:s}),o.signTypedData)return o.signTypedData({domain:r,message:i,primaryType:a,types:s});let c=ep({domain:r,message:i,primaryType:a,types:s});return e.request({method:`eth_signTypedData_v4`,params:[o.address,c]},{retryCount:0})}async function Lv(e,{id:t}){await e.request({method:`wallet_switchEthereumChain`,params:[{chainId:L(t)}]},{retryCount:0})}async function Rv(e,t){return await e.request({method:`wallet_watchAsset`,params:t},{retryCount:0})}async function zv(e,t){return cd.internal(e,jv,`sendTransactionSync`,t)}function Bv(e){return{addChain:t=>xv(e,t),deployContract:t=>Sv(e,t),fillTransaction:t=>Gc(e,t),getAddresses:()=>Cv(e),getCallsStatus:t=>gd(e,t),getCapabilities:t=>wv(e,t),getChainId:()=>Wc(e),getPermissions:()=>Tv(e),prepareAuthorization:t=>Ev(e,t),prepareTransactionRequest:t=>Yc(e,t),requestAddresses:()=>Dv(e),requestPermissions:t=>Ov(e,t),sendCalls:t=>hd(e,t),sendCallsSync:t=>kv(e,t),sendRawTransaction:t=>ad(e,t),sendRawTransactionSync:t=>vv(e,t),sendTransaction:t=>sd(e,t),sendTransactionSync:t=>jv(e,t),showCallsStatus:t=>Mv(e,t),signAuthorization:t=>Nv(e,t),signMessage:t=>Pv(e,t),signTransaction:t=>Fv(e,t),signTypedData:t=>Iv(e,t),switchChain:t=>Lv(e,t),waitForCallsStatus:t=>_d(e,t),watchAsset:t=>Rv(e,t),writeContract:t=>cd(e,t),writeContractSync:t=>zv(e,t)}}function Vv(e){let{key:t=`wallet`,name:n=`Wallet Client`,transport:r}=e;return Sd({...e,key:t,name:n,transport:r,type:`walletClient`}).extend(Bv)}function Hv({key:e,methods:t,name:n,request:r,retryCount:i=3,retryDelay:a=150,timeout:o,type:s},c){let l=xd();return{config:{key:e,methods:t,name:n,request:r,retryCount:i,retryDelay:a,timeout:o,type:s},request:zf(r,{methods:t,retryCount:i,retryDelay:a,uid:l}),value:c}}function Uv(e,t={}){let{key:n=`custom`,methods:r,name:i=`Custom Provider`,retryDelay:a}=t;return({retryCount:o})=>Hv({key:n,methods:r,name:i,request:e.request.bind(e),retryCount:t.retryCount??o,retryDelay:a,type:`custom`})}var Wv=class extends I{constructor(){super(`No URL was provided to the Transport. Please provide a valid RPC URL to the Transport.`,{docsPath:`/docs/clients/intro`,name:`UrlRequiredError`})}};function Gv(e,t={}){let{batch:n,fetchFn:r,fetchOptions:i,key:a=`http`,methods:o,name:s=`HTTP JSON-RPC`,onFetchRequest:c,onFetchResponse:l,retryDelay:u,raw:d}=t;return({chain:f,retryCount:p,timeout:m})=>{let{batchSize:h=1e3,wait:g=0}=typeof n==`object`?n:{},_=t.retryCount??p,v=m??t.timeout??1e4,y=e||f?.rpcUrls.default.http[0];if(!y)throw new Wv;let b=Kf(y,{fetchFn:r,fetchOptions:i,onRequest:c,onResponse:l,timeout:v});return Hv({key:a,methods:o,name:s,async request({method:e,params:t}){let r={method:e,params:t},{schedule:i}=Nu({id:y,wait:g,shouldSplitBatch(e){return e.length>h},fn:e=>b.request({body:e}),sort:(e,t)=>e.id-t.id}),[{error:a,result:o}]=await(async e=>n?i(e):[await b.request({body:e})])(r);if(d)return{error:a,result:o};if(a)throw new Io({body:r,error:a,url:y});return o},retryCount:_,retryDelay:u,timeout:v,type:`http`},{fetchOptions:i,url:y})}}var Kv;(function(e){e[e.Home=1]=`Home`,e[e.Escrow=2]=`Escrow`})(Kv||={});var qv;(function(e){e[e.User=0]=`User`,e[e.Node=1]=`Node`})(qv||={});var Jv;(function(e){e[e.Default=0]=`Default`,e[e.SessionKey=1]=`SessionKey`})(Jv||={});var Yv;(function(e){e[e.Void=0]=`Void`,e[e.Open=1]=`Open`,e[e.Challenged=2]=`Challenged`,e[e.Closed=3]=`Closed`})(Yv||={});var Q;(function(e){e[e.Void=0]=`Void`,e[e.Acknowledgement=1]=`Acknowledgement`,e[e.HomeDeposit=10]=`HomeDeposit`,e[e.HomeWithdrawal=11]=`HomeWithdrawal`,e[e.EscrowDeposit=20]=`EscrowDeposit`,e[e.EscrowWithdraw=21]=`EscrowWithdraw`,e[e.TransferSend=30]=`TransferSend`,e[e.TransferReceive=31]=`TransferReceive`,e[e.Commit=40]=`Commit`,e[e.Release=41]=`Release`,e[e.Migrate=100]=`Migrate`,e[e.EscrowLock=110]=`EscrowLock`,e[e.MutualLock=120]=`MutualLock`,e[e.Finalize=200]=`Finalize`})(Q||={});var Xv;(function(e){e[e.HomeDeposit=10]=`HomeDeposit`,e[e.HomeWithdrawal=11]=`HomeWithdrawal`,e[e.EscrowDeposit=20]=`EscrowDeposit`,e[e.EscrowWithdraw=21]=`EscrowWithdraw`,e[e.Transfer=30]=`Transfer`,e[e.Commit=40]=`Commit`,e[e.Release=41]=`Release`,e[e.Rebalance=42]=`Rebalance`,e[e.Migrate=100]=`Migrate`,e[e.EscrowLock=110]=`EscrowLock`,e[e.MutualLock=120]=`MutualLock`,e[e.Finalize=200]=`Finalize`})(Xv||={});function Zv(e,t){return{id:``,transition:{type:Q.Void,txId:``,amount:new P(0)},asset:e,userWallet:t,epoch:0n,version:0n,homeLedger:{tokenAddress:`0x0`,blockchainId:0n,userBalance:new P(0),userNetFlow:new P(0),nodeBalance:new P(0),nodeNetFlow:new P(0)}}}function Qv(e,t,n,r){return{type:e,txId:t,accountId:n,amount:r}}function $v(e,t){return e.type===t.type?e.txId===t.txId?e.accountId===t.accountId?e.amount.equals(t.amount)?null:`amount mismatch: expected=${e.amount.toString()}, proposed=${t.amount.toString()}`:`account ID mismatch: expected=${e.accountId}, proposed=${t.accountId}`:`tx ID mismatch: expected=${e.txId}, proposed=${t.txId}`:`type mismatch: expected=${e.type}, proposed=${t.type}`}function ey(e,t){return e.tokenAddress.toLowerCase()===t.tokenAddress.toLowerCase()?e.blockchainId===t.blockchainId?e.userBalance.equals(t.userBalance)?e.userNetFlow.equals(t.userNetFlow)?e.nodeBalance.equals(t.nodeBalance)?e.nodeNetFlow.equals(t.nodeNetFlow)?null:`node net flow mismatch: expected=${e.nodeNetFlow.toString()}, proposed=${t.nodeNetFlow.toString()}`:`node balance mismatch: expected=${e.nodeBalance.toString()}, proposed=${t.nodeBalance.toString()}`:`user net flow mismatch: expected=${e.userNetFlow.toString()}, proposed=${t.userNetFlow.toString()}`:`user balance mismatch: expected=${e.userBalance.toString()}, proposed=${t.userBalance.toString()}`:`blockchain ID mismatch: expected=${e.blockchainId}, proposed=${t.blockchainId}`:`token address mismatch: expected=${e.tokenAddress}, proposed=${t.tokenAddress}`}function ty(e){if(!e.tokenAddress||e.tokenAddress===`0x0`)throw Error(`invalid token address`);if(e.blockchainId===0n)throw Error(`invalid blockchain ID`);if(e.userBalance.isNegative())throw Error(`user balance cannot be negative`);if(e.nodeBalance.isNegative())throw Error(`node balance cannot be negative`);let t=e.userBalance.add(e.nodeBalance),n=e.userNetFlow.add(e.nodeNetFlow);if(!t.equals(n))throw Error(`ledger balances do not match net flows: balances=${t.toString()}, net_flows=${n.toString()}`)}P.set({precision:50});function ny(e){switch(e.type){case Q.Void:case Q.TransferSend:case Q.TransferReceive:case Q.Commit:case Q.Release:return 0;case Q.Finalize:return 1;case Q.HomeDeposit:return 2;case Q.HomeWithdrawal:return 3;case Q.MutualLock:return 4;case Q.EscrowDeposit:return 5;case Q.EscrowLock:return 6;case Q.EscrowWithdraw:return 7;case Q.Migrate:return 8;default:return 0}}function ry(e,t){let n=e.decimalPlaces();if(n>t)throw Error(`amount exceeds maximum decimal precision: max ${t} decimals allowed, got ${n}`)}function iy(e,t){let n=new P(10).pow(t),r=e.mul(n);if(!r.isInteger())throw Error(`amount ${e.toString()} exceeds maximum decimal precision: max ${t} decimals allowed`);return BigInt(r.toFixed(0))}function ay(e,t,n,r,i,a=`0x00`){let o=dy(n),s=z(ma([{name:`channelDefinition`,type:`tuple`,components:[{name:`challengeDuration`,type:`uint32`},{name:`user`,type:`address`},{name:`node`,type:`address`},{name:`nonce`,type:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`},{name:`metadata`,type:`bytes32`}]}],[{challengeDuration:i,user:t,node:e,nonce:r,approvedSignatureValidators:BigInt(a||`0x00`),metadata:o}]));return`0x${`1`.padStart(2,`0`)}${s.slice(4)}`}function oy(e,t){return z(ma([{type:`bytes32`},{type:`uint64`}],[e,t]))}function sy(e,t,n,r){return z(ma([{type:`address`},{type:`string`},{type:`uint256`},{type:`uint256`}],[e,t,n,r]))}function cy(e){return z(ma([{type:`tuple`,components:[{name:`type`,type:`uint8`},{name:`txId`,type:`bytes32`},{name:`accountId`,type:`bytes32`},{name:`amount`,type:`string`}]}],[{type:e.type,txId:fy(e.txId),accountId:py(e.accountId),amount:e.amount.toString()}]))}function ly(e,t){return uy(e,t)}function uy(e,t){return z(ma([{type:`string`},{type:`bytes32`}],[e,t]))}function dy(e){return ei(sa(z(pi(e)),0,8),{dir:`right`,size:32})}function fy(e){let t=e.startsWith(`0x`)?e.slice(2):e;t.length%2==1&&(t=`0`+t);let n=[];for(let e=0;ee.toString(16).padStart(2,`0`)).join(``)}`,{dir:`left`,size:32})}function py(e){if(!e||e===``)return`0x0000000000000000000000000000000000000000000000000000000000000000`;let t=e.startsWith(`0x`)?e.slice(2):e,n=t.length;if((n===40||n===64)&&/^[0-9a-fA-F]+$/.test(t))return n===40?ei(`0x${t}`,{size:32}):`0x${t}`;t.length%2==1&&(t=`0`+t);let r=[];for(let e=0;ee.toString(16).padStart(2,`0`)).join(``)}`,{dir:`left`,size:32})}function my(e,t,n){return z(ma([{type:`uint64`},{type:`string[]`},{type:`uint64`}],[e,t,n]))}function hy(e,t){return ma([{type:`address`},{type:`bytes32`}],[e,t])}function gy(e){return e.transition.type===Q.Finalize}function _y(e){let t,n={type:Q.Void,txId:``,amount:new P(0)};return t=gy(e)?{id:``,transition:n,asset:e.asset,userWallet:e.userWallet,epoch:e.epoch+1n,version:0n,homeChannelId:void 0,escrowChannelId:void 0,homeLedger:{tokenAddress:`0x0`,blockchainId:0n,userBalance:new P(0),userNetFlow:new P(0),nodeBalance:new P(0),nodeNetFlow:new P(0)},escrowLedger:void 0}:{id:``,transition:n,asset:e.asset,userWallet:e.userWallet,epoch:e.epoch,version:e.version+1n,homeChannelId:e.homeChannelId,escrowChannelId:e.escrowChannelId,homeLedger:{...e.homeLedger},escrowLedger:void 0},e.escrowLedger&&(t.escrowLedger={...e.escrowLedger},e.userSig?(e.transition.type===Q.EscrowDeposit||e.transition.type===Q.EscrowWithdraw)&&(t.escrowChannelId=void 0,t.escrowLedger=void 0):t.transition={...e.transition}),t.id=sy(t.userWallet,t.asset,t.epoch,t.version),t}function vy(e,t,n,r,i){e.homeLedger.tokenAddress=r,e.homeLedger.blockchainId=n;let a=ay(i,e.userWallet,e.asset,t.nonce,t.challenge,t.approvedSigValidators);return e.homeChannelId=a,a}function yy(e){if(e.transition.type!==Q.Void)throw Error(`state already has a transition: ${e.transition.type}`);let t=`0x0000000000000000000000000000000000000000000000000000000000000000`,n=Qv(Q.Acknowledgement,t,t,new P(0));return e.transition=n,n}function by(e,t){if(!e.homeChannelId)throw Error(`missing home channel ID`);let n=e.homeChannelId,r=ly(n,e.id),i=Qv(Q.HomeDeposit,r,n,t);return e.transition=i,e.homeLedger.userNetFlow=e.homeLedger.userNetFlow.add(i.amount),e.homeLedger.userBalance=e.homeLedger.userBalance.add(i.amount),i}function xy(e,t){if(!e.homeChannelId)throw Error(`missing home channel ID`);let n=e.homeChannelId,r=ly(n,e.id),i=Qv(Q.HomeWithdrawal,r,n,t);return e.transition=i,e.homeLedger.userNetFlow=e.homeLedger.userNetFlow.sub(i.amount),e.homeLedger.userBalance=e.homeLedger.userBalance.sub(i.amount),i}function Sy(e,t,n){let r=t,i=ly(r,e.id),a=Qv(Q.TransferSend,i,r,n);return e.transition=a,e.homeLedger.userBalance=e.homeLedger.userBalance.sub(a.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.sub(a.amount),a}function Cy(e,t,n){let r=ly(t,e.id),i=Qv(Q.Commit,r,t,n);return e.transition=i,e.homeLedger.userBalance=e.homeLedger.userBalance.sub(i.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.sub(i.amount),i}function wy(e,t,n,r){if(!e.homeChannelId)throw Error(`missing home channel ID`);if(t===0n)throw Error(`invalid blockchain ID`);if(!n||n===`0x0`)throw Error(`invalid token address`);let i=oy(e.homeChannelId,e.version);e.escrowChannelId=i;let a=i,o=ly(a,e.id),s=Qv(Q.MutualLock,o,a,r);return e.transition=s,e.homeLedger.nodeBalance=e.homeLedger.nodeBalance.add(s.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.add(s.amount),e.escrowLedger={blockchainId:t,tokenAddress:n,userBalance:new P(0).add(s.amount),userNetFlow:new P(0).add(s.amount),nodeBalance:new P(0),nodeNetFlow:new P(0)},s}function Ty(e,t){if(!e.escrowChannelId)throw Error(`internal error: escrow channel ID is nil`);if(!e.escrowLedger)throw Error(`escrow ledger is nil`);let n=e.escrowChannelId,r=ly(n,e.id),i=Qv(Q.EscrowDeposit,r,n,t);return e.transition=i,e.homeLedger.userBalance=e.homeLedger.userBalance.add(i.amount),e.homeLedger.nodeBalance=new P(0),e.escrowLedger.userBalance=e.escrowLedger.userBalance.sub(i.amount),e.escrowLedger.nodeNetFlow=e.escrowLedger.nodeNetFlow.sub(i.amount),i}function Ey(e,t,n,r){if(!e.homeChannelId)throw Error(`missing home channel ID`);if(t===0n)throw Error(`invalid blockchain ID`);if(!n||n===`0x0`)throw Error(`invalid token address`);let i=oy(e.homeChannelId,e.version);e.escrowChannelId=i;let a=i,o=ly(a,e.id),s=Qv(Q.EscrowLock,o,a,r);return e.transition=s,e.escrowLedger={blockchainId:t,tokenAddress:n,userBalance:new P(0),userNetFlow:new P(0),nodeBalance:new P(0).add(s.amount),nodeNetFlow:new P(0).add(s.amount)},s}function Dy(e,t){if(!e.escrowChannelId)throw Error(`internal error: escrow channel ID is nil`);if(!e.escrowLedger)throw Error(`escrow ledger is nil`);let n=e.escrowChannelId,r=ly(n,e.id),i=Qv(Q.EscrowWithdraw,r,n,t);return e.transition=i,e.homeLedger.userBalance=e.homeLedger.userBalance.sub(i.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.sub(i.amount),e.escrowLedger.userNetFlow=e.escrowLedger.userNetFlow.sub(i.amount),e.escrowLedger.nodeBalance=e.escrowLedger.nodeBalance.sub(i.amount),i}function Oy(e,t){throw Error(`migrate transition not implemented yet`)}function ky(e){if(!e.homeChannelId)throw Error(`missing home channel ID`);let t=e.homeChannelId,n=e.homeLedger.userBalance,r=ly(t,e.id),i=Qv(Q.Finalize,r,t,n);return e.transition=i,e.homeLedger.userNetFlow=e.homeLedger.userNetFlow.sub(e.homeLedger.userBalance),e.homeLedger.userBalance=new P(0),i}var Ay=class{constructor(e){this.assetStore=e}async packSigningData(e){if(!e.homeChannelId)throw Error(`state.homeChannelId is required for packing`);let t=e.homeChannelId,n=cy(e.transition),r=await this.assetStore.getTokenDecimals(e.homeLedger.blockchainId,e.homeLedger.tokenAddress),i={chainId:e.homeLedger.blockchainId,token:e.homeLedger.tokenAddress,decimals:r,userAllocation:iy(e.homeLedger.userBalance,r),userNetFlow:iy(e.homeLedger.userNetFlow,r),nodeAllocation:iy(e.homeLedger.nodeBalance,r),nodeNetFlow:iy(e.homeLedger.nodeNetFlow,r)},a;if(e.escrowLedger){let t=await this.assetStore.getTokenDecimals(e.escrowLedger.blockchainId,e.escrowLedger.tokenAddress);a={chainId:e.escrowLedger.blockchainId,token:e.escrowLedger.tokenAddress,decimals:t,userAllocation:iy(e.escrowLedger.userBalance,t),userNetFlow:iy(e.escrowLedger.userNetFlow,t),nodeAllocation:iy(e.escrowLedger.nodeBalance,t),nodeNetFlow:iy(e.escrowLedger.nodeNetFlow,t)}}else a={chainId:0n,token:`0x0000000000000000000000000000000000000000`,decimals:0,userAllocation:0n,userNetFlow:0n,nodeAllocation:0n,nodeNetFlow:0n};let o=ny(e.transition),s=[{name:`chainId`,type:`uint64`},{name:`token`,type:`address`},{name:`decimals`,type:`uint8`},{name:`userAllocation`,type:`uint256`},{name:`userNetFlow`,type:`int256`},{name:`nodeAllocation`,type:`uint256`},{name:`nodeNetFlow`,type:`int256`}];return{channelId:t,signingData:ma([{type:`uint64`},{type:`uint8`},{type:`bytes32`},{type:`tuple`,components:s},{type:`tuple`,components:s}],[e.version,o,n,i,a])}}packWithChannelId(e,t){return ma([{type:`bytes32`},{type:`bytes`}],[e,t])}async packState(e){let{channelId:t,signingData:n}=await this.packSigningData(e);return this.packWithChannelId(t,n)}async packChallengeState(e){let{channelId:t,signingData:n}=await this.packSigningData(e),r=ia([n,pi(`challenge`)]);return this.packWithChannelId(t,r)}};function jy(e){return new Ay(e)}async function My(e,t){return jy(t).packState(e)}async function Ny(e,t){return jy(t).packChallengeState(e)}var Py=class{constructor(e){this.assetStore=e}async validateAdvancement(e,t){let n=_y(e);if(!t.homeChannelId)throw Error(`home channel ID cannot be nil`);if(n.homeChannelId||(n.homeChannelId=t.homeChannelId,n.homeLedger.blockchainId=t.homeLedger.blockchainId,n.homeLedger.tokenAddress=t.homeLedger.tokenAddress),t.homeChannelId!==n.homeChannelId)throw Error(`home channel ID mismatch: expected=${n.homeChannelId}, proposed=${t.homeChannelId}`);if(t.version!==n.version)throw Error(`version mismatch: expected=${n.version}, proposed=${t.version}`);if(t.userWallet.toLowerCase()!==n.userWallet.toLowerCase())throw Error(`user wallet mismatch: expected=${n.userWallet}, proposed=${t.userWallet}`);if(t.asset!==n.asset)throw Error(`asset mismatch: expected=${n.asset}, proposed=${t.asset}`);if(t.epoch!==n.epoch)throw Error(`epoch mismatch: expected=${n.epoch}, proposed=${t.epoch}`);if(t.id!==n.id)throw Error(`state ID mismatch: expected=${n.id}, proposed=${t.id}`);let r=t.transition,i=await this.assetStore.getAssetDecimals(t.asset);switch(ry(r.amount,i),r.type){case Q.Acknowledgement:if(!r.amount.isZero())throw Error(`transition amount must be zero, got ${r.amount.toString()}`);break;case Q.Finalize:if(r.amount.isNegative())throw Error(`transition amount must not be negative, got ${r.amount.toString()}`);break;default:if(r.amount.isNegative()||r.amount.isZero())throw Error(`transition amount must be positive, got ${r.amount.toString()}`)}let a=e.transition;switch(r.type){case Q.Void:throw Error(`cannot apply void transition as new transition`);case Q.Acknowledgement:if(e.userSig)throw Error(`current state is already acknowledged`);yy(n);break;case Q.HomeDeposit:by(n,r.amount);break;case Q.HomeWithdrawal:xy(n,r.amount);break;case Q.TransferSend:if(!r.accountId)throw Error(`missing account ID for transfer send transition`);Sy(n,r.accountId,r.amount);break;case Q.Commit:if(!r.accountId)throw Error(`missing account ID for commit transition`);Cy(n,r.accountId,r.amount);break;case Q.MutualLock:if(!t.escrowLedger)throw Error(`proposed state escrow ledger is nil`);wy(n,t.escrowLedger.blockchainId,t.escrowLedger.tokenAddress,r.amount);break;case Q.EscrowDeposit:if(a.type===Q.MutualLock){if(!a.amount.equals(r.amount))throw Error(`escrow deposit amount must be the same as mutual lock amount`);Ty(n,r.amount)}else throw Error(`escrow deposit transition must follow a mutual lock transition`);break;case Q.EscrowLock:if(!t.escrowLedger)throw Error(`proposed state escrow ledger is nil`);Ey(n,t.escrowLedger.blockchainId,t.escrowLedger.tokenAddress,r.amount);break;case Q.EscrowWithdraw:if(a.type===Q.EscrowLock){if(!a.amount.equals(r.amount))throw Error(`escrow withdraw amount must be the same as escrow lock amount`);Dy(n,r.amount)}else throw Error(`escrow withdraw transition must follow an escrow lock transition`);break;case Q.Migrate:Oy(n,r.amount);break;case Q.Finalize:ky(n);break;default:throw Error(`unsupported type for new transition: ${r.type}`)}let o=n.transition,s=$v(o,r);if(s)throw Error(`new transition does not match expected: ${s}`);let c=ey(n.homeLedger,t.homeLedger);if(c)throw Error(`home ledger mismatch: ${c}`);if(ty(t.homeLedger),n.escrowChannelId!==void 0!=(t.escrowChannelId!==void 0))throw Error(`escrow channel ID presence mismatch`);if(n.escrowChannelId&&t.escrowChannelId&&n.escrowChannelId!==t.escrowChannelId)throw Error(`escrow channel ID mismatch: expected=${n.escrowChannelId}, proposed=${t.escrowChannelId}`);if(n.escrowLedger!==void 0!=(t.escrowLedger!==void 0))throw Error(`escrow ledger presence mismatch`);if(n.escrowLedger&&t.escrowLedger){let e=ey(n.escrowLedger,t.escrowLedger);if(e)throw Error(`escrow ledger mismatch: expected=${JSON.stringify(n.escrowLedger)}, proposed=${JSON.stringify(t.escrowLedger)}: ${e}`);if(ty(t.escrowLedger),t.escrowLedger.blockchainId===t.homeLedger.blockchainId)throw Error(`escrow ledger blockchain ID cannot match home ledger blockchain ID`)}}},Fy;(function(e){e[e.Operate=0]=`Operate`,e[e.Deposit=1]=`Deposit`,e[e.Withdraw=2]=`Withdraw`,e[e.Close=3]=`Close`,e[e.Rebalance=4]=`Rebalance`})(Fy||={});var Iy;(function(e){e[e.Void=0]=`Void`,e[e.Open=1]=`Open`,e[e.Closed=2]=`Closed`})(Iy||={});function Ly(e){let t=z(pi(new TextEncoder().encode(e.metadata)));return z(ma([{type:`string`},{type:`address`},{type:`bytes32`},{type:`uint64`},{type:`bool`}],[e.id,e.owner_wallet,t,BigInt(e.version),e.creation_approval_not_required]))}function Ry(e){let t=e.startsWith(`0x`)||e.startsWith(`0X`)?e.slice(2):e;return t.length%2==1&&(t=`0`+t),!/^[0-9a-fA-F]*$/.test(t)||t.length===0?ei(`0x00`,{size:32}):(t.length>64&&(t=t.slice(t.length-64)),`0x${t.padStart(64,`0`)}`)}function zy(e){let t=e.application_ids.map(Ry),n=e.app_session_ids.map(Ry);return z(ma([{type:`address`},{type:`address`},{type:`uint64`},{type:`bytes32[]`},{type:`bytes32[]`},{type:`uint64`}],[e.user_address,e.session_key,BigInt(e.version),t,n,BigInt(e.expires_at)]))}var By=`error`,Vy=class extends Error{constructor(e){super(e),this.name=`RPCError`}},Hy=new Vy(`already connected`),Uy=new Vy(`not connected`);new Vy(`connection timeout`),new Vy(`error reading message`),new Vy(`nil request`),new Vy(`invalid request method`),new Vy(`error marshaling request`),new Vy(`error sending request`),new Vy(`no response received`),new Vy(`error sending ping`),new Vy(`error dialing websocket`);var Wy;(function(e){e[e.Req=1]=`Req`,e[e.Resp=2]=`Resp`,e[e.Event=3]=`Event`,e[e.RespErr=4]=`RespErr`})(Wy||={});function Gy(e,t){return typeof t==`bigint`||(e===`blockchain_id`||e===`epoch`||e===`version`||e===`nonce`)&&(typeof t==`number`||typeof t==`bigint`)?t.toString():t}function Ky(e){return e==null?{}:JSON.parse(JSON.stringify(e,Gy))}function qy(e){return e}function Jy(e){let t=e[By];return typeof t==`string`?Error(t):null}function Yy(e){return e.type===Wy.RespErr?Jy(e.payload):null}function Xy(e,t,n,r={}){return{type:e,requestId:t,method:n,payload:r,timestamp:Date.now()}}function Zy(e,t,n={}){return Xy(Wy.Req,e,t,n)}function Qy(e){let t=[e.type,e.requestId,e.method,e.payload,e.timestamp];return JSON.stringify(t,Gy)}function $y(e){let t=JSON.parse(e);if(!Array.isArray(t)||t.length!==5)throw Error(`invalid RPCData: expected 5 elements in array`);let[n,r,i,a,o]=t;if(typeof n!=`number`)throw Error(`invalid type: expected number`);if(typeof r!=`number`)throw Error(`invalid requestId: expected number`);if(typeof i!=`string`)throw Error(`invalid method: expected string`);if(typeof a!=`object`||!a)throw Error(`invalid payload: expected object`);if(typeof o!=`number`)throw Error(`invalid timestamp: expected number`);return{type:n,requestId:r,method:i,payload:a,timestamp:o}}var eb=`channels.v1.get_home_channel`,tb=`channels.v1.get_escrow_channel`,nb=`channels.v1.get_channels`,rb=`channels.v1.get_latest_state`,ib=`channels.v1.get_states`,ab=`channels.v1.request_creation`,ob=`channels.v1.submit_state`,sb=`channels.v1.submit_session_key_state`,cb=`channels.v1.get_last_key_states`,lb=`app_sessions.v1.submit_deposit_state`,ub=`app_sessions.v1.submit_app_state`,db=`app_sessions.v1.rebalance_app_sessions`,fb=`app_sessions.v1.get_app_definition`,pb=`app_sessions.v1.get_app_sessions`,mb=`app_sessions.v1.create_app_session`,hb=`app_sessions.v1.submit_session_key_state`,gb=`app_sessions.v1.get_last_key_states`,_b=`apps.v1.get_apps`,vb=`apps.v1.submit_app_version`,yb=`user.v1.get_balances`,bb=`user.v1.get_transactions`,xb=`user.v1.get_action_allowances`,Sb=`node.v1.ping`,Cb=`node.v1.get_config`,wb=`node.v1.get_assets`,Tb=class{constructor(e){this.dialer=e}async start(e,t){return this.dialer.dial(e,t)}async call(e,t,n){let r=Zy(Math.floor(Math.random()*(2**53-1)),e,Ky(t)),i=await this.dialer.call(r,n),a=Yy(i);if(a)throw Error(`rpc returned error: ${a.message}`);return qy(i.payload)}async channelsV1GetHomeChannel(e,t){return this.call(eb,e,t)}async channelsV1GetEscrowChannel(e,t){return this.call(tb,e,t)}async channelsV1GetChannels(e,t){return this.call(nb,e,t)}async channelsV1GetLatestState(e,t){return this.call(rb,e,t)}async channelsV1GetStates(e,t){return this.call(ib,e,t)}async channelsV1RequestCreation(e,t){return this.call(ab,e,t)}async channelsV1SubmitState(e,t){return this.call(ob,e,t)}async channelsV1SubmitSessionKeyState(e,t){return this.call(sb,e,t)}async channelsV1GetLastKeyStates(e,t){return this.call(cb,e,t)}async appSessionsV1SubmitDepositState(e,t){return this.call(lb,e,t)}async appSessionsV1SubmitAppState(e,t){return this.call(ub,e,t)}async appSessionsV1RebalanceAppSessions(e,t){return this.call(db,e,t)}async appSessionsV1GetAppDefinition(e,t){return this.call(fb,e,t)}async appSessionsV1GetAppSessions(e,t){return this.call(pb,e,t)}async appSessionsV1CreateAppSession(e,t){return this.call(mb,e,t)}async appSessionsV1SubmitSessionKeyState(e,t){return this.call(hb,e,t)}async appSessionsV1GetLastKeyStates(e,t){return this.call(gb,e,t)}async appsV1GetApps(e,t){return this.call(_b,e,t)}async appsV1SubmitAppVersion(e,t){return this.call(vb,e,t)}async userV1GetBalances(e,t){return this.call(yb,e,t)}async userV1GetTransactions(e,t){return this.call(bb,e,t)}async userV1GetActionAllowances(e,t){return this.call(xb,e,t)}async nodeV1Ping(e){await this.call(Sb,{},e)}async nodeV1GetConfig(e){return this.call(Cb,{},e)}async nodeV1GetAssets(e,t){return this.call(wb,e,t)}async close(){return this.dialer.close()}isConnected(){return this.dialer.isConnected()}eventChannel(){return this.dialer.eventChannel()}},Eb={handshakeTimeout:5e3,eventChanSize:100},Db=class{constructor(e=Eb){this.ws=null,this.responseSinks=new Map,this.eventQueue=[],this.eventResolvers=[],this.config=e}async dial(e,t){if(this.ws&&this.ws.readyState===WebSocket.OPEN)throw Hy;return this.closeHandler=t,new Promise((t,n)=>{let r=new WebSocket(e),i=setTimeout(()=>{r.close(),n(Error(`WebSocket handshake timeout`))},this.config.handshakeTimeout);r.onopen=()=>{clearTimeout(i),this.ws=r,t()},r.onerror=()=>{clearTimeout(i);let e=Error(`WebSocket error`);this.ws===r&&this.handleClose(e),n(e)},r.onclose=()=>{clearTimeout(i),this.ws===r&&this.handleClose()},r.onmessage=e=>{this.handleMessage(e.data)}})}isConnected(){return this.ws!==null&&this.ws.readyState===WebSocket.OPEN}async call(e,t){if(!this.isConnected())throw Uy;return new Promise((n,r)=>{if(t?.aborted){r(Error(`Request aborted`));return}let i=()=>{this.responseSinks.delete(e.requestId),r(Error(`Request aborted`))};t?.addEventListener(`abort`,i,{once:!0}),this.responseSinks.set(e.requestId,e=>{t?.removeEventListener(`abort`,i),n(e)});try{let t=Qy(e);this.ws.send(t)}catch(n){this.responseSinks.delete(e.requestId),t?.removeEventListener(`abort`,i),r(n)}})}async*eventChannel(){for(;this.isConnected();)this.eventQueue.length>0?yield this.eventQueue.shift():yield await new Promise(e=>{this.eventResolvers.push(e)})}async close(){this.ws&&=(this.ws.close(),null)}handleMessage(e){try{let t=$y(e),n=this.responseSinks.get(t.requestId);n?(this.responseSinks.delete(t.requestId),n(t)):this.eventResolvers.length>0?this.eventResolvers.shift()(t):(this.eventQueue.push(t),this.eventQueue.length>this.config.eventChanSize&&this.eventQueue.shift())}catch(e){console.error(`Failed to parse WebSocket message:`,e)}}handleClose(e){this.ws=null;for(let[e,t]of this.responseSinks.entries())t({type:4,requestId:e,method:``,payload:{error:`Connection closed`},timestamp:Date.now()});this.responseSinks.clear(),this.closeHandler&&this.closeHandler(e)}},Ob=class{constructor(e){this.cache=new Map,this.getAssetsFn=e}async getAssetDecimals(e){let t=this.cache.get(e.toLowerCase());if(t)return t.decimals;let n=await this.getAssetsFn();for(let t of n)if(this.cache.set(t.symbol.toLowerCase(),t),t.symbol.toLowerCase()===e.toLowerCase())return t.decimals;throw Error(`asset ${e} not found`)}async getTokenDecimals(e,t){if(this.cache.size===0){let e=await this.getAssetsFn();for(let t of e)this.cache.set(t.symbol.toLowerCase(),t)}let n=t.toLowerCase();for(let t of this.cache.values())for(let r of t.tokens)if(r.blockchainId===e&&r.address.toLowerCase()===n)return r.decimals;throw Error(`token ${t} on blockchain ${e} not found`)}async getTokenAddress(e,t){if(this.cache.size===0){let e=await this.getAssetsFn();for(let t of e)this.cache.set(t.symbol.toLowerCase(),t)}let n=e.toLowerCase();for(let r of this.cache.values())if(r.symbol.toLowerCase()===n){for(let e of r.tokens)if(e.blockchainId===t)return e.address;throw Error(`asset ${e} not available on blockchain ${t}`)}let r=await this.getAssetsFn();for(let i of r)if(this.cache.set(i.symbol.toLowerCase(),i),i.symbol.toLowerCase()===n){for(let e of i.tokens)if(e.blockchainId===t)return e.address;throw Error(`asset ${e} not available on blockchain ${t}`)}throw Error(`asset ${e} not found`)}async assetExistsOnBlockchain(e,t){let n=t.toLowerCase();for(let t of this.cache.values())if(t.symbol.toLowerCase()===n){for(let n of t.tokens)if(n.blockchainId===e)return!0;return!1}let r=await this.getAssetsFn();for(let t of r)if(this.cache.set(t.symbol.toLowerCase(),t),t.symbol.toLowerCase()===n){for(let n of t.tokens)if(n.blockchainId===e)return!0;return!1}return!1}async getSuggestedBlockchainId(e){let t=e.toLowerCase(),n=this.cache.get(t);if(n){if(n.suggestedBlockchainId===0n)throw Error(`no suggested blockchain ID for asset ${e}`);return n.suggestedBlockchainId}let r=await this.getAssetsFn();for(let e of r)this.cache.set(e.symbol.toLowerCase(),e);let i=this.cache.get(t);if(i){if(i.suggestedBlockchainId===0n)throw Error(`no suggested blockchain ID for asset ${e}`);return i.suggestedBlockchainId}throw Error(`asset ${e} not found`)}clearCache(){this.cache.clear()}};function kb(e){e&&console.error(`[nitrolite]`,`connection error:`,e)}var Ab={handshakeTimeout:5e3,errorHandler:kb,blockchainRPCs:new Map};function jb(e,t){return n=>{n.blockchainRPCs||=new Map,n.blockchainRPCs.set(e,t)}}function Mb(){return BigInt(Date.now())*1000000n+BigInt(Math.floor(Math.random()*1e6))}function Nb(e){if(Array.isArray(e))return e;if(typeof e==`string`&&e.length>0){let t=atob(e);return Array.from(t,e=>e.charCodeAt(0))}return[]}function Pb(e){let t=e.blockchains.map(e=>({name:e.name,id:BigInt(e.blockchain_id),channelHubAddress:e.channel_hub_address,lockingContractAddress:e.locking_contract_address,blockStep:0n}));return{nodeAddress:e.node_address,nodeVersion:e.node_version,supportedSigValidators:Nb(e.supported_sig_validators),blockchains:t}}function Fb(e){return e.map(e=>({name:e.name,symbol:e.symbol,decimals:e.decimals,suggestedBlockchainId:BigInt(e.suggested_blockchain_id),tokens:e.tokens.map(e=>({name:e.name,symbol:e.symbol,address:e.address,blockchainId:BigInt(e.blockchain_id),decimals:e.decimals}))}))}function Ib(e){return e.map(e=>({asset:e.asset,balance:new P(e.amount),enforced:new P(e.enforced)}))}function Lb(e){switch(e.toLowerCase()){case`home`:return Kv.Home;case`escrow`:return Kv.Escrow;default:return Kv.Home}}function Rb(e){switch(e.toLowerCase()){case`void`:return Yv.Void;case`open`:return Yv.Open;case`challenged`:return Yv.Challenged;case`closed`:return Yv.Closed;default:return Yv.Void}}function zb(e){let t={channelId:e.channel_id,userWallet:e.user_wallet,asset:e.asset,type:Lb(e.type),blockchainId:BigInt(e.blockchain_id),tokenAddress:e.token_address,challengeDuration:e.challenge_duration,nonce:BigInt(e.nonce),approvedSigValidators:e.approved_sig_validators,status:Rb(e.status),stateVersion:BigInt(e.state_version)};return e.challenge_expires_at&&(t.challengeExpiresAt=new Date(e.challenge_expires_at)),t}function Bb(e){return{tokenAddress:e.token_address,blockchainId:BigInt(e.blockchain_id),userBalance:new P(e.user_balance),userNetFlow:new P(e.user_net_flow),nodeBalance:new P(e.node_balance),nodeNetFlow:new P(e.node_net_flow)}}function Vb(e){let t={type:e.type,txId:e.tx_id,amount:new P(e.amount)};return e.account_id&&(t.accountId=e.account_id),t}function Hb(e){let t={id:e.id,transition:Vb(e.transition),asset:e.asset,userWallet:e.user_wallet,epoch:BigInt(e.epoch),version:BigInt(e.version),homeLedger:Bb(e.home_ledger)};return e.home_channel_id&&(t.homeChannelId=e.home_channel_id),e.escrow_channel_id&&(t.escrowChannelId=e.escrow_channel_id),e.escrow_ledger&&(t.escrowLedger=Bb(e.escrow_ledger)),e.user_sig&&(t.userSig=e.user_sig),e.node_sig&&(t.nodeSig=e.node_sig),t}function Ub(e){let t={id:e.id,asset:e.asset,txType:e.tx_type,fromAccount:e.from_account,toAccount:e.to_account,amount:new P(e.amount),createdAt:new Date(e.created_at)};return e.sender_new_state_id&&(t.senderNewStateId=e.sender_new_state_id),e.receiver_new_state_id&&(t.receiverNewStateId=e.receiver_new_state_id),t}function Wb(e){return{page:e.page,perPage:e.per_page,totalCount:e.total_count,pageCount:e.page_count}}function Gb(e){return{gatedAction:e.gated_action,timeWindow:e.time_window,allowance:BigInt(e.allowance),used:BigInt(e.used)}}function Kb(e){return{application_id:e.applicationId,participants:e.participants.map(e=>({wallet_address:e.walletAddress,signature_weight:e.signatureWeight})),quorum:e.quorum,nonce:e.nonce.toString()}}function qb(e){return{app_session_id:e.appSessionId,intent:e.intent,version:e.version.toString(),allocations:e.allocations.map(e=>({participant:e.participant,asset:e.asset,amount:e.amount.toString()})),session_data:e.sessionData}}function Jb(e){return{app_state_update:qb(e.appStateUpdate),quorum_sigs:e.quorumSigs}}function Yb(e){return{appSessionId:e.app_session_id,appDefinition:Xb(e.app_definition),isClosed:e.status===`closed`,sessionData:e.session_data||``,version:BigInt(e.version),allocations:(e.allocations||[]).map(e=>({participant:e.participant,asset:e.asset,amount:new P(e.amount)}))}}function Xb(e){if(!e.application_id||e.nonce===void 0||e.nonce===null)throw Error(`Invalid app definition: missing required fields (application_id, nonce)`);return{applicationId:e.application_id,participants:(e.participants||[]).map(e=>({walletAddress:e.wallet_address,signatureWeight:e.signature_weight})),quorum:e.quorum,nonce:BigInt(e.nonce)}}function Zb(e,t,n,r){return{challengeDuration:e.challenge,user:n,node:r,nonce:e.nonce,approvedSignatureValidators:BigInt(e.approvedSigValidators||`0x00`),metadata:dy(t)}}async function Qb(e,t){let n=await t(e.homeLedger.blockchainId,e.homeLedger.tokenAddress),r=$b(e.homeLedger,n),i;if(e.escrowLedger){let n=await t(e.escrowLedger.blockchainId,e.escrowLedger.tokenAddress);i=$b(e.escrowLedger,n)}else i={chainId:0n,token:`0x0000000000000000000000000000000000000000`,decimals:0,userAllocation:0n,userNetFlow:0n,nodeAllocation:0n,nodeNetFlow:0n};let a=nx(e.transition.type),o=cy(e.transition),s=e.userSig?e.userSig:`0x`,c=e.nodeSig?e.nodeSig:`0x`;return{version:e.version,intent:a,metadata:o,homeLedger:r,nonHomeLedger:i,userSig:s,nodeSig:c}}function $b(e,t){let n=iy(e.userBalance,t),r=iy(e.userNetFlow,t),i=iy(e.nodeBalance,t),a=iy(e.nodeNetFlow,t);return{chainId:e.blockchainId,token:e.tokenAddress,decimals:t,userAllocation:n,userNetFlow:r,nodeAllocation:i,nodeNetFlow:a}}function ex(e,t,n){let r=tx(e.homeLedger),i;e.nonHomeLedger.chainId!==0n&&(i=tx(e.nonHomeLedger));let a=t||void 0,o=n||void 0,s,c;return e.userSig&&e.userSig!==`0x`&&(s=e.userSig),e.nodeSig&&e.nodeSig!==`0x`&&(c=e.nodeSig),{id:``,transition:{type:Q.Void,txId:``,amount:new P(0)},asset:``,userWallet:`0x0000000000000000000000000000000000000000`,epoch:0n,version:e.version,homeChannelId:a,escrowChannelId:o,homeLedger:r,escrowLedger:i,userSig:s,nodeSig:c}}function tx(e){let t=-e.decimals;return{blockchainId:e.chainId,tokenAddress:e.token,userBalance:new P(e.userAllocation.toString()).mul(P.pow(10,t)),userNetFlow:new P(e.userNetFlow.toString()).mul(P.pow(10,t)),nodeBalance:new P(e.nodeAllocation.toString()).mul(P.pow(10,t)),nodeNetFlow:new P(e.nodeNetFlow.toString()).mul(P.pow(10,t))}}function nx(e){switch(e){case Q.HomeDeposit:return 2;case Q.HomeWithdrawal:return 3;case Q.Finalize:return 1;case Q.EscrowDeposit:return 4;case Q.EscrowWithdraw:return 6;case Q.Migrate:return 8;default:return 0}}var rx=[{type:`function`,name:`name`,inputs:[],outputs:[{name:``,type:`string`}],stateMutability:`view`},{type:`function`,name:`symbol`,inputs:[],outputs:[{name:``,type:`string`}],stateMutability:`view`},{type:`function`,name:`decimals`,inputs:[],outputs:[{name:``,type:`uint8`}],stateMutability:`view`},{type:`function`,name:`totalSupply`,inputs:[],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`balanceOf`,inputs:[{name:`account`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`transfer`,inputs:[{name:`to`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[{name:``,type:`bool`}],stateMutability:`nonpayable`},{type:`function`,name:`allowance`,inputs:[{name:`owner`,type:`address`},{name:`spender`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`approve`,inputs:[{name:`spender`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[{name:``,type:`bool`}],stateMutability:`nonpayable`},{type:`function`,name:`transferFrom`,inputs:[{name:`from`,type:`address`},{name:`to`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[{name:``,type:`bool`}],stateMutability:`nonpayable`},{type:`event`,name:`Transfer`,inputs:[{name:`from`,type:`address`,indexed:!0},{name:`to`,type:`address`,indexed:!0},{name:`value`,type:`uint256`,indexed:!1}]},{type:`event`,name:`Approval`,inputs:[{name:`owner`,type:`address`,indexed:!0},{name:`spender`,type:`address`,indexed:!0},{name:`value`,type:`uint256`,indexed:!1}]}],ix=class{constructor(e,t,n){this.tokenAddress=e,this.client=t,this.walletSigner=n}async balanceOf(e){return this.client.readContract({address:this.tokenAddress,abi:rx,functionName:`balanceOf`,args:[e]})}async allowance(e,t){return this.client.readContract({address:this.tokenAddress,abi:rx,functionName:`allowance`,args:[e,t]})}async approve(e,t){if(!this.walletSigner)throw Error(`Wallet signer is required for approve operation`);try{let{request:n}=await this.client.simulateContract({address:this.tokenAddress,abi:rx,functionName:`approve`,args:[e,t],account:this.walletSigner.account.address}),r=await this.walletSigner.writeContract(n);return await this.client.waitForTransactionReceipt({hash:r}),r}catch(e){throw console.error(`❌ Approve simulation/execution failed!`),e.message&&console.error(` Reason:`,e.message),e}}async decimals(){throw Error(`decimals() not available in minimal ERC20 ABI`)}};function ax(e,t,n){return new ix(e,t,n)}var ox=[{type:`constructor`,inputs:[{name:`_defaultSigValidator`,type:`address`,internalType:`contract ISignatureValidator`},{name:`_node`,type:`address`,internalType:`address`}],stateMutability:`nonpayable`},{type:`function`,name:`DEFAULT_SIG_VALIDATOR`,inputs:[],outputs:[{name:``,type:`address`,internalType:`contract ISignatureValidator`}],stateMutability:`view`},{type:`function`,name:`ESCROW_DEPOSIT_UNLOCK_DELAY`,inputs:[],outputs:[{name:``,type:`uint32`,internalType:`uint32`}],stateMutability:`view`},{type:`function`,name:`MAX_DEPOSIT_ESCROW_STEPS`,inputs:[],outputs:[{name:``,type:`uint32`,internalType:`uint32`}],stateMutability:`view`},{type:`function`,name:`MIN_CHALLENGE_DURATION`,inputs:[],outputs:[{name:``,type:`uint32`,internalType:`uint32`}],stateMutability:`view`},{type:`function`,name:`NODE`,inputs:[],outputs:[{name:``,type:`address`,internalType:`address`}],stateMutability:`view`},{type:`function`,name:`TRANSFER_GAS_LIMIT`,inputs:[],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`VALIDATOR_ACTIVATION_DELAY`,inputs:[],outputs:[{name:``,type:`uint64`,internalType:`uint64`}],stateMutability:`view`},{type:`function`,name:`VERSION`,inputs:[],outputs:[{name:``,type:`uint8`,internalType:`uint8`}],stateMutability:`view`},{type:`function`,name:`challengeChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengerSig`,type:`bytes`,internalType:`bytes`},{name:`challengerIdx`,type:`uint8`,internalType:`enum ParticipantIndex`}],outputs:[],stateMutability:`payable`},{type:`function`,name:`challengeEscrowDeposit`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`challengerSig`,type:`bytes`,internalType:`bytes`},{name:`challengerIdx`,type:`uint8`,internalType:`enum ParticipantIndex`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`challengeEscrowWithdrawal`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`challengerSig`,type:`bytes`,internalType:`bytes`},{name:`challengerIdx`,type:`uint8`,internalType:`enum ParticipantIndex`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`checkpointChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`claimFunds`,inputs:[{name:`token`,type:`address`,internalType:`address`},{name:`destination`,type:`address`,internalType:`address`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`closeChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`createChannel`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`initState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`depositToChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`depositToNode`,inputs:[{name:`token`,type:`address`,internalType:`address`},{name:`amount`,type:`uint256`,internalType:`uint256`}],outputs:[],stateMutability:`payable`},{type:`function`,name:`escrowHead`,inputs:[],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`finalizeEscrowDeposit`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`finalizeEscrowWithdrawal`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`finalizeMigration`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`getChannelData`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`}],outputs:[{name:`status`,type:`uint8`,internalType:`enum ChannelStatus`},{name:`definition`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`lastState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpiry`,type:`uint256`,internalType:`uint256`},{name:`lockedFunds`,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`getChannelIds`,inputs:[{name:`user`,type:`address`,internalType:`address`}],outputs:[{name:``,type:`bytes32[]`,internalType:`bytes32[]`}],stateMutability:`view`},{type:`function`,name:`getEscrowDepositData`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`}],outputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`status`,type:`uint8`,internalType:`enum EscrowStatus`},{name:`unlockAt`,type:`uint64`,internalType:`uint64`},{name:`challengeExpiry`,type:`uint64`,internalType:`uint64`},{name:`lockedAmount`,type:`uint256`,internalType:`uint256`},{name:`initState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],stateMutability:`view`},{type:`function`,name:`getEscrowDepositIds`,inputs:[{name:`page`,type:`uint256`,internalType:`uint256`},{name:`pageSize`,type:`uint256`,internalType:`uint256`}],outputs:[{name:`ids`,type:`bytes32[]`,internalType:`bytes32[]`}],stateMutability:`view`},{type:`function`,name:`getEscrowWithdrawalData`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`}],outputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`status`,type:`uint8`,internalType:`enum EscrowStatus`},{name:`challengeExpiry`,type:`uint64`,internalType:`uint64`},{name:`lockedAmount`,type:`uint256`,internalType:`uint256`},{name:`initState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],stateMutability:`view`},{type:`function`,name:`getNodeBalance`,inputs:[{name:`token`,type:`address`,internalType:`address`}],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`getNodeValidator`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`}],outputs:[{name:`validator`,type:`address`,internalType:`contract ISignatureValidator`},{name:`registeredAt`,type:`uint64`,internalType:`uint64`}],stateMutability:`view`},{type:`function`,name:`getOpenChannels`,inputs:[{name:`user`,type:`address`,internalType:`address`}],outputs:[{name:`openChannels`,type:`bytes32[]`,internalType:`bytes32[]`}],stateMutability:`view`},{type:`function`,name:`getReclaimBalance`,inputs:[{name:`account`,type:`address`,internalType:`address`},{name:`token`,type:`address`,internalType:`address`}],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`getUnlockableEscrowDepositStats`,inputs:[],outputs:[{name:`count`,type:`uint256`,internalType:`uint256`},{name:`totalAmount`,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`initiateEscrowDeposit`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`initiateEscrowWithdrawal`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`initiateMigration`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`purgeEscrowDeposits`,inputs:[{name:`maxSteps`,type:`uint256`,internalType:`uint256`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`registerNodeValidator`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`},{name:`validator`,type:`address`,internalType:`contract ISignatureValidator`},{name:`signature`,type:`bytes`,internalType:`bytes`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`withdrawFromChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`withdrawFromNode`,inputs:[{name:`to`,type:`address`,internalType:`address`},{name:`token`,type:`address`,internalType:`address`},{name:`amount`,type:`uint256`,internalType:`uint256`}],outputs:[],stateMutability:`nonpayable`},{type:`event`,name:`ChannelChallenged`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpireAt`,type:`uint64`,indexed:!1,internalType:`uint64`}],anonymous:!1},{type:`event`,name:`ChannelCheckpointed`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelClosed`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`finalState`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelCreated`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`user`,type:`address`,indexed:!0,internalType:`address`},{name:`definition`,type:`tuple`,indexed:!1,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`initialState`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelDeposited`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelWithdrawn`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`Deposited`,inputs:[{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`EscrowDepositChallenged`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpireAt`,type:`uint64`,indexed:!1,internalType:`uint64`}],anonymous:!1},{type:`event`,name:`EscrowDepositFinalized`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositFinalizedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositInitiated`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositInitiatedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositsPurged`,inputs:[{name:`purgedCount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalChallenged`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpireAt`,type:`uint64`,indexed:!1,internalType:`uint64`}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalFinalized`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalFinalizedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalInitiated`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalInitiatedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`FundsClaimed`,inputs:[{name:`account`,type:`address`,indexed:!0,internalType:`address`},{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`destination`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`MigrationInFinalized`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`MigrationInInitiated`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`MigrationOutFinalized`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`MigrationOutInitiated`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`NodeBalanceUpdated`,inputs:[{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`TransferFailed`,inputs:[{name:`recipient`,type:`address`,indexed:!0,internalType:`address`},{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`ValidatorRegistered`,inputs:[{name:`validatorId`,type:`uint8`,indexed:!0,internalType:`uint8`},{name:`validator`,type:`address`,indexed:!0,internalType:`contract ISignatureValidator`}],anonymous:!1},{type:`event`,name:`Withdrawn`,inputs:[{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`error`,name:`AddressCollision`,inputs:[{name:`collision`,type:`address`,internalType:`address`}]},{type:`error`,name:`ChallengerVersionTooLow`,inputs:[]},{type:`error`,name:`ECDSAInvalidSignature`,inputs:[]},{type:`error`,name:`ECDSAInvalidSignatureLength`,inputs:[{name:`length`,type:`uint256`,internalType:`uint256`}]},{type:`error`,name:`ECDSAInvalidSignatureS`,inputs:[{name:`s`,type:`bytes32`,internalType:`bytes32`}]},{type:`error`,name:`EmptySignature`,inputs:[]},{type:`error`,name:`IncorrectAmount`,inputs:[]},{type:`error`,name:`IncorrectChallengeDuration`,inputs:[]},{type:`error`,name:`IncorrectChannelId`,inputs:[]},{type:`error`,name:`IncorrectChannelStatus`,inputs:[]},{type:`error`,name:`IncorrectNode`,inputs:[]},{type:`error`,name:`IncorrectSignature`,inputs:[]},{type:`error`,name:`IncorrectStateIntent`,inputs:[]},{type:`error`,name:`IncorrectValue`,inputs:[]},{type:`error`,name:`InsufficientBalance`,inputs:[]},{type:`error`,name:`InvalidAddress`,inputs:[]},{type:`error`,name:`InvalidValidatorId`,inputs:[]},{type:`error`,name:`NativeTransferFailed`,inputs:[{name:`to`,type:`address`,internalType:`address`},{name:`amount`,type:`uint256`,internalType:`uint256`}]},{type:`error`,name:`NoChannelIdFoundForEscrow`,inputs:[]},{type:`error`,name:`ReentrancyGuardReentrantCall`,inputs:[]},{type:`error`,name:`SafeCastOverflowedIntToUint`,inputs:[{name:`value`,type:`int256`,internalType:`int256`}]},{type:`error`,name:`SafeERC20FailedOperation`,inputs:[{name:`token`,type:`address`,internalType:`address`}]},{type:`error`,name:`ValidatorAlreadyRegistered`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`}]},{type:`error`,name:`ValidatorNotActive`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`},{name:`activatesAt`,type:`uint64`,internalType:`uint64`}]},{type:`error`,name:`ValidatorNotApproved`,inputs:[]},{type:`error`,name:`ValidatorNotRegistered`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`}]}],sx=class{constructor(e,t,n,r,i,a,o){this.contractAddress=e,this.evmClient=t,this.walletSigner=n,this.blockchainId=r,this.nodeAddress=i,this.assetStore=a,this.requireCheckAllowance=o?.requireCheckAllowance??!0,this.requireCheckBalance=o?.requireCheckBalance??!0}hexToBytes32(e){let t=Ci(e);if(t.length!==32)throw Error(`invalid length: expected 32 bytes, got ${t.length}`);return`0x${Array.from(t).map(e=>e.toString(16).padStart(2,`0`)).join(``)}`}async getAllowance(e,t){let n=await this.assetStore.getTokenAddress(e,this.blockchainId);if(n===`0x0000000000000000000000000000000000000000`)return new P(`1e18`);let r=await ax(n,this.evmClient).allowance(t,this.contractAddress),i=await this.assetStore.getTokenDecimals(this.blockchainId,n);return new P(r.toString()).div(P.pow(10,i))}async getTokenBalance(e,t){let n=await this.assetStore.getTokenAddress(e,this.blockchainId);if(n===`0x0000000000000000000000000000000000000000`)return new P((await this.evmClient.getBalance({address:t})).toString()).div(P.pow(10,18));let r=await ax(n,this.evmClient).balanceOf(t),i=await this.assetStore.getTokenDecimals(this.blockchainId,n);return new P(r.toString()).div(P.pow(10,i))}async checkAllowance(e,t){return await this.getAllowance(e,t)}async approve(e,t){let n=await this.assetStore.getTokenAddress(e,this.blockchainId);if(n===`0x0000000000000000000000000000000000000000`)throw Error(`Native tokens do not require approval`);let r=iy(t,await this.assetStore.getTokenDecimals(this.blockchainId,n));return await ax(n,this.evmClient,this.walletSigner).approve(this.contractAddress,r)}async approveTokenByAddress(e,t){return await ax(e,this.evmClient,this.walletSigner).approve(this.contractAddress,t)}async checkAllowanceByAddress(e,t){return await ax(e,this.evmClient).allowance(t,this.contractAddress)}async getNodeBalance(e){let t=await this.evmClient.readContract({address:this.contractAddress,abi:ox,functionName:`getNodeBalance`,args:[e]}),n=await this.assetStore.getTokenDecimals(this.blockchainId,e);return new P(t.toString()).div(P.pow(10,n))}async getOpenChannels(e){return(await this.evmClient.readContract({address:this.contractAddress,abi:ox,functionName:`getOpenChannels`,args:[e]})).map(e=>e)}async getHomeChannelData(e){let t=this.hexToBytes32(e),n=await this.evmClient.readContract({address:this.contractAddress,abi:ox,functionName:`getChannelData`,args:[t]}),[,r,i,a]=Array.isArray(n)?n:[n.status,n.definition,n.lastState,n.challengeExpiry,n.lockedFunds],o=ex(i,e);return{definition:{nonce:r.nonce,challenge:r.challengeDuration,approvedSigValidators:`0x`+(r.approvedSignatureValidators??0n).toString(16)},node:r.node,lastState:o,challengeExpiry:a}}async getEscrowDepositData(e){throw Error(`getEscrowDepositData not implemented - needs contract ABI update`)}async getEscrowWithdrawalData(e){throw Error(`getEscrowWithdrawalData not implemented - needs contract ABI update`)}async deposit(e,t){let n=iy(t,await this.assetStore.getTokenDecimals(this.blockchainId,e));console.log(`💳 EVM Client - Deposit transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),token:e,amount:t.toString(),amountBig:n.toString(),walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});try{console.log(`🔍 Simulating deposit...`);let{request:t}=await this.evmClient.simulateContract({address:this.contractAddress,abi:ox,functionName:`depositToNode`,args:[e,n],account:this.walletSigner.account.address,...e===`0x0000000000000000000000000000000000000000`?{value:n}:{}});console.log(`✅ Simulation successful - executing deposit...`);let r=await this.walletSigner.writeContract(t);console.log(`📤 Deposit transaction submitted - hash:`,r),console.log(`⏳ Waiting for confirmation...`);let i=await this.evmClient.waitForTransactionReceipt({hash:r});return console.log(`✅ Deposit transaction confirmed!`,{blockNumber:i.blockNumber,gasUsed:i.gasUsed.toString()}),r}catch(e){throw console.error(`❌ Deposit transaction failed at blockchain level`),(e.message?.includes(`not supported`)||e.message?.includes(`not available`))&&(console.error(`⚠️ RPC ENDPOINT ISSUE: The RPC endpoint does not support sending transactions.`),console.error(` This usually means the RPC only supports read operations (eth_call, eth_getBalance, etc.)`),console.error(` but not write operations (eth_sendTransaction).`),console.error(` Solutions:`),console.error(` 1. Use an RPC provider that supports transactions (Infura, Alchemy, etc.)`),console.error(` 2. Make sure your RPC endpoint includes transaction capabilities`)),e}}async withdraw(e,t,n){let r=iy(n,await this.assetStore.getTokenDecimals(this.blockchainId,t));console.log(`💳 EVM Client - Withdraw transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),to:e,token:t,amount:n.toString(),amountBig:r.toString(),walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});try{console.log(`🔍 Simulating withdrawal...`);let{request:n}=await this.evmClient.simulateContract({address:this.contractAddress,abi:ox,functionName:`withdrawFromNode`,args:[e,t,r],account:this.walletSigner.account.address});console.log(`✅ Simulation successful - executing withdrawal...`);let i=await this.walletSigner.writeContract(n);console.log(`📤 Withdraw transaction submitted - hash:`,i),console.log(`⏳ Waiting for confirmation...`);let a=await this.evmClient.waitForTransactionReceipt({hash:i});return console.log(`✅ Withdraw transaction confirmed!`,{blockNumber:a.blockNumber,gasUsed:a.gasUsed.toString()}),i}catch(e){throw console.error(`❌ Withdraw simulation/execution failed!`),e.message&&console.error(` Reason:`,e.message),e}}async create(e,t){let n=Zb(e,t.asset,t.userWallet,this.nodeAddress),r=await Qb(t,(e,t)=>this.assetStore.getTokenDecimals(e,t));if(t.transition.type===Q.HomeDeposit||t.transition.type===Q.EscrowDeposit){if(this.requireCheckAllowance&&(await this.getAllowance(t.asset,t.userWallet)).lessThan(t.transition.amount))throw Error(`Allowance is not sufficient to cover the deposit amount`);if(this.requireCheckBalance&&(await this.getTokenBalance(t.asset,t.userWallet)).lessThan(t.transition.amount))throw Error(`Balance is not sufficient to cover the deposit amount`)}console.log(`💳 EVM Client - Create channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});let i;(t.transition.type===Q.HomeDeposit||t.transition.type===Q.EscrowDeposit)&&r.homeLedger.token===`0x0000000000000000000000000000000000000000`&&(i=iy(t.transition.amount,r.homeLedger.decimals)),console.log(`🔍 Simulating transaction...`);try{let{request:e}=await this.evmClient.simulateContract({address:this.contractAddress,abi:ox,functionName:`createChannel`,args:[n,r],account:this.walletSigner.account.address,...i==null?{}:{value:i}});console.log(`✅ Simulation successful - executing transaction...`);let t=await this.walletSigner.writeContract(e);console.log(`📤 Transaction submitted - hash:`,t),console.log(`⏳ Waiting for confirmation...`);let a=await this.evmClient.waitForTransactionReceipt({hash:t});return console.log(`✅ Create channel transaction confirmed!`,{blockNumber:a.blockNumber,gasUsed:a.gasUsed.toString()}),t}catch(e){throw console.error(`❌ Transaction simulation failed!`),console.error(` This means the transaction would revert on-chain.`),e.message&&console.error(` Revert reason:`,e.message),e}}async checkpoint(e){if(!e.homeChannelId)throw Error(`Candidate state must have a home channel ID`);let t=this.hexToBytes32(e.homeChannelId),n=await Qb(e,(e,t)=>this.assetStore.getTokenDecimals(e,t));if(e.transition.type===Q.HomeDeposit){if(this.requireCheckAllowance&&(await this.getAllowance(e.asset,e.userWallet)).lessThan(e.transition.amount))throw Error(`Allowance is not sufficient to cover the deposit amount`);if(this.requireCheckBalance&&(await this.getTokenBalance(e.asset,e.userWallet)).lessThan(e.transition.amount))throw Error(`Balance is not sufficient to cover the deposit amount`);let r=n.homeLedger.token===`0x0000000000000000000000000000000000000000`?iy(e.transition.amount,n.homeLedger.decimals):void 0;console.log(`💳 EVM Client - Deposit to channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id});let i=await this.walletSigner.writeContract({address:this.contractAddress,abi:ox,functionName:`depositToChannel`,args:[t,n],gas:5000000n,...r==null?{}:{value:r}});return console.log(`✅ Deposit to channel transaction hash:`,i),i}if(e.transition.type===Q.HomeWithdrawal){console.log(`💳 EVM Client - Withdraw from channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id});let e=await this.walletSigner.writeContract({address:this.contractAddress,abi:ox,functionName:`withdrawFromChannel`,args:[t,n],gas:5000000n});return console.log(`✅ Withdraw from channel transaction hash:`,e),e}console.log(`💳 EVM Client - Checkpoint channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id});let r=await this.walletSigner.writeContract({address:this.contractAddress,abi:ox,functionName:`checkpointChannel`,args:[t,n],gas:5000000n});return console.log(`✅ Checkpoint channel transaction hash:`,r),r}async challenge(e,t,n=0){if(!e.homeChannelId)throw Error(`Candidate state must have a home channel ID`);let r=this.hexToBytes32(e.homeChannelId),i=await Qb(e,(e,t)=>this.assetStore.getTokenDecimals(e,t));console.log(`💳 EVM Client - Challenge channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:r,walletChain:this.walletSigner.chain?.id});let a=await this.walletSigner.writeContract({address:this.contractAddress,abi:ox,functionName:`challengeChannel`,args:[r,i,t,n],gas:5000000n});return console.log(`✅ Challenge channel transaction hash:`,a),a}async close(e){if(!e.homeChannelId)throw Error(`Candidate state must have a home channel ID`);let t=this.hexToBytes32(e.homeChannelId),n=await Qb(e,(e,t)=>this.assetStore.getTokenDecimals(e,t));if(e.transition.type!==Q.Finalize)throw Error(`Unsupported intent for close`);console.log(`💳 EVM Client - Close channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});let r=await this.walletSigner.writeContract({address:this.contractAddress,abi:ox,functionName:`closeChannel`,args:[t,n],gas:5000000n});return console.log(`✅ Close channel transaction hash:`,r),r}async initiateEscrowDeposit(e,t){throw Error(`initiateEscrowDeposit not implemented - needs contract ABI update`)}async challengeEscrowDeposit(e,t,n=0){throw Error(`challengeEscrowDeposit not implemented - needs contract ABI update`)}async finalizeEscrowDeposit(e){throw Error(`finalizeEscrowDeposit not implemented - needs contract ABI update`)}async initiateEscrowWithdrawal(e,t){throw Error(`initiateEscrowWithdrawal not implemented - needs contract ABI update`)}async challengeEscrowWithdrawal(e,t,n=0){throw Error(`challengeEscrowWithdrawal not implemented - needs contract ABI update`)}async finalizeEscrowWithdrawal(e){throw Error(`finalizeEscrowWithdrawal not implemented - needs contract ABI update`)}async migrateChannelHere(e,t){throw Error(`migrateChannelHere not implemented - needs contract ABI update`)}},cx=[{type:`function`,name:`asset`,inputs:[],outputs:[{name:``,type:`address`}],stateMutability:`view`},{type:`function`,name:`UNLOCK_PERIOD`,inputs:[],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`balanceOf`,inputs:[{name:`user`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`lockStateOf`,inputs:[{name:`user`,type:`address`}],outputs:[{name:``,type:`uint8`}],stateMutability:`view`},{type:`function`,name:`unlockTimestampOf`,inputs:[{name:`user`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`lock`,inputs:[{name:`target`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`relock`,inputs:[],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`unlock`,inputs:[],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`withdraw`,inputs:[{name:`destination`,type:`address`}],outputs:[],stateMutability:`nonpayable`}],lx=class{constructor(e,t,n){this.contractAddress=e,this.evmClient=t,this.walletSigner=n}requireWalletSigner(){if(!this.walletSigner)throw Error(`Write operations require a wallet signer. In Node.js, use a TransactionSigner that implements getAccount() (e.g., EthereumRawSigner)`);return this.walletSigner}async ensureTokenInfo(){if(this.tokenAddress!==void 0&&this.tokenDecimals!==void 0)return{address:this.tokenAddress,decimals:this.tokenDecimals};let e=await this.evmClient.readContract({address:this.contractAddress,abi:cx,functionName:`asset`}),t=await this.evmClient.readContract({address:e,abi:rx,functionName:`decimals`});return this.tokenAddress=e,this.tokenDecimals=t,{address:e,decimals:t}}async lock(e,t){let n=this.requireWalletSigner(),{decimals:r}=await this.ensureTokenInfo(),i=iy(t,r),{request:a}=await this.evmClient.simulateContract({address:this.contractAddress,abi:cx,functionName:`lock`,args:[e,i],account:n.account.address}),o=await n.writeContract(a);return await this.evmClient.waitForTransactionReceipt({hash:o}),o}async relock(){let e=this.requireWalletSigner(),{request:t}=await this.evmClient.simulateContract({address:this.contractAddress,abi:cx,functionName:`relock`,account:e.account.address}),n=await e.writeContract(t);return await this.evmClient.waitForTransactionReceipt({hash:n}),n}async unlock(){let e=this.requireWalletSigner(),{request:t}=await this.evmClient.simulateContract({address:this.contractAddress,abi:cx,functionName:`unlock`,account:e.account.address}),n=await e.writeContract(t);return await this.evmClient.waitForTransactionReceipt({hash:n}),n}async withdraw(e){let t=this.requireWalletSigner(),{request:n}=await this.evmClient.simulateContract({address:this.contractAddress,abi:cx,functionName:`withdraw`,args:[e],account:t.account.address}),r=await t.writeContract(n);return await this.evmClient.waitForTransactionReceipt({hash:r}),r}async approveToken(e){let t=this.requireWalletSigner(),{address:n,decimals:r}=await this.ensureTokenInfo(),i=iy(e,r),{request:a}=await this.evmClient.simulateContract({address:n,abi:rx,functionName:`approve`,args:[this.contractAddress,i],account:t.account.address}),o=await t.writeContract(a);return await this.evmClient.waitForTransactionReceipt({hash:o}),o}async getBalance(e){let{decimals:t}=await this.ensureTokenInfo();return new P((await this.evmClient.readContract({address:this.contractAddress,abi:cx,functionName:`balanceOf`,args:[e]})).toString()).div(P.pow(10,t))}async getLockState(e){return await this.evmClient.readContract({address:this.contractAddress,abi:cx,functionName:`lockStateOf`,args:[e]})}async getTokenDecimals(){let{decimals:e}=await this.ensureTokenInfo();return e}},ux=86400;function dx(e){if(e.length<6)throw Error(`signature too short to contain a signer type prefix: ${e}`);let t=parseInt(e.slice(2,4),16);if(t!==Jv.Default)throw Error(`expected ChannelDefaultSigner prefix 0x00, got 0x${t.toString(16).padStart(2,`0`)}; session key signing requires the default wallet signer, not a session key signer`);return`0x${e.slice(4)}`}var fx=class e{constructor(e,t,n,r,i){this.rpcClient=e,this.config=t,this.stateSigner=n,this.txSigner=r,this.assetStore=i,this.blockchainClients=new Map,this.blockchainLockingClients=new Map,this.homeBlockchains=new Map,this.stateAdvancer=new Py(i),this.exitPromise=new Promise(e=>{this.exitResolve=e})}static async create(t,n,r,...i){let a={url:t,handshakeTimeout:Ab.handshakeTimeout,pingInterval:Ab.pingInterval,errorHandler:Ab.errorHandler,blockchainRPCs:Ab.blockchainRPCs||new Map};for(let e of i)e(a);let o=new Tb(new Db),s;return s=new e(o,a,n,r,new Ob(async()=>await s.getAssets())),await o.start(t,e=>{e&&a.errorHandler&&a.errorHandler(e),s.exitResolve?.()}),s}async setHomeBlockchain(e,t){let n=this.homeBlockchains.get(e);if(n!==void 0)throw Error(`home blockchain is already set for asset ${e} to ${n}, please use Migrate() if you want to change home blockchain`);if(!await this.assetStore.assetExistsOnBlockchain(t,e))throw Error(`asset ${e} not supported on blockchain ${t}`);this.homeBlockchains.set(e,t)}async close(){this.exitResolve?.()}waitForClose(){return this.exitPromise}async signState(e){let t=await My(e,this.assetStore);return await this.stateSigner.signMessage(t)}getUserAddress(){return this.stateSigner.getAddress()}async validateAndSignState(e,t){return await this.stateAdvancer.validateAdvancement(e,t),this.signState(t)}async signAndSubmitState(e,t){t.userSig=await this.validateAndSignState(e,t);let n=await this.submitState(t);return t.nodeSig=n,n}async deposit(e,t,n){let r=this.getUserAddress(),i=await this.getNodeAddress();if(!i)throw Error(`node address is undefined - ensure node config is properly loaded`);let a=await this.assetStore.getTokenAddress(t,e);if(!a)throw Error(`token address not found for asset ${t} on blockchain ${e}`);let o=null,s=!1;try{o=await this.getLatestState(r,t,!1),o&&o.homeChannelId&&(s=o.transition.type!==Q.Finalize)}catch{}if(!o||!s){let s=await this.getSupportedSigValidatorsBitmap(),c={nonce:Mb(),challenge:ux,approvedSigValidators:s};o||=Zv(t,r);let l=_y(o);return vy(l,c,e,a,i),by(l,n),l.userSig=await this.signState(l),l.nodeSig=await this.requestChannelCreation(l,c),l}let c=_y(o);return by(c,n),await this.signAndSubmitState(o,c),c}async withdraw(e,t,n){let r=this.getUserAddress(),i=await this.getNodeAddress();if(!i)throw Error(`node address is undefined - ensure node config is properly loaded`);let a=await this.assetStore.getTokenAddress(t,e);if(!a)throw Error(`token address not found for asset ${t} on blockchain ${e}`);let o=null,s=!1;try{o=await this.getLatestState(r,t,!1),o&&o.homeChannelId&&(s=o.transition.type!==Q.Finalize)}catch{}if(!o||!s){let s=await this.getSupportedSigValidatorsBitmap(),c={nonce:Mb(),challenge:ux,approvedSigValidators:s};o||=Zv(t,r);let l=_y(o);return vy(l,c,e,a,i),xy(l,n),l.userSig=await this.signState(l),l.nodeSig=await this.requestChannelCreation(l,c),l}let c=_y(o);return xy(c,n),await this.signAndSubmitState(o,c),c}async transfer(e,t,n){let r=this.getUserAddress(),i=null;try{i=await this.getLatestState(r,t,!1)}catch{}if(!i){let a=await this.getSupportedSigValidatorsBitmap(),o={nonce:Mb(),challenge:ux,approvedSigValidators:a};i||=Zv(t,r);let s=_y(i),c=this.homeBlockchains.get(t);c||=i.homeLedger.blockchainId===0n?await this.assetStore.getSuggestedBlockchainId(t):i.homeLedger.blockchainId;let l=await this.getNodeAddress();if(!l)throw Error(`node address is undefined - ensure node config is properly loaded`);let u=await this.assetStore.getTokenAddress(t,c);if(!u)throw Error(`token address not found for asset ${t} on blockchain ${c}`);return vy(s,o,c,u,l),Sy(s,e,n),s.userSig=await this.signState(s),s.nodeSig=await this.requestChannelCreation(s,o),s}let a=_y(i);return Sy(a,e,n),await this.signAndSubmitState(i,a),a}async acknowledge(e){let t=this.getUserAddress(),n=null;try{n=await this.getLatestState(t,e,!1)}catch{}if(!n){let r=await this.getSupportedSigValidatorsBitmap(),i={nonce:Mb(),challenge:ux,approvedSigValidators:r};n||=Zv(e,t);let a=_y(n),o=this.homeBlockchains.get(e);o||=n.homeLedger.blockchainId===0n?await this.assetStore.getSuggestedBlockchainId(e):n.homeLedger.blockchainId;let s=await this.getNodeAddress();if(!s)throw Error(`node address is undefined - ensure node config is properly loaded`);let c=await this.assetStore.getTokenAddress(e,o);if(!c)throw Error(`token address not found for asset ${e} on blockchain ${o}`);return vy(a,i,o,c,s),yy(a),a.userSig=await this.signState(a),a.nodeSig=await this.requestChannelCreation(a,i),a}if(n.userSig)throw Error(`state already acknowledged by user`);let r=_y(n);return yy(r),await this.signAndSubmitState(n,r),r}async closeHomeChannel(e){let t=this.getUserAddress(),n=await this.getLatestState(t,e,!1);if(!n.homeChannelId)throw Error(`no channel exists for asset ${e}`);let r=_y(n);return ky(r),await this.signAndSubmitState(n,r),r}async checkpoint(e){let t=this.getUserAddress(),n=await this.getLatestState(t,e,!0);if(!n.homeChannelId)throw Error(`no channel exists for asset ${e}`);let r=n.homeLedger.blockchainId;await this.initializeBlockchainClient(r);let i=this.blockchainClients.get(r),a=await this.getHomeChannel(t,e);switch(n.transition.type){case Q.Acknowledgement:case Q.HomeDeposit:case Q.HomeWithdrawal:case Q.TransferSend:case Q.TransferReceive:case Q.Commit:case Q.Release:if(a.status===Yv.Void){let e={nonce:a.nonce,challenge:a.challengeDuration,approvedSigValidators:a.approvedSigValidators};return await i.create(e,n)}return await i.checkpoint(n);case Q.Finalize:return await i.close(n);default:throw Error(`transition type ${n.transition.type} does not require a blockchain operation`)}}async challenge(e){if(!e.userSig||!e.nodeSig)throw Error(`state must have both user and node signatures`);if(!e.homeChannelId)throw Error(`state must have a home channel ID`);let t=await My(e,this.assetStore),n=`0x${e.userSig.slice(4)}`;if(!await g_({address:e.userWallet,message:{raw:t},signature:n}))throw Error(`invalid user signature`);let r=await this.getNodeAddress(),i=`0x${e.nodeSig.slice(4)}`;if(!await g_({address:r,message:{raw:t},signature:i}))throw Error(`invalid node signature`);let a=await Ny(e,this.assetStore),o=await this.stateSigner.signMessage(a),s=e.homeLedger.blockchainId;return await this.initializeBlockchainClient(s),await this.blockchainClients.get(s).challenge(e,o)}async approveToken(e,t,n){return await this.initializeBlockchainClient(e),await this.blockchainClients.get(e).approve(t,n)}async getOnChainBalance(e,t,n){return await this.initializeBlockchainClient(e),await this.blockchainClients.get(e).getTokenBalance(t,n)}async checkTokenAllowance(e,t,n){return await this.initializeBlockchainClient(e),await this.blockchainClients.get(e).checkAllowanceByAddress(t,n)}async escrowSecurityTokens(e,t,n){return await this.initializeLockingClient(t),this.blockchainLockingClients.get(t).lock(e,n)}async initiateSecurityTokensWithdrawal(e){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).unlock()}async cancelSecurityTokensWithdrawal(e){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).relock()}async withdrawSecurityTokens(e,t){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).withdraw(t)}async approveSecurityToken(e,t){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).approveToken(t)}async getLockedBalance(e,t){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).getBalance(t)}async ping(){await this.rpcClient.nodeV1Ping()}async getConfig(){return Pb(await this.rpcClient.nodeV1GetConfig())}async getBlockchains(){return(await this.getConfig()).blockchains}async getAssets(e){let t={};return e!==void 0&&(t.blockchain_id=e),Fb((await this.rpcClient.nodeV1GetAssets(t)).assets)}async getBalances(e){let t={wallet:e};return Ib((await this.rpcClient.userV1GetBalances(t)).balances)}async getTransactions(e,t){let n={wallet:e,asset:t?.asset,tx_type:t?.txType,from_time:t?.fromTime,to_time:t?.toTime,pagination:t?.page&&t?.pageSize?{offset:(t.page-1)*t.pageSize,limit:t.pageSize}:void 0},r=await this.rpcClient.userV1GetTransactions(n);return{transactions:r.transactions.map(Ub),metadata:Wb(r.metadata)}}async getActionAllowances(e){let t={wallet:e};return(await this.rpcClient.userV1GetActionAllowances(t)).allowances.map(Gb)}async getChannels(e,t){let n={wallet:e,status:t?.status,asset:t?.asset,channel_type:t?.channelType,pagination:t?.pagination?{offset:t.pagination.offset,limit:t.pagination.limit}:void 0},r=await this.rpcClient.channelsV1GetChannels(n);return{channels:r.channels.map(zb),metadata:Wb(r.metadata)}}async getHomeChannel(e,t){let n={wallet:e,asset:t};return zb((await this.rpcClient.channelsV1GetHomeChannel(n)).channel)}async getEscrowChannel(e){let t={escrow_channel_id:e};return zb((await this.rpcClient.channelsV1GetEscrowChannel(t)).channel)}async getLatestState(e,t,n){let r={wallet:e,asset:t,only_signed:n};return Hb((await this.rpcClient.channelsV1GetLatestState(r)).state)}async getAppSessions(e){let t={app_session_id:e?.appSessionId,participant:e?.wallet,status:e?.status,pagination:e?.page&&e?.pageSize?{offset:(e.page-1)*e.pageSize,limit:e.pageSize}:void 0},n=await this.rpcClient.appSessionsV1GetAppSessions(t);return{sessions:n.app_sessions.map(Yb),metadata:Wb(n.metadata)}}async getAppDefinition(e){let t={app_session_id:e};return Xb((await this.rpcClient.appSessionsV1GetAppDefinition(t)).definition)}async createAppSession(e,t,n,r){let i={definition:Kb(e),session_data:t,quorum_sigs:n};r?.ownerSig&&(i.owner_sig=r.ownerSig);let a=await this.rpcClient.appSessionsV1CreateAppSession(i);return{appSessionId:a.app_session_id,version:a.version,status:a.status}}async submitAppSessionDeposit(e,t,n,r){let i=_y(await this.getLatestState(this.getUserAddress(),n,!1));Cy(i,e.appSessionId,r);let a=qb(e);i.userSig=await this.signState(i);let o={app_state_update:a,quorum_sigs:t,user_state:this.transformStateToRPC(i)};return(await this.rpcClient.appSessionsV1SubmitDepositState(o)).signature}async submitAppState(e,t){let n={app_state_update:qb(e),quorum_sigs:t};await this.rpcClient.appSessionsV1SubmitAppState(n)}async rebalanceAppSessions(e){let t={signed_updates:e.map(Jb)};return(await this.rpcClient.appSessionsV1RebalanceAppSessions(t)).batch_id}async getApps(e){let t={app_id:e?.appId,owner_wallet:e?.ownerWallet,pagination:e?.page&&e?.pageSize?{offset:(e.page-1)*e.pageSize,limit:e.pageSize}:void 0},n=await this.rpcClient.appsV1GetApps(t);return{apps:n.apps,metadata:Wb(n.metadata)}}async registerApp(e,t,n){let r={id:e,owner_wallet:this.txSigner.getAddress(),metadata:t,version:`1`,creation_approval_not_required:n},i=Ly(r);if(!this.txSigner.signPersonalMessage)throw Error(`TransactionSigner must implement signPersonalMessage for app registration`);let a={app:r,owner_sig:await this.txSigner.signPersonalMessage(i)};await this.rpcClient.appsV1SubmitAppVersion(a)}async signChannelSessionKeyState(e){let t=my(BigInt(e.version),e.assets,BigInt(e.expires_at)),n=hy(e.session_key,t);return dx(await this.stateSigner.signMessage(n))}async submitChannelSessionKeyState(e){let t={state:e};await this.rpcClient.channelsV1SubmitSessionKeyState(t)}async getLastChannelKeyStates(e,t){let n={user_address:e,session_key:t};return(await this.rpcClient.channelsV1GetLastKeyStates(n)).states}async signSessionKeyState(e){let t=zy(e);return dx(await this.stateSigner.signMessage(t))}async submitSessionKeyState(e){let t={state:e};await this.rpcClient.appSessionsV1SubmitSessionKeyState(t)}async getLastKeyStates(e,t){let n={user_address:e,session_key:t};return(await this.rpcClient.appSessionsV1GetLastKeyStates(n)).states}async getBlockchainRPCInfo(e){let t=this.config.blockchainRPCs?.get(e);if(!t)throw Error(`blockchain RPC not configured for chain ${e} (use withBlockchainRPC)`);let n=await this.getConfig(),r=n.blockchains.find(t=>t.id===e);if(!r)throw Error(`blockchain ${e} not found in node config`);return{rpcUrl:t,blockchainInfo:r,config:n}}createEVMClients(e,t){let n=bv({transport:Gv(t)}),r={id:Number(e),name:`Chain ${e}`,nativeCurrency:{name:`ETH`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[t]},public:{http:[t]}}},i=typeof window<`u`&&window.ethereum!==void 0,a=null;if(i)a=Vv({chain:r,transport:Uv(window.ethereum),account:this.txSigner.getAddress()});else{let e=this.txSigner.getAccount?this.txSigner.getAccount():void 0;e&&(a=Vv({chain:r,transport:Gv(t),account:e}))}return{publicClient:n,walletClient:a}}async initializeBlockchainClient(e){if(this.blockchainClients.has(e))return;let{rpcUrl:t,blockchainInfo:n,config:r}=await this.getBlockchainRPCInfo(e);if(!n.channelHubAddress)throw Error(`channel hub address not configured for blockchain ${e}`);let{publicClient:i,walletClient:a}=this.createEVMClients(e,t);if(!a)throw Error(`Node.js environment requires a TransactionSigner that implements getAccount() (e.g., EthereumRawSigner)`);let o=new sx(n.channelHubAddress,i,a,e,r.nodeAddress,this.assetStore);this.blockchainClients.set(e,o)}async initializeLockingClient(e){if(this.blockchainLockingClients.has(e))return;let{rpcUrl:t,blockchainInfo:n}=await this.getBlockchainRPCInfo(e);if(!n.lockingContractAddress)throw Error(`locking contract address not configured for blockchain ${e}`);let{publicClient:r,walletClient:i}=this.createEVMClients(e,t),a=new lx(n.lockingContractAddress,r,i||void 0);this.blockchainLockingClients.set(e,a)}buildSigValidatorsBitmap(e){let t=new Uint8Array(32);for(let n of e){let e=n&255;t[31-Math.floor(e/8)]|=1<e.toString(16).padStart(2,`0`)).join(``);return`0x00`}async getSupportedSigValidatorsBitmap(){let e=await this.getConfig();return this.buildSigValidatorsBitmap(e.supportedSigValidators)}async getNodeAddress(){return(await this.getConfig()).nodeAddress}async submitState(e){let t={state:this.transformStateToRPC(e)};return(await this.rpcClient.channelsV1SubmitState(t)).signature}async requestChannelCreation(e,t){let n={state:this.transformStateToRPC(e),channel_definition:this.transformChannelDefinitionToRPC(t)};return(await this.rpcClient.channelsV1RequestCreation(n)).signature}transformStateToRPC(e){return{id:e.id,transition:{type:e.transition.type,tx_id:e.transition.txId,account_id:e.transition.accountId||``,amount:e.transition.amount.toString()},asset:e.asset,user_wallet:e.userWallet,epoch:e.epoch.toString(),version:e.version.toString(),home_channel_id:e.homeChannelId,escrow_channel_id:e.escrowChannelId,home_ledger:{token_address:e.homeLedger.tokenAddress,blockchain_id:e.homeLedger.blockchainId.toString(),user_balance:e.homeLedger.userBalance.toString(),user_net_flow:e.homeLedger.userNetFlow.toString(),node_balance:e.homeLedger.nodeBalance.toString(),node_net_flow:e.homeLedger.nodeNetFlow.toString()},escrow_ledger:e.escrowLedger?{token_address:e.escrowLedger.tokenAddress,blockchain_id:e.escrowLedger.blockchainId.toString(),user_balance:e.escrowLedger.userBalance.toString(),user_net_flow:e.escrowLedger.userNetFlow.toString(),node_balance:e.escrowLedger.nodeBalance.toString(),node_net_flow:e.escrowLedger.nodeNetFlow.toString()}:void 0,user_sig:e.userSig,node_sig:e.nodeSig}}transformChannelDefinitionToRPC(e){return{nonce:e.nonce.toString(),challenge:e.challenge,approved_sig_validators:e.approvedSigValidators}}transitionTypeToString(e){return{[Q.Void]:`void`,[Q.Acknowledgement]:`acknowledgement`,[Q.HomeDeposit]:`home_deposit`,[Q.HomeWithdrawal]:`home_withdrawal`,[Q.EscrowDeposit]:`escrow_deposit`,[Q.EscrowWithdraw]:`escrow_withdraw`,[Q.TransferSend]:`transfer_send`,[Q.TransferReceive]:`transfer_receive`,[Q.Commit]:`commit`,[Q.Release]:`release`,[Q.Migrate]:`migrate`,[Q.EscrowLock]:`escrow_lock`,[Q.MutualLock]:`mutual_lock`,[Q.Finalize]:`finalize`}[e]||`home_deposit`}};function px(e){if(typeof e==`string`){if(!ra(e,{strict:!1}))throw new Xi({address:e});return{address:e,type:`json-rpc`}}if(!ra(e.address,{strict:!1}))throw new Xi({address:e.address});return{address:e.address,nonceManager:e.nonceManager,sign:e.sign,signAuthorization:e.signAuthorization,signMessage:e.signMessage,signTransaction:e.signTransaction,signTypedData:e.signTypedData,source:`custom`,type:`local`}}var mx=!1;async function hx({hash:e,privateKey:t,to:n=`object`}){let{r,s:i,recovery:a}=Wg.sign(e.slice(2),t.slice(2),{lowS:!0,extraEntropy:xr(mx,{strict:!1})?Ci(mx):mx}),o={r:L(r,{size:32}),s:L(i,{size:32}),v:a?28n:27n,yParity:a};return n===`bytes`||n===`hex`?ev({...o,to:n}):o}async function gx(e){let{chainId:t,nonce:n,privateKey:r,to:i=`object`}=e,a=e.contractAddress??e.address,o=await hx({hash:ks({address:a,chainId:t,nonce:n}),privateKey:r,to:i});return i===`object`?{address:a,chainId:t,nonce:n,...o}:o}async function _x({message:e,privateKey:t}){return await hx({hash:Xf(e),privateKey:t,to:`hex`})}async function vx(e){let{privateKey:t,transaction:n,serializer:r=Of}=e;return await r(n,await hx({hash:z(await r(n.type===`eip4844`?{...n,sidecars:!1}:n)),privateKey:t}))}async function yx(e){let{privateKey:t,...n}=e;return await hx({hash:ip(n),privateKey:t,to:`hex`})}function bx(e,t={}){let{nonceManager:n}=t,r=pi(Wg.getPublicKey(e.slice(2),!1));return{...px({address:gs(r),nonceManager:n,async sign({hash:t}){return hx({hash:t,privateKey:e,to:`hex`})},async signAuthorization(t){return gx({...t,privateKey:e})},async signMessage({message:t}){return _x({message:t,privateKey:e})},async signTransaction(t,{serializer:n}={}){return vx({privateKey:e,transaction:t,serializer:n})},async signTypedData(t){return yx({...t,privateKey:e})}}),publicKey:r,source:`privateKey`}}var xx=class{constructor(e){this.inner=e}getAddress(){return this.inner.getAddress()}async signMessage(e){return`0x00${(await this.inner.signMessage(e)).slice(2)}`}},Sx=class{constructor(e,t,n,r){this.account=bx(e),this.walletAddress=t,this.metadataHash=n,this.authSignature=r}getAddress(){return this.walletAddress}getSessionKeyAddress(){return this.account.address}async signMessage(e){let t=await this.account.signMessage({message:{raw:e}});return`0x01${ma([{type:`tuple`,components:[{name:`sessionKey`,type:`address`},{name:`metadataHash`,type:`bytes32`},{name:`authSignature`,type:`bytes`}]},{type:`bytes`}],[{sessionKey:this.account.address,metadataHash:this.metadataHash,authSignature:this.authSignature},t]).slice(2)}`}},Cx;(function(e){e.Ping=`ping`,e.GetConfig=`get_config`,e.GetChannels=`get_channels`,e.ChannelsUpdate=`channels_update`,e.ChannelUpdate=`channel_update`,e.BalanceUpdate=`balance_update`,e.GetAssets=`get_assets`,e.Assets=`assets`,e.GetLedgerBalances=`get_ledger_balances`,e.GetLedgerEntries=`get_ledger_entries`,e.GetAppSessions=`get_app_sessions`,e.CreateChannel=`create_channel`,e.CloseChannel=`close_channel`,e.ResizeChannel=`resize_channel`,e.Transfer=`transfer`,e.CreateAppSession=`create_app_session`,e.CloseAppSession=`close_app_session`,e.SubmitAppState=`submit_app_state`,e.GetAppDefinition=`get_app_definition`,e.AuthRequest=`auth_request`,e.AuthChallenge=`auth_challenge`,e.AuthVerify=`auth_verify`,e.Error=`error`,e.GetLedgerTransactions=`get_ledger_transactions`,e.TransferNotification=`tr`})(Cx||={});var wx;(function(e){e.Open=`open`,e.Closed=`closed`,e.Resizing=`resizing`,e.Challenged=`challenged`})(wx||={});var Tx;(function(e){e.NitroRPC_0_2=`NitroRPC/0.2`,e.NitroRPC_0_4=`NitroRPC/0.4`})(Tx||={});var Ex;(function(e){e.Operate=`operate`,e.Deposit=`deposit`,e.Withdraw=`withdraw`})(Ex||={});var Dx;(function(e){e.Transfer=`transfer`,e.Deposit=`deposit`,e.Withdrawal=`withdrawal`,e.AppDeposit=`app_deposit`,e.AppWithdrawal=`app_withdrawal`,e.EscrowLock=`escrow_lock`,e.EscrowUnlock=`escrow_unlock`})(Dx||={});function Ox(e){let t=[];if(e.blockchainRPCs)for(let[n,r]of Object.entries(e.blockchainRPCs))t.push(jb(BigInt(n),r));return t}var kx=class extends Error{constructor(e,t){super(e),this.name=`CompatError`,this.code=t}},Ax=class extends kx{constructor(e){super(e,`ALLOWANCE_INSUFFICIENT`),this.name=`AllowanceError`}},jx=class extends kx{constructor(e){super(e,`USER_REJECTED`),this.name=`UserRejectedError`}},Mx=class extends kx{constructor(e){super(e,`INSUFFICIENT_FUNDS`),this.name=`InsufficientFundsError`}},Nx=class extends kx{constructor(e){super(e,`NOT_INITIALIZED`),this.name=`NotInitializedError`}},Px=class extends kx{constructor(e){super(e,`ONGOING_STATE_TRANSITION`),this.name=`OngoingStateTransitionError`}},Fx=class{constructor(e){this.walletClient=e}getAddress(){if(!this.walletClient.account?.address)throw Error(`Wallet has no account`);return this.walletClient.account.address}async signMessage(e){if(!this.walletClient.account)throw Error(`Wallet has no account`);return this.walletClient.signMessage({account:this.walletClient.account,message:{raw:e}})}},Ix=class{constructor(e){this.walletClient=e}getAddress(){if(!this.walletClient.account?.address)throw Error(`Wallet has no account`);return this.walletClient.account.address}async sendTransaction(e){throw Error(`Use the blockchain client for transactions`)}async signMessage(e){if(!this.walletClient.account)throw Error(`Wallet has no account`);let t=this.walletClient.chain;return this.walletClient.signTypedData({account:this.walletClient.account,domain:{name:`Nitrolite`,version:`1`,chainId:t?.id??1},types:{Message:[{name:`data`,type:`bytes32`}]},primaryType:`Message`,message:{data:e.raw}})}},Lx=class e{constructor(e,t,n,r){this.assetsByToken=new Map,this.assetsBySymbol=new Map,this._lastChannels=[],this._lastAppSessionsListError=null,this._lastAppSessionsListErrorLogged=null,this._blockchains=null,this._lockingTokenDecimals=new Map,this.innerClient=e,this.userAddress=t,this._chainId=BigInt(n),this._blockchainRPCs=r??{}}static async create(t){let n=t.walletClient.account?.address;if(!n)throw Error(`WalletClient must have an account`);let r;if(t.channelSessionKeySigner){let e=t.channelSessionKeySigner.walletAddress;if(e.toLowerCase()!==n.toLowerCase())throw Error(`channelSessionKeySigner wallet ${e} does not match walletClient account ${n}`);r=new Sx(t.channelSessionKeySigner.sessionKeyPrivateKey,e,t.channelSessionKeySigner.metadataHash,t.channelSessionKeySigner.authSig)}else r=new xx(new Fx(t.walletClient));let i=new Ix(t.walletClient),a=Ox({wsURL:t.wsURL,blockchainRPCs:t.blockchainRPCs}),o=new e(await fx.create(t.wsURL,r,i,...a),n,t.chainId,t.blockchainRPCs);try{await o.refreshAssets()}catch{console.warn(`[compat] Could not pre-load asset map; will retry on demand`)}return o}async refreshAssets(){let e=await this.innerClient.getAssets();this.assetsByToken.clear(),this.assetsBySymbol.clear();for(let t of e)for(let e of t.tokens){let n={symbol:t.symbol,chainId:e.blockchainId,decimals:t.decimals,tokenAddress:e.address.toLowerCase()};this.assetsByToken.set(n.tokenAddress,n),e.blockchainId===this._chainId&&this.assetsBySymbol.set(t.symbol.toLowerCase(),n)}}async ensureAssets(){this.assetsByToken.size===0&&await this.refreshAssets()}async getDecimalsForAsset(e){await this.ensureAssets();let t=this.assetsBySymbol.get(e.toLowerCase());return t||console.warn(`[compat] Unknown asset symbol ${e}, falling back to 6 decimals`),t?.decimals??6}async resolveToken(e){await this.ensureAssets();let t=e.toString().toLowerCase(),n=this.assetsByToken.get(t);if(!n)throw Error(`Unknown token address: ${e}`);return n}async resolveAsset(e){await this.ensureAssets();let t=this.assetsBySymbol.get(e.toLowerCase());if(!t)throw Error(`Unknown asset: ${e}`);return t}async getTokenDecimals(e){await this.ensureAssets();let t=e.toString().toLowerCase(),n=this.assetsByToken.get(t);return n||console.warn(`[compat] Unknown token ${e}, falling back to 6 decimals`),n?.decimals??6}async formatAmount(e,t){return U(t,await this.getTokenDecimals(e))}async parseAmount(e,t){return v_(t,await this.getTokenDecimals(e))}async resolveAssetDisplay(e,t){await this.ensureAssets();let n=e.toString().toLowerCase(),r=this.assetsByToken.get(n);return r?{symbol:r.symbol,decimals:r.decimals}:null}findOpenChannel(e,t){let n=e.toString().toLowerCase();return this._lastChannels.find(e=>{let r=e.status===`open`||e.status===`resizing`,i=e.token.toLowerCase()===n,a=t===void 0||e.chain_id===t;return r&&i&&a})??null}async getAccountInfo(){return{balances:await this.getBalances(),channelCount:BigInt(this._lastChannels.length)}}static classifyError(e){let t=e instanceof Error?e.message:String(e),n=t.toLowerCase();return n.includes(`allowance`)&&n.includes(`insufficient`)?new Ax(t):n.includes(`user rejected`)||n.includes(`user denied`)?new jx(t):n.includes(`insufficient funds`)||n.includes(`exceeds balance`)?new Mx(t):n.includes(`not initialized`)||n.includes(`not connected`)?new Nx(t):n.includes(`ongoing`)||n.includes(`state transition`)?new Px(t):e instanceof Error?e:Error(t)}async checkpointWithApproval(t,n,r){try{return await this.innerClient.checkpoint(t)}catch(i){let a=e.classifyError(i);if(!(a instanceof Ax))throw a;return console.log(`[compat] Allowance insufficient, requesting token approval…`),await this.innerClient.approveToken(n,r,e.DEFAULT_APPROVE_AMOUNT),await this.innerClient.checkpoint(t)}}toHumanAmount(e,t){return new P(e.toString()).div(new P(10).pow(t))}async deposit(e,t){let{symbol:n,chainId:r,decimals:i,tokenAddress:a}=await this.resolveToken(e);await this.innerClient.setHomeBlockchain(n,r).catch(()=>{});let o=this.toHumanAmount(t,i);return await this.innerClient.deposit(r,n,o),await this.checkpointWithApproval(n,r,a)}async depositAndCreateChannel(e,t,n){return this.deposit(e,t)}async createChannel(e){console.warn(`[compat] createChannel is implicit in v1 -- use deposit() instead`)}async closeChannel(e){let t=e?.tokenAddress?.toString().toLowerCase();if(t){await this.ensureAssets();let n=this.assetsByToken.get(t);if(!n)throw Error(`Unknown token address for close: ${e.tokenAddress}`);await this.innerClient.closeHomeChannel(n.symbol),await this.checkpointWithApproval(n.symbol,n.chainId,n.tokenAddress);return}let n=(await this.getChannels()).filter(e=>e.status===`open`||e.status===`resizing`);for(let e of n)try{await this.ensureAssets();let t=this.assetsByToken.get(e.token.toLowerCase()),n=t?.symbol;if(!n)continue;await this.innerClient.closeHomeChannel(n),await this.checkpointWithApproval(n,t.chainId,t.tokenAddress)}catch{}}async resizeChannel(e){return this.deposit(e.token,e.allocate_amount)}async challengeChannel(e){return this.innerClient.challenge(e.state)}async withdrawal(e,t){let{symbol:n,chainId:r,decimals:i,tokenAddress:a}=await this.resolveToken(e);await this.innerClient.setHomeBlockchain(n,r).catch(()=>{});let o=this.toHumanAmount(t,i);return await this.innerClient.withdraw(r,n,o),await this.checkpointWithApproval(n,r,a)}async getChannelData(e){await this.ensureAssets();for(let[,t]of this.assetsBySymbol)try{let n=await this.innerClient.getHomeChannel(this.userAddress,t.symbol);if(n.channelId===e)return{channel:n,state:await this.innerClient.getLatestState(this.userAddress,t.symbol,!1)}}catch{}throw Error(`Channel ${e} not found`)}async getChannels(){try{this._lastChannels=await this.getChannelsViaRPC()}catch{this._lastChannels=await this.getChannelsViaAssetScan()}return this._lastChannels}async getChannelsViaRPC(){let{channels:t}=await this.innerClient.getChannels(this.userAddress),n=[];for(let r of t){let t=0n;if(r.status===1)try{let e=(await this.innerClient.getLatestState(this.userAddress,r.asset,!1)).homeLedger?.userBalance;if(e){let n=this.assetsBySymbol.get(r.asset.toLowerCase())?.decimals??6;t=BigInt(e.mul(new P(10).pow(n)).toFixed(0))}}catch{}n.push({channel_id:r.channelId,participant:r.userWallet??this.userAddress,status:e.STATUS_MAP[r.status]??String(r.status),token:r.tokenAddress??``,amount:t,chain_id:Number(r.blockchainId??0),adjudicator:``,challenge:r.challengeDuration??0,nonce:Number(r.nonce??0),version:Number(r.stateVersion??0),created_at:``,updated_at:``})}return n}async getChannelsViaAssetScan(){let t=await this.innerClient.getAssets(),n=[];for(let r of t)try{let t=await this.innerClient.getHomeChannel(this.userAddress,r.symbol);if(t.channelId){let i=0n;try{let e=(await this.innerClient.getLatestState(this.userAddress,r.symbol,!1)).homeLedger?.userBalance;if(e){let t=this.assetsBySymbol.get(r.symbol.toLowerCase())?.decimals??r.decimals;i=BigInt(e.mul(new P(10).pow(t)).toFixed(0))}}catch{}let a=Number(t.blockchainId??r.tokens?.[0]?.blockchainId??0);n.push({channel_id:t.channelId,participant:this.userAddress,status:e.STATUS_MAP[t.status]??String(t.status),token:t.tokenAddress||r.tokens?.[0]?.address||``,amount:i,chain_id:a,adjudicator:``,challenge:t.challengeDuration??0,nonce:Number(t.nonce??0),version:Number(t.stateVersion??0),created_at:``,updated_at:``})}}catch{}return n}async getBalances(e){return(await this.innerClient.getBalances(e??this.userAddress)).map(e=>{let t=this.assetsBySymbol.get(e.asset.toLowerCase())?.decimals??6,n=e.balance.mul(new P(10).pow(t)).toFixed(0);return{asset:e.asset,amount:n}})}async getLedgerEntries(e){let{transactions:t}=await this.innerClient.getTransactions(e??this.userAddress);return t.map((t,n)=>({id:n,account_id:e??this.userAddress,account_type:0,asset:t.asset,participant:e??this.userAddress,credit:t.amount.greaterThanOrEqualTo(0)?t.amount.toString():`0`,debit:t.amount.lessThan(0)?t.amount.abs().toString():`0`,created_at:t.createdAt?.toISOString?.()??``}))}async getAppSessionsList(e,t){let n=e=>e.map(e=>({app_session_id:e.appSessionId,nonce:Number(e.nonce??0),participants:e.participants.map(e=>e.walletAddress),protocol:``,quorum:e.quorum,status:e.isClosed?`closed`:`open`,version:Number(e.version??0),weights:e.participants.map(e=>e.signatureWeight),allocations:e.allocations?.map(e=>{let t=this.assetsBySymbol.get(e.asset?.toLowerCase?.()??``)?.decimals??6,n=e.amount?e.amount.mul(new P(10).pow(t)).toFixed(0):`0`;return{participant:e.participant,asset:e.asset,amount:n}})??[],sessionData:e.sessionData??``})),r=(e??this.userAddress).toLowerCase(),i=t?.toLowerCase(),a=i&&i!==`any`?i:void 0,o=a?{wallet:r,status:a}:{wallet:r};try{console.info(`[compat] getAppSessionsList request`,{participant:r,status:a??`any`,rawStatus:t??null});let{sessions:e}=await this.innerClient.getAppSessions(o);return console.info(`[compat] getAppSessionsList success count=${e.length}`),this._lastAppSessionsListError=null,n(e)}catch(e){if(a)try{console.warn(`[compat] getAppSessionsList retrying without status filter participant=${r} status=${a}`);let{sessions:e}=await this.innerClient.getAppSessions({wallet:r}),t=n(e).filter(e=>e.status===a);return console.info(`[compat] getAppSessionsList success count=${t.length} (fallback without status)`),this._lastAppSessionsListError=null,t}catch{}let t=e instanceof Error?e.message:String(e);return this._lastAppSessionsListError=t,this._lastAppSessionsListErrorLogged!==t&&(console.warn(`[compat] getAppSessionsList failed participant=${r} status=${a??`any`} error=${t}`),this._lastAppSessionsListErrorLogged=t),[]}}getLastAppSessionsListError(){return this._lastAppSessionsListError}async getAssetsList(){let e=await this.innerClient.getAssets(),t=[];for(let n of e)for(let e of n.tokens)t.push({token:e.address,chainId:Number(e.blockchainId),symbol:n.symbol,decimals:n.decimals});return t}async getConfig(){return this.innerClient.getConfig()}async signChannelSessionKeyState(e){return this.innerClient.signChannelSessionKeyState(e)}async submitChannelSessionKeyState(e){await this.innerClient.submitChannelSessionKeyState(e)}async getLastChannelKeyStates(e,t){return this.innerClient.getLastChannelKeyStates(e,t)}async signSessionKeyState(e){return this.innerClient.signSessionKeyState(e)}async submitSessionKeyState(e){await this.innerClient.submitSessionKeyState(e)}async getLastKeyStates(e,t){return this.innerClient.getLastKeyStates(e,t)}async createAppSession(e,t,n,r){let i=`definition`in e?e.definition:e,a=`definition`in e?e.allocations:t??[],o=`definition`in e?e.quorum_sigs??[]:n??[],s=`definition`in e?e.session_data??JSON.stringify({allocations:a}):JSON.stringify({allocations:a}),c=`definition`in e?e.owner_sig??r?.ownerSig:r?.ownerSig,l={applicationId:i.application||``,participants:i.participants.map((e,t)=>({walletAddress:e,signatureWeight:i.weights[t]??1})),quorum:i.quorum,nonce:BigInt(i.nonce??Date.now())},u=c?{ownerSig:c}:void 0,d=await this.innerClient.createAppSession(l,s,o,u);return{appSessionId:d.appSessionId,version:d.version,status:d.status}}async closeAppSession(t,n,r=[]){let i=typeof t==`string`?t:t.app_session_id,a=typeof t==`string`?n??[]:t.allocations,o=typeof t==`string`?void 0:t.version,s=typeof t==`string`?void 0:t.session_data,c=typeof t==`string`?r:t.quorum_sigs??r,{sessions:l}=await this.innerClient.getAppSessions({appSessionId:i});if(l.length===0)throw Error(`App session ${i} not found`);let u=l[0],d=[];for(let e of a){let t=await this.getDecimalsForAsset(e.asset),n=new P(e.amount).div(new P(10).pow(t));d.push({participant:e.participant,asset:e.asset,amount:n})}let f={appSessionId:i,intent:e.INTENT_MAP.close,version:o===void 0?u.version+1n:BigInt(o),allocations:d,sessionData:s??``};return await this.innerClient.submitAppState(f,c),{appSessionId:i}}async getAppDefinition(e){let t=await this.innerClient.getAppDefinition(e);return{protocol:t.applicationId,participants:t.participants.map(e=>e.walletAddress),weights:t.participants.map(e=>e.signatureWeight),quorum:t.quorum,challenge:0,nonce:Number(t.nonce??0)}}async submitAppState(t){let n=`intent`in t,r=n?t.intent:Ex.Operate,i=e.INTENT_MAP[r]??0;console.info(`[compat] submitAppState request`,{appSessionId:t.app_session_id,intent:r,allocationCount:t.allocations.length,hasQuorumSigs:(t.quorum_sigs?.length??0)>0,quorumSigCount:t.quorum_sigs?.length??0});let{sessions:a}=await this.innerClient.getAppSessions({appSessionId:t.app_session_id});if(a.length===0)throw Error(`App session ${t.app_session_id} not found`);let o=a[0],s=n?BigInt(t.version):o.version+1n,c=[];for(let e of t.allocations){let t=await this.getDecimalsForAsset(e.asset),n=new P(e.amount).div(new P(10).pow(t));c.push({participant:e.participant,asset:e.asset,amount:n})}let l={appSessionId:t.app_session_id,intent:i,version:s,allocations:c,sessionData:t.session_data??``};if(r===Ex.Deposit){let e=this.userAddress.toLowerCase(),n=new Map;for(let e of o.allocations??[])n.set(`${e.participant.toLowerCase()}::${e.asset.toLowerCase()}`,e.amount);let r=[],i=[],a=new Map;for(let e of c){let t=`${e.participant.toLowerCase()}::${e.asset.toLowerCase()}`;a.set(t,{participant:e.participant.toLowerCase(),asset:e.asset,amount:e.amount})}let s=new Set([...n.keys(),...a.keys()]);for(let e of s){let t=n.get(e)??new P(0),o=a.get(e),s=o?.amount??new P(0),[c,l]=e.split(`::`),u=s.minus(t);u.greaterThan(0)?r.push({participant:c,asset:o?.asset??l,amount:u}):u.lessThan(0)&&i.push({participant:c,asset:o?.asset??l,amount:u})}if(r.length===0)throw Error(`Deposit intent requires at least one positive allocation delta`);if(r.length>1)throw Error(`Deposit intent currently supports exactly one deposited asset delta`);if(i.length>0)throw Error(`Deposit intent cannot decrease existing app-session allocations`);let[u]=r;if(u.participant!==e)throw Error(`Deposit must be submitted by depositor ${u.participant}; connected wallet is ${e}`);console.info(`[compat] submitAppState deposit delta`,{appSessionId:t.app_session_id,depositor:u.participant,asset:u.asset,amount:u.amount.toString(),negativeDeltaCount:i.length}),await this.innerClient.submitAppSessionDeposit(l,t.quorum_sigs??[],u.asset,u.amount)}else await this.innerClient.submitAppState(l,t.quorum_sigs??[]);return console.info(`[compat] submitAppState success`,{appSessionId:t.app_session_id,intent:r,version:Number(s)}),{appSessionId:t.app_session_id,version:Number(s),status:i===3?`closed`:`open`}}async transfer(e,t){for(let n of t){let t=await this.getDecimalsForAsset(n.asset),r=new P(n.amount).div(new P(10).pow(t));await this.innerClient.transfer(e,n.asset,r)}}async close(){await this.innerClient.close()}async ping(){await this.innerClient.ping()}waitForClose(){return this.innerClient.waitForClose()}async acknowledge(e){let{symbol:t}=await this.resolveToken(e);await this.innerClient.acknowledge(t)}async checkTokenAllowance(e,t){return this.innerClient.checkTokenAllowance(BigInt(e),t,this.userAddress)}async getBlockchains(){return this.ensureBlockchains()}async ensureBlockchains(){return this._blockchains||=await this.innerClient.getBlockchains(),this._blockchains}async getActionAllowances(e){return this.innerClient.getActionAllowances(e??this.userAddress)}async getEscrowChannel(e){return this.innerClient.getEscrowChannel(e)}async getApps(e){return this.innerClient.getApps(e)}async registerApp(e,t,n){await this.innerClient.registerApp(e,t,n)}async lockSecurityTokens(e,t,n){if(n<=0n)throw Error(`amount must be positive`);let r=await this.getLockingTokenDecimals(t),i=this.toHumanAmount(n,r);return this.innerClient.escrowSecurityTokens(e,BigInt(t),i)}async initiateSecurityTokensWithdrawal(e){return this.innerClient.initiateSecurityTokensWithdrawal(BigInt(e))}async cancelSecurityTokensWithdrawal(e){return this.innerClient.cancelSecurityTokensWithdrawal(BigInt(e))}async withdrawSecurityTokens(e,t){return this.innerClient.withdrawSecurityTokens(BigInt(e),t)}async approveSecurityToken(e,t){if(t<=0n)throw Error(`amount must be positive`);let n=await this.getLockingTokenDecimals(e),r=this.toHumanAmount(t,n);return this.innerClient.approveSecurityToken(BigInt(e),r)}async getLockedBalance(e,t){let n=await this.innerClient.getLockedBalance(BigInt(e),t??this.userAddress),r=await this.getLockingTokenDecimals(e);return BigInt(n.mul(new P(10).pow(r)).toFixed(0))}async getLockingTokenDecimals(t){let n=this._lockingTokenDecimals.get(t);if(n!==void 0)return n;let r=(await this.ensureBlockchains()).find(e=>e.id===BigInt(t));if(!r?.lockingContractAddress)throw Error(`No locking contract configured for chain ${t}`);let i=this._blockchainRPCs[t];if(!i)throw Error(`No RPC URL configured for chain ${t}. Pass blockchainRPCs in NitroliteClientConfig to use locking methods.`);let a=bv({transport:Gv(i)}),o=await a.readContract({address:r.lockingContractAddress,abi:e.LOCKING_ASSET_ABI,functionName:`asset`}),s=await a.readContract({address:o,abi:e.ERC20_DECIMALS_ABI,functionName:`decimals`});return this._lockingTokenDecimals.set(t,s),s}};Lx.MAX_UINT256=2n**256n-1n,Lx.DEFAULT_APPROVE_AMOUNT=new P(1e5),Lx.STATUS_MAP={0:`void`,1:`open`,2:`challenged`,3:`closed`},Lx.INTENT_MAP={operate:0,deposit:1,withdraw:2,close:3},Lx.LOCKING_ASSET_ABI=[{type:`function`,name:`asset`,inputs:[],outputs:[{type:`address`}],stateMutability:`view`}],Lx.ERC20_DECIMALS_ABI=[{type:`function`,name:`decimals`,inputs:[],outputs:[{type:`uint8`}],stateMutability:`view`}];var Rx=`0xa1`,zx=132,Bx=134;function Vx(e){if(typeof e==`number`)return e;switch(e){case Ex.Operate:return 0;case Ex.Deposit:return 1;case Ex.Withdraw:return 2;case`close`:return 3;default:throw Error(`Unsupported app state intent: ${e}`)}}function Hx(e){return z(ma([{type:`string`},{type:`tuple[]`,components:[{name:`walletAddress`,type:`address`},{name:`signatureWeight`,type:`uint8`}]},{type:`uint8`},{type:`uint64`},{type:`string`}],[e.application,e.participants.map(e=>({walletAddress:e.walletAddress,signatureWeight:e.signatureWeight})),e.quorum,BigInt(e.nonce),e.sessionData??``]))}function Ux(e){return z(ma([{type:`bytes32`},{type:`uint8`},{type:`uint64`},{type:`tuple[]`,components:[{name:`participant`,type:`address`},{name:`asset`,type:`string`},{name:`amount`,type:`string`}]},{type:`string`}],[e.appSessionId,Vx(e.intent),BigInt(e.version),e.allocations.map(e=>({participant:e.participant,asset:e.asset,amount:e.amount})),e.sessionData??``]))}function Wx(e){let t=e.toLowerCase();if(!t.startsWith(`0x`))throw Error(`Signature must be a hex string with 0x prefix`);if(t.startsWith(Rx)&&t.length===Bx)return t;if(t.length!==zx)throw Error(`Expected a 65-byte wallet signature (0x + 130 hex chars)`);return oa([Rx,t])}var Gx=Hf({id:11155111,name:`Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://11155111.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://sepolia.etherscan.io`,apiUrl:`https://api-sepolia.etherscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:751532},ensUniversalResolver:{address:`0xeeeeeeee14d718c2b47d9923deab1335e144eeee`,blockCreated:8928790}},testnet:!0}),Kx=pe((e=>{var t=Symbol.for(`react.transitional.element`);function n(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.jsx=n,e.jsxs=n})),$=pe(((e,t)=>{t.exports=Kx()}))(),qx=`yusd`,Jx=`wss://clearnode-sandbox.yellow.org/v1/ws`,Yx={11155111:`https://ethereum-sepolia-rpc.publicnode.com`},Xx={Operate:0,Deposit:1,Withdraw:2};function Zx(){let e=window.ethereum;return e?Array.isArray(e.providers)?e.providers?.find(e=>e.isMetaMask)??null:e.isMetaMask?e:null:null}async function Qx(e,t){let n=await fetch(e,{credentials:`include`,headers:{"Content-Type":`application/json`,...t?.headers||{}},...t});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error?.message||`Request failed with status ${n.status}`)}return n.json()}function $x(e){return e?e.length<=12?e:`${e.slice(0,6)}...${e.slice(-4)}`:`Not connected`}function eS(e){return new P(e||`0`).toFixed()}function tS(e){if(!e)return`No store activity yet.`;try{let t=JSON.parse(e);switch(t.action){case`bootstrap`:return`Store session ready.`;case`deposit`:return`Last action: added ${t.amount}`;case`purchase`:return`Last action: purchased ${t.item_id} for ${t.price}`;case`user_withdraw`:return`Last action: withdrew ${t.amount}`;default:return`Store session active.`}}catch{return`Store session active.`}}function nS(e){return{id:e.id,transition:{type:e.transition.type,tx_id:e.transition.txId,account_id:e.transition.accountId??``,amount:e.transition.amount.toString()},asset:e.asset,user_wallet:e.userWallet,epoch:e.epoch.toString(),version:e.version.toString(),home_channel_id:e.homeChannelId??void 0,escrow_channel_id:e.escrowChannelId??void 0,home_ledger:{token_address:e.homeLedger.tokenAddress,blockchain_id:e.homeLedger.blockchainId.toString(),user_balance:e.homeLedger.userBalance.toString(),user_net_flow:e.homeLedger.userNetFlow.toString(),node_balance:e.homeLedger.nodeBalance.toString(),node_net_flow:e.homeLedger.nodeNetFlow.toString()},escrow_ledger:e.escrowLedger?{token_address:e.escrowLedger.tokenAddress,blockchain_id:e.escrowLedger.blockchainId.toString(),user_balance:e.escrowLedger.userBalance.toString(),user_net_flow:e.escrowLedger.userNetFlow.toString(),node_balance:e.escrowLedger.nodeBalance.toString(),node_net_flow:e.escrowLedger.nodeNetFlow.toString()}:void 0,user_sig:e.userSig,node_sig:e.nodeSig}}function rS(){let[e,t]=(0,Ce.useState)(null),[n,r]=(0,Ce.useState)(null),[i,a]=(0,Ce.useState)(null),[o,s]=(0,Ce.useState)(qx),[c,l]=(0,Ce.useState)(null),[u,d]=(0,Ce.useState)(`1.00`),[f,p]=(0,Ce.useState)(`0.50`),[m,h]=(0,Ce.useState)(null),[g,_]=(0,Ce.useState)(null),[v,y]=(0,Ce.useState)(null),[b,x]=(0,Ce.useState)([]),S=(0,Ce.useRef)(!1),ee=(0,Ce.useMemo)(()=>new Set((c?.library??[]).map(e=>e.id)),[c]);function C(e){let t=`${new Date().toISOString()} ${e}`;x(e=>[t,...e].slice(0,40))}async function te(e){if(await e.request({method:`eth_chainId`})!==`0xaa36a7`)try{await e.request({method:`wallet_switchEthereumChain`,params:[{chainId:`0xaa36a7`}]})}catch(e){throw Error(`Switch MetaMask to Sepolia and try again. ${String(e)}`)}}async function ne(t,r,a,o){let c=r??i,u=a??e,d=o??n,f=await Qx(`/api/store/bootstrap?asset=${encodeURIComponent(t)}`);if(l(f),s(f.selected_asset),C(`bootstrap ${t} -> ${f.session.status}`),f.session.status===`missing`&&c&&u&&d&&!S.current){S.current=!0;try{let e=await re(f,d,u);l(e),C(`session created ${e.session.app_session_id}`)}finally{S.current=!1}}}async function w(){_(`connect`),y(null);try{let e=Zx();if(!e)throw Error(`MetaMask extension was not found in this browser.`);await te(e);let n=(await e.request({method:`eth_requestAccounts`}))[0];if(!n)throw Error(`MetaMask did not return an account.`);let i=Vv({account:n,chain:Gx,transport:Uv(e)}),s=await Qx(`/api/store/connect/challenge`,{method:`POST`,body:JSON.stringify({wallet_address:n})}),c=await i.signMessage({account:n,message:s.message});await Qx(`/api/store/connect/verify`,{method:`POST`,body:JSON.stringify({challenge_id:s.challenge_id,wallet_address:n,signature:c})});let l=await Lx.create({wsURL:Jx,walletClient:i,chainId:11155111,blockchainRPCs:Yx});t(n),r(i),a(l),C(`wallet connected ${n}`),await ne(o,l,n,i)}catch(e){y(e instanceof Error?e.message:`Failed to connect wallet`)}finally{_(null)}}async function re(e,t,n){let r=Date.now(),i=JSON.stringify({action:`bootstrap`,asset:e.selected_asset}),a={application_id:e.app_id,participants:[{wallet_address:n,signature_weight:1},{wallet_address:e.app_signer,signature_weight:1}],quorum:2,nonce:String(r)},o=Hx({application:e.app_id,participants:a.participants.map(e=>({walletAddress:e.wallet_address,signatureWeight:e.signature_weight})),quorum:a.quorum,nonce:r,sessionData:i}),s=Wx(await t.signMessage({account:n,message:{raw:o}}));return Qx(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:e.selected_asset,kind:`create_session`,definition:a,session_data:i,user_signature:s})})}async function ie(t){if(!(!c||!e||!n)){if(!c.session.app_session_id||c.session.status!==`open`){y(`Store session is not ready yet.`);return}_(`purchase:${t.id}`),y(null);try{let r=c.session.version+1,i=new P(c.session.user_allocation),a=new P(c.session.app_allocation),o=new P(t.prices[c.selected_asset]),s=i.minus(o),u=a.plus(o);if(s.isNegative())throw Error(`Add funds before purchasing this item.`);let d=JSON.stringify({action:`purchase`,item_id:t.id,price:o.toFixed()}),f={app_session_id:c.session.app_session_id,intent:Xx.Operate,version:String(r),allocations:[{participant:e,asset:c.selected_asset,amount:s.toFixed()},{participant:c.app_signer,asset:c.selected_asset,amount:u.toFixed()}],session_data:d},p=Ux({appSessionId:f.app_session_id,intent:f.intent,version:r,allocations:f.allocations,sessionData:d}),m=Wx(await n.signMessage({account:e,message:{raw:p}}));l(await Qx(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:c.selected_asset,kind:`submit_app_state`,app_state_update:f,user_signature:m})})),C(`purchase ${t.id}`)}catch(e){y(e instanceof Error?e.message:`Failed to buy item`)}finally{_(null)}}}async function ae(){if(!(!c||!e||!n)){if(!c.session.app_session_id||c.session.status!==`open`){y(`Store session is not ready yet.`);return}_(`withdraw`),y(null);try{let t=new P(f),r=c.session.version+1,i=new P(c.session.user_allocation),a=new P(c.session.app_allocation),o=i.minus(t);if(o.isNegative())throw Error(`Withdraw amount exceeds your store balance.`);let s=JSON.stringify({action:`user_withdraw`,amount:t.toFixed()}),u={app_session_id:c.session.app_session_id,intent:Xx.Withdraw,version:String(r),allocations:[{participant:e,asset:c.selected_asset,amount:o.toFixed()},{participant:c.app_signer,asset:c.selected_asset,amount:a.toFixed()}],session_data:s},d=Ux({appSessionId:u.app_session_id,intent:u.intent,version:r,allocations:u.allocations,sessionData:s}),p=await n.signMessage({account:e,message:{raw:d}});l(await Qx(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:c.selected_asset,kind:`submit_app_state`,app_state_update:u,user_signature:Wx(p)})})),C(`withdraw ${t.toFixed()}`)}catch(e){y(e instanceof Error?e.message:`Failed to withdraw`)}finally{_(null)}}}async function T(){if(!(!c||!e||!n||!i)){if(!c.session.app_session_id||c.session.status!==`open`){y(`Store session is not ready yet.`);return}_(`deposit`),y(null);try{let t=new P(u),r=c.session.version+1,a=new P(c.session.user_allocation),o=new P(c.session.app_allocation),s=a.plus(t),d=JSON.stringify({action:`deposit`,amount:t.toFixed()}),f={app_session_id:c.session.app_session_id,intent:Xx.Deposit,version:String(r),allocations:[{participant:e,asset:c.selected_asset,amount:s.toFixed()},{participant:c.app_signer,asset:c.selected_asset,amount:o.toFixed()}],session_data:d},p=Ux({appSessionId:f.app_session_id,intent:f.intent,version:r,allocations:f.allocations,sessionData:d}),m=Wx(await n.signMessage({account:e,message:{raw:p}})),h=_y(await i.innerClient.getLatestState(e,c.selected_asset,!1));Cy(h,c.session.app_session_id,t),h.userSig=await i.innerClient.signState(h),l(await Qx(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:c.selected_asset,kind:`submit_deposit_state`,app_state_update:f,user_signature:m,user_state:nS(h)})})),C(`deposit ${t.toFixed()}`)}catch(e){y(e instanceof Error?e.message:`Failed to add funds`)}finally{_(null)}}}async function E(e){if(c){_(`content:${e}`),y(null);try{h(await Qx(`/api/store/content/${encodeURIComponent(e)}?asset=${encodeURIComponent(c.selected_asset)}`)),C(`open content ${e}`)}catch(e){y(e instanceof Error?e.message:`Failed to open content`)}finally{_(null)}}}async function D(){try{await navigator.clipboard.writeText(b.join(` -`)),C(`copied activity log`)}catch(e){y(e instanceof Error?e.message:`Failed to copy activity log`)}}return(0,Ce.useEffect)(()=>{!c||!e||!i||c.selected_asset!==o&&ne(o)},[o,c,e,i]),(0,$.jsxs)(`main`,{className:`shell`,children:[(0,$.jsxs)(`section`,{className:`hero`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`p`,{className:`eyebrow`,children:`Content store`}),(0,$.jsx)(`h1`,{children:`Simple content store`}),(0,$.jsx)(`p`,{className:`lede`,children:`Connect MetaMask, add funds, buy content instantly, read what you own, and withdraw what remains.`})]}),(0,$.jsxs)(`div`,{className:`hero-actions`,children:[(0,$.jsx)(`button`,{className:`primary`,onClick:w,disabled:g===`connect`,children:g===`connect`?`Connecting…`:e?`Reconnect MetaMask`:`Connect MetaMask`}),(0,$.jsxs)(`div`,{className:`identity-card`,children:[(0,$.jsx)(`span`,{className:`label`,children:`Wallet`}),(0,$.jsx)(`strong`,{children:$x(e)})]})]})]}),v?(0,$.jsx)(`div`,{className:`alert`,children:v}):null,(0,$.jsxs)(`section`,{className:`grid two-up`,children:[(0,$.jsxs)(`article`,{className:`panel`,children:[(0,$.jsxs)(`div`,{className:`panel-head`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`label`,children:`Store`}),(0,$.jsx)(`h2`,{children:c?.store_name??`Store`})]}),(0,$.jsxs)(`label`,{className:`asset-picker`,children:[(0,$.jsx)(`span`,{children:`Asset`}),(0,$.jsx)(`select`,{value:o,onChange:e=>s(e.target.value),disabled:!e,children:(c?.supported_assets??[qx]).map(e=>(0,$.jsx)(`option`,{value:e,children:e.toUpperCase()},e))})]})]}),(0,$.jsxs)(`div`,{className:`stats`,children:[(0,$.jsxs)(`div`,{className:`stat`,children:[(0,$.jsx)(`span`,{className:`label`,children:`Available balance`}),(0,$.jsx)(`strong`,{children:c?eS(c.available_balance):`0`})]}),(0,$.jsxs)(`div`,{className:`stat`,children:[(0,$.jsx)(`span`,{className:`label`,children:`Store balance`}),(0,$.jsx)(`strong`,{children:c?eS(c.session.user_allocation):`0`})]}),(0,$.jsxs)(`div`,{className:`stat`,children:[(0,$.jsx)(`span`,{className:`label`,children:`Store status`}),(0,$.jsx)(`strong`,{children:c?.session.status??`Connect first`})]})]}),(0,$.jsx)(`p`,{className:`supporting`,children:c?tS(c.session.session_data):`Connect MetaMask to start shopping.`}),(0,$.jsxs)(`div`,{className:`form-grid`,children:[(0,$.jsxs)(`label`,{children:[(0,$.jsx)(`span`,{children:`Add funds`}),(0,$.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),inputMode:`decimal`})]}),(0,$.jsx)(`button`,{className:`primary`,disabled:!e||g===`deposit`,onClick:T,children:g===`deposit`?`Adding…`:`Add funds`}),(0,$.jsxs)(`label`,{children:[(0,$.jsx)(`span`,{children:`Withdraw`}),(0,$.jsx)(`input`,{value:f,onChange:e=>p(e.target.value),inputMode:`decimal`})]}),(0,$.jsx)(`button`,{className:`secondary`,disabled:!e||g===`withdraw`,onClick:ae,children:g===`withdraw`?`Withdrawing…`:`Withdraw to wallet`})]})]}),(0,$.jsxs)(`article`,{className:`panel`,children:[(0,$.jsx)(`div`,{className:`panel-head`,children:(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`label`,children:`Library`}),(0,$.jsx)(`h2`,{children:`What you own`})]})}),c?.library.length?(0,$.jsx)(`div`,{className:`stack`,children:c.library.map(e=>(0,$.jsxs)(`div`,{className:`library-item`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`strong`,{children:e.title}),(0,$.jsx)(`p`,{children:e.description}),(0,$.jsxs)(`span`,{className:`meta`,children:[e.type,` · bought for `,e.price]})]}),(0,$.jsx)(`button`,{className:`secondary`,disabled:g===`content:${e.id}`,onClick:()=>E(e.id),children:g===`content:${e.id}`?`Opening…`:`Read`})]},e.id))}):(0,$.jsx)(`p`,{className:`supporting`,children:`Buy something from the catalog and it will appear here.`})]})]}),(0,$.jsxs)(`section`,{className:`grid two-up`,children:[(0,$.jsxs)(`article`,{className:`panel`,children:[(0,$.jsx)(`div`,{className:`panel-head`,children:(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`label`,children:`Catalog`}),(0,$.jsx)(`h2`,{children:`Browse content`})]})}),(0,$.jsx)(`div`,{className:`stack`,children:(c?.catalog??[]).map(t=>(0,$.jsxs)(`div`,{className:`catalog-item`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`strong`,{children:t.title}),(0,$.jsx)(`p`,{children:t.description}),(0,$.jsxs)(`span`,{className:`meta`,children:[t.type,` · `,t.prices[o]]})]}),(0,$.jsx)(`button`,{className:`primary`,disabled:!e||ee.has(t.id)||g===`purchase:${t.id}`,onClick:()=>ie(t),children:ee.has(t.id)?`Owned`:g===`purchase:${t.id}`?`Buying…`:`Buy`})]},t.id))})]}),(0,$.jsxs)(`article`,{className:`panel`,children:[(0,$.jsx)(`div`,{className:`panel-head`,children:(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`label`,children:`Reader`}),(0,$.jsx)(`h2`,{children:`Open content`})]})}),m?(0,$.jsxs)(`article`,{className:`reader`,children:[(0,$.jsx)(`h3`,{children:m.title}),(0,$.jsx)(`pre`,{children:m.content})]}):(0,$.jsx)(`p`,{className:`supporting`,children:`Open an item from your library to read it here.`})]})]}),(0,$.jsxs)(`section`,{className:`panel`,children:[(0,$.jsxs)(`div`,{className:`panel-head`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`label`,children:`Browser activity`}),(0,$.jsx)(`h2`,{children:`Recent actions`})]}),(0,$.jsx)(`button`,{className:`secondary`,onClick:D,disabled:b.length===0,children:`Copy log`})]}),b.length?(0,$.jsx)(`ul`,{className:`activity-list`,children:b.map(e=>(0,$.jsx)(`li`,{children:e},e))}):(0,$.jsx)(`p`,{className:`supporting`,children:`No activity yet.`})]})]})}(0,we.createRoot)(document.getElementById(`root`)).render((0,$.jsx)(Ce.StrictMode,{children:(0,$.jsx)(rS,{})}));export{Fo as a,co as c,I as d,xr as f,Qc as i,ma as l,kd as n,Oo as o,Pu as r,V as s,Ad as t,ia as u}; \ No newline at end of file diff --git a/internal/webui/dist/assets/index-r8X5N65j.js b/internal/webui/dist/assets/index-r8X5N65j.js new file mode 100644 index 0000000..fc7f7c9 --- /dev/null +++ b/internal/webui/dist/assets/index-r8X5N65j.js @@ -0,0 +1,56 @@ +import{A as e,B as t,C as n,D as r,E as i,F as a,I as o,L as s,M as c,N as l,O as u,P as d,R as f,S as p,T as m,V as h,_ as g,a as _,b as v,c as y,d as b,f as x,g as S,h as C,i as w,j as T,k as E,l as D,m as ee,n as te,o as ne,p as O,r as k,s as A,t as j,u as re,v as M,w as ie,x as ae,y as oe,z as se}from"./utils-DUS54ir-.js";var ce=Object.create,le=Object.defineProperty,ue=Object.getOwnPropertyDescriptor,de=Object.getOwnPropertyNames,fe=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty,me=(e,t)=>()=>(e&&(t=e(e=0)),t),he=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),ge=(e,t)=>{let n={};for(var r in e)le(n,r,{get:e[r],enumerable:!0});return t||le(n,Symbol.toStringTag,{value:`Module`}),n},_e=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=de(t),a=0,o=i.length,s;at[e]).bind(null,s),enumerable:!(r=ue(t,s))||r.enumerable});return e},ve=(e,t,n)=>(n=e==null?{}:ce(fe(e)),_e(t||!e||!e.__esModule?le(n,`default`,{value:e,enumerable:!0}):n,e)),ye=e=>pe.call(e,`module.exports`)?e[`module.exports`]:_e(le({},`__esModule`,{value:!0}),e);(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var be=he((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function E(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function D(e,t){return E(e.type,t,e.props)}function ee(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function te(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ne=/\/+/g;function O(e,t){return typeof e==`object`&&e&&e.key!=null?te(``+e.key):t.toString(36)}function k(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function A(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,A(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+O(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(ne,`$&/`)+`/`),A(o,r,i,``,function(e){return e})):o!=null&&(ee(o)&&(o=D(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ne,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=be()})),Se=he((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,ee());else{var t=n(l);t!==null&&O(x,t.startTime-e)}}var S=!1,C=-1,w=5,T=-1;function E(){return g?!0:!(e.unstable_now()-Tt&&E());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&O(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?ee():S=!1}}}var ee;if(typeof y==`function`)ee=function(){y(D)};else if(typeof MessageChannel<`u`){var te=new MessageChannel,ne=te.port2;te.port1.onmessage=D,ee=function(){ne.postMessage(null)}}else ee=function(){_(D,0)};function O(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,O(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,ee()))),r},e.unstable_shouldYield=E,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Ce=he(((e,t)=>{t.exports=Se()})),we=he((e=>{var t=xe();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=we()})),Ee=he((e=>{var t=Ce(),n=xe(),r=Te();function i(e){var t=`https://react.dev/errors/`+e;if(1ie||(e.current=M[ie],M[ie]=null,ie--)}function se(e,t){ie++,M[ie]=e.current,e.current=t}var ce=ae(null),le=ae(null),ue=ae(null),de=ae(null);function fe(e,t){switch(se(ue,t),se(le,e),se(ce,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Yd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Yd(t),e=Xd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}oe(ce),se(ce,e)}function pe(){oe(ce),oe(le),oe(ue)}function me(e){e.memoizedState!==null&&se(de,e);var t=ce.current,n=Xd(t,e.type);t!==n&&(se(le,e),se(ce,n))}function he(e){le.current===e&&(oe(ce),oe(le)),de.current===e&&(oe(de),op._currentValue=re)}var ge,_e;function ve(e){if(ge===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);ge=t&&t[1]||``,_e=-1)`:-1i||c[r]!==l[i]){var u=` +`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{ye=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?ve(n):``}function Se(e,t){switch(e.tag){case 26:case 27:case 5:return ve(e.type);case 16:return ve(`Lazy`);case 13:return e.child!==t&&t!==null?ve(`Suspense Fallback`):ve(`Suspense`);case 19:return ve(`SuspenseList`);case 0:case 15:return be(e.type,!1);case 11:return be(e.type.render,!1);case 1:return be(e.type,!0);case 31:return ve(`Activity`);default:return``}}function we(e){try{var t=``,n=null;do t+=Se(e,n),n=e,e=e.return;while(e);return t}catch(e){return` +Error generating stack: `+e.message+` +`+e.stack}}var Ee=Object.prototype.hasOwnProperty,De=t.unstable_scheduleCallback,N=t.unstable_cancelCallback,Oe=t.unstable_shouldYield,ke=t.unstable_requestPaint,Ae=t.unstable_now,je=t.unstable_getCurrentPriorityLevel,Me=t.unstable_ImmediatePriority,Ne=t.unstable_UserBlockingPriority,Pe=t.unstable_NormalPriority,Fe=t.unstable_LowPriority,Ie=t.unstable_IdlePriority,P=t.log,Le=t.unstable_setDisableYieldValue,Re=null,ze=null;function Be(e){if(typeof P==`function`&&Le(e),ze&&typeof ze.setStrictMode==`function`)try{ze.setStrictMode(Re,e)}catch{}}var Ve=Math.clz32?Math.clz32:We,He=Math.log,Ue=Math.LN2;function We(e){return e>>>=0,e===0?32:31-(He(e)/Ue|0)|0}var Ge=256,Ke=262144,qe=4194304;function Je(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function F(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Je(n))):i=Je(o):i=Je(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Je(n))):i=Je(o)):i=Je(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ye(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Xe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var e=qe;return qe<<=1,!(qe&62914560)&&(qe=4194304),e}function I(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Qe(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function $e(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),dn=!1;if(un)try{var R={};Object.defineProperty(R,`passive`,{get:function(){dn=!0}}),window.addEventListener(`test`,R,R),window.removeEventListener(`test`,R,R)}catch{dn=!1}var fn=null,pn=null,mn=null;function hn(){if(mn)return mn;var e,t=pn,n=t.length,r,i=`value`in fn?fn.value:fn.textContent,a=i.length;for(e=0;e=qn),Xn=` `,Zn=!1;function Qn(e,t){switch(e){case`keyup`:return Gn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function $n(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var er=!1;function tr(e,t){switch(e){case`compositionend`:return $n(t);case`keypress`:return t.which===32?(Zn=!0,Xn):null;case`textInput`:return e=t.data,e===Xn&&Zn?null:e;default:return null}}function nr(e,t){if(er)return e===`compositionend`||!Kn&&Qn(e,t)?(e=hn(),mn=pn=fn=null,er=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=wr(n)}}function Er(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Er(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Dr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Lt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Lt(e.document)}return t}function Or(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var kr=un&&`documentMode`in document&&11>=document.documentMode,Ar=null,jr=null,Mr=null,Nr=!1;function Pr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Nr||Ar==null||Ar!==Lt(r)||(r=Ar,`selectionStart`in r&&Or(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Mr&&Cr(Mr,r)||(Mr=r,r=Nd(jr,`onSelect`),0>=o,i-=o,Ti=1<<32-Ve(t)+i|n<m?(h=d,d=null):h=d.sibling;var g=p(i,d,s[m],c);if(g===null){d===null&&(d=h);break}e&&d&&g.alternate===null&&t(i,d),a=o(g,a,m),u===null?l=g:u.sibling=g,u=g,d=h}if(m===s.length)return n(i,d),Pi&&Di(i,m),l;if(d===null){for(;mh?(g=m,m=null):g=m.sibling;var y=p(a,m,v.value,l);if(y===null){m===null&&(m=g);break}e&&m&&y.alternate===null&&t(a,m),s=o(y,s,h),d===null?u=y:d.sibling=y,d=y,m=g}if(v.done)return n(a,m),Pi&&Di(a,h),u;if(m===null){for(;!v.done;h++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return Pi&&Di(a,h),u}for(m=r(m);!v.done;h++,v=c.next())v=_(m,a,h,v.value,l),v!==null&&(e&&v.alternate!==null&&m.delete(v.key===null?h:v.key),s=o(v,s,h),d===null?u=v:d.sibling=v,d=v);return e&&m.forEach(function(e){return t(a,e)}),Pi&&Di(a,h),u}function x(e,r,o,c){if(typeof o==`object`&&o&&o.type===g&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case m:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===g){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===T&&Oa(l)===r.type){n(e,r.sibling),c=a(r,o.props),Fa(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===g?(c=fi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=di(o.type,o.key,o.props,null,e.mode,c),Fa(c,o),c.return=e,e=c)}return s(e);case h:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=hi(o,e.mode,c),c.return=e,e=c}return s(e);case T:return o=Oa(o),x(e,r,o,c)}if(k(o))return v(e,r,o,c);if(te(o)){if(l=te(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),y(e,r,o,c)}if(typeof o.then==`function`)return x(e,r,Pa(o),c);if(o.$$typeof===b)return x(e,r,na(e,o),c);Ia(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=pi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Na=0;var i=x(e,t,n,r);return Ma=null,i}catch(t){if(t===Sa||t===wa)throw t;var a=si(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ra=La(!0),za=La(!1),Ba=!1;function Va(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ha(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ua(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Wa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Ul&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=ii(e),ri(e,null,n),t}return ei(e,r,t,n),ii(e)}function Ga(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tt(e,n)}}function Ka(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var qa=!1;function Ja(){if(qa){var e=pa;if(e!==null)throw e}}function Ya(e,t,n,r){qa=!1;var i=e.updateQueue;Ba=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var p=s.lane&-536870913,m=p!==s.lane;if(m?(U&p)===p:(r&p)===p){p!==0&&p===fa&&(qa=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;p=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,p);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,p=typeof h==`function`?h.call(_,d,p):h,p==null)break a;d=f({},d,p);break a;case 2:Ba=!0}}p=s.callback,p!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[p]:m.push(p))}else m={lane:p,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=p;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Ql|=o,e.lanes=o,e.memoizedState=d}}function Xa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function Za(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=A.T,s={};A.T=s,Is(e,!1,t,n);try{var c=i(),l=A.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Fs(e,t,ga(c,r),bu(e)):Fs(e,t,r,bu(e))}catch(n){Fs(e,t,{then:function(){},status:`rejected`,reason:n},bu())}finally{j.p=a,o!==null&&s.types!==null&&(o.types=s.types),A.T=o}}function Ts(){}function Es(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Ds(e).queue;ws(e,a,t,re,n===null?Ts:function(){return Os(e),n(r)})}function Ds(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:re,baseState:re,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Lo,lastRenderedState:re},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Lo,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Os(e){var t=Ds(e);t.next===null&&(t=e.alternate.memoizedState),Fs(e,t.next.queue,{},bu())}function ks(){return ta(op)}function As(){return V().memoizedState}function js(){return V().memoizedState}function Ms(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=bu();e=Ua(n);var r=Wa(t,e,n);r!==null&&(Su(r,t,n),Ga(r,t,n)),t={cache:ca()},e.payload=t;return}t=t.return}}function Ns(e,t,n){var r=bu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Ls(e)?Rs(t,n):(n=ti(e,t,n,r),n!==null&&(Su(n,e,r),zs(n,t,r)))}function Ps(e,t,n){Fs(e,t,n,bu())}function Fs(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ls(e))Rs(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Sr(s,o))return ei(e,t,i,0),Wl===null&&$r(),!1}catch{}if(n=ti(e,t,i,r),n!==null)return Su(n,e,r),zs(n,t,r),!0}return!1}function Is(e,t,n,r){if(r={lane:2,revertLane:vd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Ls(e)){if(t)throw Error(i(479))}else t=ti(e,n,r,2),t!==null&&Su(t,e,2)}function Ls(e){var t=e.alternate;return e===B||t!==null&&t===B}function Rs(e,t){_o=go=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function zs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tt(e,n)}}var Bs={readContext:ta,use:Fo,useCallback:Co,useContext:Co,useEffect:Co,useImperativeHandle:Co,useLayoutEffect:Co,useInsertionEffect:Co,useMemo:Co,useReducer:Co,useRef:Co,useState:Co,useDebugValue:Co,useDeferredValue:Co,useTransition:Co,useSyncExternalStore:Co,useId:Co,useHostTransitionStatus:Co,useFormState:Co,useActionState:Co,useOptimistic:Co,useMemoCache:Co,useCacheRefresh:Co};Bs.useEffectEvent=Co;var Vs={readContext:ta,use:Fo,useCallback:function(e,t){return Mo().memoizedState=[e,t===void 0?null:t],e},useContext:ta,useEffect:ds,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),ls(4194308,4,_s.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ls(4194308,4,e,t)},useInsertionEffect:function(e,t){ls(4,2,e,t)},useMemo:function(e,t){var n=Mo();t=t===void 0?null:t;var r=e();if(vo){Be(!0);try{e()}finally{Be(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Mo();if(n!==void 0){var i=n(t);if(vo){Be(!0);try{n(t)}finally{Be(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ns.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var t=Mo();return e={current:e},t.memoizedState=e},useState:function(e){e=qo(e);var t=e.queue,n=Ps.bind(null,B,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:ys,useDeferredValue:function(e,t){return Ss(Mo(),e,t)},useTransition:function(){var e=qo(!1);return e=ws.bind(null,B,e.queue,!0,!1),Mo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=B,a=Mo();if(Pi){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),Wl===null)throw Error(i(349));U&127||Ho(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,ds(Wo.bind(null,r,o,e),[e]),r.flags|=2048,ss(9,{destroy:void 0},Uo.bind(null,r,o,n,t),null),n},useId:function(){var e=Mo(),t=Wl.identifierPrefix;if(Pi){var n=Ei,r=Ti;n=(r&~(1<<32-Ve(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=yo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[st]=t,o[ct]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Hd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Fc(t)}}return Bc(t),Ic(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Fc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ue.current,Vi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Mi,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[st]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||zd(e.nodeValue,n)),e||Ri(t,!0)}else e=Jd(e).createTextNode(r),e[st]=t,t.stateNode=e}return Bc(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Vi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[st]=t}else Hi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Bc(t),e=!1}else n=Ui(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(lo(t),t):(lo(t),null);if(t.flags&128)throw Error(i(558))}return Bc(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Vi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[st]=t}else Hi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Bc(t),a=!1}else a=Ui(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(lo(t),t):(lo(t),null)}return lo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Rc(t,t.updateQueue),Bc(t),null);case 4:return pe(),e===null&&kd(t.stateNode.containerInfo),Bc(t),null;case 10:return Yi(t.type),Bc(t),null;case 19:if(oe(uo),r=t.memoizedState,r===null)return Bc(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)zc(r,!1);else{if(Zl!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=fo(e),o!==null){for(t.flags|=128,zc(r,!1),e=o.updateQueue,t.updateQueue=e,Rc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)ui(n,e),n=n.sibling;return se(uo,uo.current&1|2),Pi&&Di(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Ae()>cu&&(t.flags|=128,a=!0,zc(r,!1),t.lanes=4194304)}else{if(!a)if(e=fo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Rc(t,e),zc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!Pi)return Bc(t),null}else 2*Ae()-r.renderingStartTime>cu&&n!==536870912&&(t.flags|=128,a=!0,zc(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(Bc(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Ae(),e.sibling=null,n=uo.current,se(uo,a?n&1|2:n&1),Pi&&Di(t,r.treeForkCount),e);case 22:case 23:return lo(t),no(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(Bc(t),t.subtreeFlags&6&&(t.flags|=8192)):Bc(t),n=t.updateQueue,n!==null&&Rc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&oe(va),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Yi(sa),Bc(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Hc(e,t){switch(Ai(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Yi(sa),pe(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return he(t),null;case 31:if(t.memoizedState!==null){if(lo(t),t.alternate===null)throw Error(i(340));Hi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(lo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Hi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return oe(uo),null;case 4:return pe(),null;case 10:return Yi(t.type),null;case 22:case 23:return lo(t),no(),e!==null&&oe(va),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Yi(sa),null;case 25:return null;default:return null}}function Uc(e,t){switch(Ai(t),t.tag){case 3:Yi(sa),pe();break;case 26:case 27:case 5:he(t);break;case 4:pe();break;case 31:t.memoizedState!==null&&lo(t);break;case 13:lo(t);break;case 19:oe(uo);break;case 10:Yi(t.type);break;case 22:case 23:lo(t),no(),e!==null&&oe(va);break;case 24:Yi(sa)}}function Wc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Qu(t,t.return,e)}}function Gc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Qu(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Qu(t,t.return,e)}}function Kc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Za(t,n)}catch(t){Qu(e,e.return,t)}}}function qc(e,t,n){n.props=Js(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Qu(e,t,n)}}function Jc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Qu(e,t,n)}}function Yc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){Qu(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Qu(e,t,n)}else n.current=null}function Xc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Qu(e,e.return,t)}}function Zc(e,t,n){try{var r=e.stateNode;Ud(r,e.type,n,t),r[ct]=t}catch(t){Qu(e,e.return,t)}}function Qc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&of(e.type)||e.tag===4}function $c(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Qc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&of(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function el(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=en));else if(r!==4&&(r===27&&of(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(el(e,t,n),e=e.sibling;e!==null;)el(e,t,n),e=e.sibling}function tl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&of(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(tl(e,t,n),e=e.sibling;e!==null;)tl(e,t,n),e=e.sibling}function nl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Hd(t,r,n),t[st]=e,t[ct]=n}catch(t){Qu(e,e.return,t)}}var rl=!1,il=!1,al=!1,ol=typeof WeakSet==`function`?WeakSet:Set,sl=null;function cl(e,t){if(e=e.containerInfo,Kd=hp,e=Dr(e),Or(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(qd={focusedElem:e,selectionRange:n},hp=!1,sl=t;sl!==null;)if(t=sl,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,sl=e;else for(;sl!==null;){switch(t=sl,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Hd(o,r,n),o[st]=e,bt(o),r=o;break a;case`link`:var s=Yf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Tr(s,h),v=Tr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,A.T=null,n=gu,gu=null;var o=fu,s=mu;if(du=0,pu=fu=null,mu=0,Ul&6)throw Error(i(331));var c=Ul;if(Ul|=4,Rl(o.current),Al(o,o.current,s,n),Ul=c,dd(0,!1),ze&&typeof ze.onPostCommitFiberRoot==`function`)try{ze.onPostCommitFiberRoot(Re,o)}catch{}return!0}finally{j.p=a,A.T=r,Ju(e,t)}}function Zu(e,t,n){t=_i(n,t),t=ec(e.stateNode,t,2),e=Wa(e,t,2),e!==null&&(Qe(e,2),ud(e))}function Qu(e,t,n){if(e.tag===3)Zu(e,e,n);else for(;t!==null;){if(t.tag===3){Zu(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(uu===null||!uu.has(r))){e=_i(n,e),n=tc(2),r=Wa(t,n,2),r!==null&&(nc(n,r,t,e),Qe(r,2),ud(r));break}}t=t.return}}function W(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Hl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Yl=!0,i.add(n),e=$u.bind(null,e,t,n),t.then(e,e))}function $u(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,Wl===e&&(U&n)===n&&(Zl===4||Zl===3&&(U&62914560)===U&&300>Ae()-ou?!(Ul&2)&&ku(e,0):eu|=n,nu===U&&(nu=0)),ud(e)}function ed(e,t){t===0&&(t=Ze()),e=ni(e,t),e!==null&&(Qe(e,t),ud(e))}function td(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),ed(e,n)}function nd(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),ed(e,n)}function rd(e,t){return De(e,t)}var id=null,ad=null,od=!1,sd=!1,cd=!1,ld=0;function ud(e){e!==ad&&e.next===null&&(ad===null?id=ad=e:ad=ad.next=e),sd=!0,od||(od=!0,_d())}function dd(e,t){if(!cd&&sd){cd=!0;do for(var n=!1,r=id;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Ve(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,gd(r,a))}else a=U,a=F(r,r===Wl?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ye(r,a)||(n=!0,gd(r,a));r=r.next}while(n);cd=!1}}function fd(){pd()}function pd(){sd=od=!1;var e=0;ld!==0&&$d()&&(e=ld);for(var t=Ae(),n=null,r=id;r!==null;){var i=r.next,a=md(r,t);a===0?(r.next=null,n===null?id=i:n.next=i,i===null&&(ad=n)):(n=r,(e!==0||a&3)&&(sd=!0)),r=i}du!==0&&du!==5||dd(e,!1),ld!==0&&(ld=0)}function md(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Wd(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function kf(e,t,n){var r=Of;if(r&&typeof t==`string`&&t){var i=zt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),Cf.has(i)||(Cf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Hd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function Af(e){Tf.D(e),kf(`dns-prefetch`,e,null)}function jf(e,t){Tf.C(e,t),kf(`preconnect`,e,t)}function Mf(e,t,n){Tf.L(e,t,n);var r=Of;if(r&&e&&t){var i=`link[rel="preload"][as="`+zt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+zt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+zt(n.imageSizes)+`"]`)):i+=`[href="`+zt(e)+`"]`;var a=i;switch(t){case`style`:a=Rf(e);break;case`script`:a=Hf(e)}Sf.has(a)||(e=f({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),Sf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(zf(a))||t===`script`&&r.querySelector(Uf(a))||(t=r.createElement(`link`),Hd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function Nf(e,t){Tf.m(e,t);var n=Of;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+zt(r)+`"][href="`+zt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Hf(e)}if(!Sf.has(a)&&(e=f({rel:`modulepreload`,href:e},t),Sf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Uf(a)))return}r=n.createElement(`link`),Hd(r,`link`,e),bt(r),n.head.appendChild(r)}}}function Pf(e,t,n){Tf.S(e,t,n);var r=Of;if(r&&e){var i=yt(r).hoistableStyles,a=Rf(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(zf(a)))s.loading=5;else{e=f({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=Sf.get(a))&&Kf(e,n);var c=o=r.createElement(`link`);bt(c),Hd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Gf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Ff(e,t){Tf.X(e,t);var n=Of;if(n&&e){var r=yt(n).hoistableScripts,i=Hf(e),a=r.get(i);a||(a=n.querySelector(Uf(i)),a||(e=f({src:e,async:!0},t),(t=Sf.get(i))&&qf(e,t),a=n.createElement(`script`),bt(a),Hd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function If(e,t){Tf.M(e,t);var n=Of;if(n&&e){var r=yt(n).hoistableScripts,i=Hf(e),a=r.get(i);a||(a=n.querySelector(Uf(i)),a||(e=f({src:e,async:!0,type:`module`},t),(t=Sf.get(i))&&qf(e,t),a=n.createElement(`script`),bt(a),Hd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Lf(e,t,n,r){var a=(a=ue.current)?wf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Rf(n.href),n=yt(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Rf(n.href);var o=yt(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(zf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),Sf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},Sf.set(e,n),o||Vf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Hf(n),n=yt(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Rf(e){return`href="`+zt(e)+`"`}function zf(e){return`link[rel="stylesheet"][`+e+`]`}function Bf(e){return f({},e,{"data-precedence":e.precedence,precedence:null})}function Vf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Hd(t,`link`,n),bt(t),e.head.appendChild(t))}function Hf(e){return`[src="`+zt(e)+`"]`}function Uf(e){return`script[async]`+e}function Wf(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+zt(n.href)+`"]`);if(r)return t.instance=r,bt(r),r;var a=f({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),bt(r),Hd(r,`style`,a),Gf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Rf(n.href);var o=e.querySelector(zf(a));if(o)return t.state.loading|=4,t.instance=o,bt(o),o;r=Bf(n),(a=Sf.get(a))&&Kf(r,a),o=(e.ownerDocument||e).createElement(`link`),bt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Hd(o,`link`,r),t.state.loading|=4,Gf(o,n.precedence,e),t.instance=o;case`script`:return o=Hf(n.src),(a=e.querySelector(Uf(o)))?(t.instance=a,bt(a),a):(r=n,(a=Sf.get(o))&&(r=f({},n),qf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),bt(a),Hd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Gf(r,n.precedence,e));return t.instance}function Gf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Zf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Qf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function $f(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Rf(r.href),a=t.querySelector(zf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=np.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,bt(a);return}a=t.ownerDocument||t,r=Bf(r),(i=Sf.get(i))&&Kf(r,i),a=a.createElement(`link`),bt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Hd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=np.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var ep=0;function tp(e,t){return e.stylesheets&&e.count===0&&ip(e,e.stylesheets),0ep?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function np(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)ip(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var rp=null;function ip(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,rp=new Map,t.forEach(ap,e),rp=null,np.call(e))}function ap(e,t){if(!(t.state.loading&4)){var n=rp.get(e);if(n)var r=n.get(null);else{n=new Map,rp.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=Ee()})),N=ve(xe(),1),Oe=De(),ke=9e15,Ae=1e9,je=`0123456789abcdef`,Me=`2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058`,Ne=`3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789`,Pe={precision:20,rounding:4,modulo:1,toExpNeg:-7,toExpPos:21,minE:-ke,maxE:ke,crypto:!1},Fe,Ie,P=!0,Le=`[DecimalError] `,Re=Le+`Invalid argument: `,ze=Le+`Precision limit exceeded`,Be=Le+`crypto unavailable`,Ve=`[object Decimal]`,He=Math.floor,Ue=Math.pow,We=/^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i,Ge=/^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i,Ke=/^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i,qe=/^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,Je=1e7,F=7,Ye=9007199254740991,Xe=Me.length-1,Ze=Ne.length-1,I={toStringTag:Ve};I.absoluteValue=I.abs=function(){var e=new this.constructor(this);return e.s<0&&(e.s=1),L(e)},I.ceil=function(){return L(new this.constructor(this),this.e+1,2)},I.clampedTo=I.clamp=function(e,t){var n,r=this,i=r.constructor;if(e=new i(e),t=new i(t),!e.s||!t.s)return new i(NaN);if(e.gt(t))throw Error(Re+t);return n=r.cmp(e),n<0?e:r.cmp(t)>0?t:new i(r)},I.comparedTo=I.cmp=function(e){var t,n,r,i,a=this,o=a.d,s=(e=new a.constructor(e)).d,c=a.s,l=e.s;if(!o||!s)return!c||!l?NaN:c===l?o===s?0:!o^c<0?1:-1:c;if(!o[0]||!s[0])return o[0]?c:s[0]?-l:0;if(c!==l)return c;if(a.e!==e.e)return a.e>e.e^c<0?1:-1;for(r=o.length,i=s.length,t=0,n=rs[t]^c<0?1:-1;return r===i?0:r>i^c<0?1:-1},I.cosine=I.cos=function(){var e,t,n=this,r=n.constructor;return n.d?n.d[0]?(e=r.precision,t=r.rounding,r.precision=e+Math.max(n.e,n.sd())+F,r.rounding=1,n=nt(r,xt(r,n)),r.precision=e,r.rounding=t,L(Ie==2||Ie==3?n.neg():n,e,t,!0)):new r(1):new r(NaN)},I.cubeRoot=I.cbrt=function(){var e,t,n,r,i,a,o,s,c,l,u=this,d=u.constructor;if(!u.isFinite()||u.isZero())return new d(u);for(P=!1,a=u.s*Ue(u.s*u,1/3),!a||Math.abs(a)==1/0?(n=Qe(u.d),e=u.e,(a=(e-n.length+1)%3)&&(n+=a==1||a==-2?`0`:`00`),a=Ue(n,1/3),e=He((e+1)/3)-(e%3==(e<0?-1:2)),a==1/0?n=`5e`+e:(n=a.toExponential(),n=n.slice(0,n.indexOf(`e`)+1)+e),r=new d(n),r.s=u.s):r=new d(a.toString()),o=(e=d.precision)+3;;)if(s=r,c=s.times(s).times(s),l=c.plus(u),r=rt(l.plus(u).times(s),l.plus(c),o+2,1),Qe(s.d).slice(0,o)===(n=Qe(r.d)).slice(0,o))if(n=n.slice(o-3,o+1),n==`9999`||!i&&n==`4999`){if(!i&&(L(s,e+1,0),s.times(s).times(s).eq(u))){r=s;break}o+=4,i=1}else{(!+n||!+n.slice(1)&&n.charAt(0)==`5`)&&(L(r,e+1,1),t=!r.times(r).times(r).eq(u));break}return P=!0,L(r,e,d.rounding,t)},I.decimalPlaces=I.dp=function(){var e,t=this.d,n=NaN;if(t){if(e=t.length-1,n=(e-He(this.e/F))*F,e=t[e],e)for(;e%10==0;e/=10)n--;n<0&&(n=0)}return n},I.dividedBy=I.div=function(e){return rt(this,new this.constructor(e))},I.dividedToIntegerBy=I.divToInt=function(e){var t=this,n=t.constructor;return L(rt(t,new n(e),0,1,1),n.precision,n.rounding)},I.equals=I.eq=function(e){return this.cmp(e)===0},I.floor=function(){return L(new this.constructor(this),this.e+1,3)},I.greaterThan=I.gt=function(e){return this.cmp(e)>0},I.greaterThanOrEqualTo=I.gte=function(e){var t=this.cmp(e);return t==1||t===0},I.hyperbolicCosine=I.cosh=function(){var e,t,n,r,i,a=this,o=a.constructor,s=new o(1);if(!a.isFinite())return new o(a.s?1/0:NaN);if(a.isZero())return s;n=o.precision,r=o.rounding,o.precision=n+Math.max(a.e,a.sd())+4,o.rounding=1,i=a.d.length,i<32?(e=Math.ceil(i/3),t=(1/bt(4,e)).toString()):(e=16,t=`2.3283064365386962890625e-10`),a=yt(o,1,a.times(t),new o(1),!0);for(var c,l=e,u=new o(8);l--;)c=a.times(a),a=s.minus(c.times(u.minus(c.times(u))));return L(a,o.precision=n,o.rounding=r,!0)},I.hyperbolicSine=I.sinh=function(){var e,t,n,r,i=this,a=i.constructor;if(!i.isFinite()||i.isZero())return new a(i);if(t=a.precision,n=a.rounding,a.precision=t+Math.max(i.e,i.sd())+4,a.rounding=1,r=i.d.length,r<3)i=yt(a,2,i,i,!0);else{e=1.4*Math.sqrt(r),e=e>16?16:e|0,i=i.times(1/bt(5,e)),i=yt(a,2,i,i,!0);for(var o,s=new a(5),c=new a(16),l=new a(20);e--;)o=i.times(i),i=i.times(s.plus(o.times(c.times(o).plus(l))))}return a.precision=t,a.rounding=n,L(i,t,n,!0)},I.hyperbolicTangent=I.tanh=function(){var e,t,n=this,r=n.constructor;return n.isFinite()?n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+7,r.rounding=1,rt(n.sinh(),n.cosh(),r.precision=e,r.rounding=t)):new r(n.s)},I.inverseCosine=I.acos=function(){var e=this,t=e.constructor,n=e.abs().cmp(1),r=t.precision,i=t.rounding;return n===-1?e.isZero()?st(t,r+4,i).times(.5):(t.precision=r+6,t.rounding=1,e=new t(1).minus(e).div(e.plus(1)).sqrt().atan(),t.precision=r,t.rounding=i,e.times(2)):n===0?e.isNeg()?st(t,r,i):new t(0):new t(NaN)},I.inverseHyperbolicCosine=I.acosh=function(){var e,t,n=this,r=n.constructor;return n.lte(1)?new r(n.eq(1)?0:NaN):n.isFinite()?(e=r.precision,t=r.rounding,r.precision=e+Math.max(Math.abs(n.e),n.sd())+4,r.rounding=1,P=!1,n=n.times(n).minus(1).sqrt().plus(n),P=!0,r.precision=e,r.rounding=t,n.ln()):new r(n)},I.inverseHyperbolicSine=I.asinh=function(){var e,t,n=this,r=n.constructor;return!n.isFinite()||n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+2*Math.max(Math.abs(n.e),n.sd())+6,r.rounding=1,P=!1,n=n.times(n).plus(1).sqrt().plus(n),P=!0,r.precision=e,r.rounding=t,n.ln())},I.inverseHyperbolicTangent=I.atanh=function(){var e,t,n,r,i=this,a=i.constructor;return i.isFinite()?i.e>=0?new a(i.abs().eq(1)?i.s/0:i.isZero()?i:NaN):(e=a.precision,t=a.rounding,r=i.sd(),Math.max(r,e)<2*-i.e-1?L(new a(i),e,t,!0):(a.precision=n=r-i.e,i=rt(i.plus(1),new a(1).minus(i),n+e,1),a.precision=e+4,a.rounding=1,i=i.ln(),a.precision=e,a.rounding=t,i.times(.5))):new a(NaN)},I.inverseSine=I.asin=function(){var e,t,n,r,i=this,a=i.constructor;return i.isZero()?new a(i):(t=i.abs().cmp(1),n=a.precision,r=a.rounding,t===-1?(a.precision=n+6,a.rounding=1,i=i.div(new a(1).minus(i.times(i)).sqrt().plus(1)).atan(),a.precision=n,a.rounding=r,i.times(2)):t===0?(e=st(a,n+4,r).times(.5),e.s=i.s,e):new a(NaN))},I.inverseTangent=I.atan=function(){var e,t,n,r,i,a,o,s,c,l=this,u=l.constructor,d=u.precision,f=u.rounding;if(!l.isFinite()){if(!l.s)return new u(NaN);if(d+4<=Ze)return o=st(u,d+4,f).times(.5),o.s=l.s,o}else if(l.isZero())return new u(l);else if(l.abs().eq(1)&&d+4<=Ze)return o=st(u,d+4,f).times(.25),o.s=l.s,o;for(u.precision=s=d+10,u.rounding=1,n=Math.min(28,s/F+2|0),e=n;e;--e)l=l.div(l.times(l).plus(1).sqrt().plus(1));for(P=!1,t=Math.ceil(s/F),r=1,c=l.times(l),o=new u(l),i=l;e!==-1;)if(i=i.times(c),a=o.minus(i.div(r+=2)),i=i.times(c),o=a.plus(i.div(r+=2)),o.d[t]!==void 0)for(e=t;o.d[e]===a.d[e]&&e--;);return n&&(o=o.times(2<this.d.length-2},I.isNaN=function(){return!this.s},I.isNegative=I.isNeg=function(){return this.s<0},I.isPositive=I.isPos=function(){return this.s>0},I.isZero=function(){return!!this.d&&this.d[0]===0},I.lessThan=I.lt=function(e){return this.cmp(e)<0},I.lessThanOrEqualTo=I.lte=function(e){return this.cmp(e)<1},I.logarithm=I.log=function(e){var t,n,r,i,a,o,s,c,l=this,u=l.constructor,d=u.precision,f=u.rounding,p=5;if(e==null)e=new u(10),t=!0;else{if(e=new u(e),n=e.d,e.s<0||!n||!n[0]||e.eq(1))return new u(NaN);t=e.eq(10)}if(n=l.d,l.s<0||!n||!n[0]||l.eq(1))return new u(n&&!n[0]?-1/0:l.s==1?n?0:1/0:NaN);if(t)if(n.length>1)a=!0;else{for(i=n[0];i%10==0;)i/=10;a=i!==1}if(P=!1,s=d+p,o=mt(l,s),r=t?ot(u,s+10):mt(e,s),c=rt(o,r,s,1),et(c.d,i=d,f))do if(s+=10,o=mt(l,s),r=t?ot(u,s+10):mt(e,s),c=rt(o,r,s,1),!a){+Qe(c.d).slice(i+1,i+15)+1==0x5af3107a4000&&(c=L(c,d+1,0));break}while(et(c.d,i+=10,f));return P=!0,L(c,d,f)},I.minus=I.sub=function(e){var t,n,r,i,a,o,s,c,l,u,d,f,p=this,m=p.constructor;if(e=new m(e),!p.d||!e.d)return!p.s||!e.s?e=new m(NaN):p.d?e.s=-e.s:e=new m(e.d||p.s!==e.s?p:NaN),e;if(p.s!=e.s)return e.s=-e.s,p.plus(e);if(l=p.d,f=e.d,s=m.precision,c=m.rounding,!l[0]||!f[0]){if(f[0])e.s=-e.s;else if(l[0])e=new m(p);else return new m(c===3?-0:0);return P?L(e,s,c):e}if(n=He(e.e/F),u=He(p.e/F),l=l.slice(),a=u-n,a){for(d=a<0,d?(t=l,a=-a,o=f.length):(t=f,n=u,o=l.length),r=Math.max(Math.ceil(s/F),o)+2,a>r&&(a=r,t.length=1),t.reverse(),r=a;r--;)t.push(0);t.reverse()}else{for(r=l.length,o=f.length,d=r0;--r)l[o++]=0;for(r=f.length;r>a;){if(l[--r]o?a+1:o+1,i>o&&(i=o,n.length=1),n.reverse();i--;)n.push(0);n.reverse()}for(o=l.length,i=u.length,o-i<0&&(i=o,n=u,u=l,l=n),t=0;i;)t=(l[--i]=l[i]+u[i]+t)/Je|0,l[i]%=Je;for(t&&(l.unshift(t),++r),o=l.length;l[--o]==0;)l.pop();return e.d=l,e.e=at(l,r),P?L(e,s,c):e},I.precision=I.sd=function(e){var t,n=this;if(e!==void 0&&e!==!!e&&e!==1&&e!==0)throw Error(Re+e);return n.d?(t=ct(n.d),e&&n.e+1>t&&(t=n.e+1)):t=NaN,t},I.round=function(){var e=this,t=e.constructor;return L(new t(e),e.e+1,t.rounding)},I.sine=I.sin=function(){var e,t,n=this,r=n.constructor;return n.isFinite()?n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+Math.max(n.e,n.sd())+F,r.rounding=1,n=vt(r,xt(r,n)),r.precision=e,r.rounding=t,L(Ie>2?n.neg():n,e,t,!0)):new r(NaN)},I.squareRoot=I.sqrt=function(){var e,t,n,r,i,a,o=this,s=o.d,c=o.e,l=o.s,u=o.constructor;if(l!==1||!s||!s[0])return new u(!l||l<0&&(!s||s[0])?NaN:s?o:1/0);for(P=!1,l=Math.sqrt(+o),l==0||l==1/0?(t=Qe(s),(t.length+c)%2==0&&(t+=`0`),l=Math.sqrt(t),c=He((c+1)/2)-(c<0||c%2),l==1/0?t=`5e`+c:(t=l.toExponential(),t=t.slice(0,t.indexOf(`e`)+1)+c),r=new u(t)):r=new u(l.toString()),n=(c=u.precision)+3;;)if(a=r,r=a.plus(rt(o,a,n+2,1)).times(.5),Qe(a.d).slice(0,n)===(t=Qe(r.d)).slice(0,n))if(t=t.slice(n-3,n+1),t==`9999`||!i&&t==`4999`){if(!i&&(L(a,c+1,0),a.times(a).eq(o))){r=a;break}n+=4,i=1}else{(!+t||!+t.slice(1)&&t.charAt(0)==`5`)&&(L(r,c+1,1),e=!r.times(r).eq(o));break}return P=!0,L(r,c,u.rounding,e)},I.tangent=I.tan=function(){var e,t,n=this,r=n.constructor;return n.isFinite()?n.isZero()?new r(n):(e=r.precision,t=r.rounding,r.precision=e+10,r.rounding=1,n=n.sin(),n.s=1,n=rt(n,new r(1).minus(n.times(n)).sqrt(),e+10,0),r.precision=e,r.rounding=t,L(Ie==2||Ie==4?n.neg():n,e,t,!0)):new r(NaN)},I.times=I.mul=function(e){var t,n,r,i,a,o,s,c,l,u=this,d=u.constructor,f=u.d,p=(e=new d(e)).d;if(e.s*=u.s,!f||!f[0]||!p||!p[0])return new d(!e.s||f&&!f[0]&&!p||p&&!p[0]&&!f?NaN:!f||!p?e.s/0:e.s*0);for(n=He(u.e/F)+He(e.e/F),c=f.length,l=p.length,c=0;){for(t=0,i=c+r;i>r;)s=a[i]+p[r]*f[i-r-1]+t,a[i--]=s%Je|0,t=s/Je|0;a[i]=(a[i]+t)%Je|0}for(;!a[--o];)a.pop();return t?++n:a.shift(),e.d=a,e.e=at(a,n),P?L(e,d.precision,d.rounding):e},I.toBinary=function(e,t){return St(this,2,e,t)},I.toDecimalPlaces=I.toDP=function(e,t){var n=this,r=n.constructor;return n=new r(n),e===void 0?n:($e(e,0,Ae),t===void 0?t=r.rounding:$e(t,0,8),L(n,e+n.e+1,t))},I.toExponential=function(e,t){var n,r=this,i=r.constructor;return e===void 0?n=it(r,!0):($e(e,0,Ae),t===void 0?t=i.rounding:$e(t,0,8),r=L(new i(r),e+1,t),n=it(r,!0,e+1)),r.isNeg()&&!r.isZero()?`-`+n:n},I.toFixed=function(e,t){var n,r,i=this,a=i.constructor;return e===void 0?n=it(i):($e(e,0,Ae),t===void 0?t=a.rounding:$e(t,0,8),r=L(new a(i),e+i.e+1,t),n=it(r,!1,e+r.e+1)),i.isNeg()&&!i.isZero()?`-`+n:n},I.toFraction=function(e){var t,n,r,i,a,o,s,c,l,u,d,f,p=this,m=p.d,h=p.constructor;if(!m)return new h(p);if(l=n=new h(1),r=c=new h(0),t=new h(r),a=t.e=ct(m)-p.e-1,o=a%F,t.d[0]=Ue(10,o<0?F+o:o),e==null)e=a>0?t:l;else{if(s=new h(e),!s.isInt()||s.lt(l))throw Error(Re+s);e=s.gt(t)?a>0?t:l:s}for(P=!1,s=new h(Qe(m)),u=h.precision,h.precision=a=m.length*F*2;d=rt(s,t,0,1,1),i=n.plus(d.times(r)),i.cmp(e)!=1;)n=r,r=i,i=l,l=c.plus(d.times(i)),c=i,i=t,t=s.minus(d.times(i)),s=i;return i=rt(e.minus(n),r,0,1,1),c=c.plus(i.times(l)),n=n.plus(i.times(r)),c.s=l.s=p.s,f=rt(l,r,a,1).minus(p).abs().cmp(rt(c,n,a,1).minus(p).abs())<1?[l,r]:[c,n],h.precision=u,P=!0,f},I.toHexadecimal=I.toHex=function(e,t){return St(this,16,e,t)},I.toNearest=function(e,t){var n=this,r=n.constructor;if(n=new r(n),e==null){if(!n.d)return n;e=new r(1),t=r.rounding}else{if(e=new r(e),t===void 0?t=r.rounding:$e(t,0,8),!n.d)return e.s?n:e;if(!e.d)return e.s&&=n.s,e}return e.d[0]?(P=!1,n=rt(n,e,0,t,1).times(e),P=!0,L(n)):(e.s=n.s,n=e),n},I.toNumber=function(){return+this},I.toOctal=function(e,t){return St(this,8,e,t)},I.toPower=I.pow=function(e){var t,n,r,i,a,o,s=this,c=s.constructor,l=+(e=new c(e));if(!s.d||!e.d||!s.d[0]||!e.d[0])return new c(Ue(+s,l));if(s=new c(s),s.eq(1))return s;if(r=c.precision,a=c.rounding,e.eq(1))return L(s,r,a);if(t=He(e.e/F),t>=e.d.length-1&&(n=l<0?-l:l)<=Ye)return i=ut(c,s,n,r),e.s<0?new c(1).div(i):L(i,r,a);if(o=s.s,o<0){if(tc.maxE+1||t0?o/0:0):(P=!1,c.rounding=s.s=1,n=Math.min(12,(t+``).length),i=pt(e.times(mt(s,r+n)),r),i.d&&(i=L(i,r+5,1),et(i.d,r,a)&&(t=r+10,i=L(pt(e.times(mt(s,t+n)),t),t+5,1),+Qe(i.d).slice(r+1,r+15)+1==0x5af3107a4000&&(i=L(i,r+1,0)))),i.s=o,P=!0,c.rounding=a,L(i,r,a))},I.toPrecision=function(e,t){var n,r=this,i=r.constructor;return e===void 0?n=it(r,r.e<=i.toExpNeg||r.e>=i.toExpPos):($e(e,1,Ae),t===void 0?t=i.rounding:$e(t,0,8),r=L(new i(r),e,t),n=it(r,e<=r.e||r.e<=i.toExpNeg,e)),r.isNeg()&&!r.isZero()?`-`+n:n},I.toSignificantDigits=I.toSD=function(e,t){var n=this,r=n.constructor;return e===void 0?(e=r.precision,t=r.rounding):($e(e,1,Ae),t===void 0?t=r.rounding:$e(t,0,8)),L(new r(n),e,t)},I.toString=function(){var e=this,t=e.constructor,n=it(e,e.e<=t.toExpNeg||e.e>=t.toExpPos);return e.isNeg()&&!e.isZero()?`-`+n:n},I.truncated=I.trunc=function(){return L(new this.constructor(this),this.e+1,1)},I.valueOf=I.toJSON=function(){var e=this,t=e.constructor,n=it(e,e.e<=t.toExpNeg||e.e>=t.toExpPos);return e.isNeg()?`-`+n:n};function Qe(e){var t,n,r,i=e.length-1,a=``,o=e[0];if(i>0){for(a+=o,t=1;tn)throw Error(Re+e)}function et(e,t,n,r){var i,a,o,s;for(a=e[0];a>=10;a/=10)--t;return--t<0?(t+=F,i=0):(i=Math.ceil((t+1)/F),t%=F),a=Ue(10,F-t),s=e[i]%a|0,r==null?t<3?(t==0?s=s/100|0:t==1&&(s=s/10|0),o=n<4&&s==99999||n>3&&s==49999||s==5e4||s==0):o=(n<4&&s+1==a||n>3&&s+1==a/2)&&(e[i+1]/a/100|0)==Ue(10,t-2)-1||(s==a/2||s==0)&&(e[i+1]/a/100|0)==0:t<4?(t==0?s=s/1e3|0:t==1?s=s/100|0:t==2&&(s=s/10|0),o=(r||n<4)&&s==9999||!r&&n>3&&s==4999):o=((r||n<4)&&s+1==a||!r&&n>3&&s+1==a/2)&&(e[i+1]/a/1e3|0)==Ue(10,t-3)-1,o}function tt(e,t,n){for(var r,i=[0],a,o=0,s=e.length;on-1&&(i[r+1]===void 0&&(i[r+1]=0),i[r+1]+=i[r]/n|0,i[r]%=n)}return i.reverse()}function nt(e,t){var n,r,i;if(t.isZero())return t;r=t.d.length,r<32?(n=Math.ceil(r/3),i=(1/bt(4,n)).toString()):(n=16,i=`2.3283064365386962890625e-10`),e.precision+=n,t=yt(e,1,t.times(i),new e(1));for(var a=n;a--;){var o=t.times(t);t=o.times(o).minus(o).times(8).plus(1)}return e.precision-=n,t}var rt=(function(){function e(e,t,n){var r,i=0,a=e.length;for(e=e.slice();a--;)r=e[a]*t+i,e[a]=r%n|0,i=r/n|0;return i&&e.unshift(i),e}function t(e,t,n,r){var i,a;if(n!=r)a=n>r?1:-1;else for(i=a=0;it[i]?1:-1;break}return a}function n(e,t,n,r){for(var i=0;n--;)e[n]-=i,i=+(e[n]1;)e.shift()}return function(r,i,a,o,s,c){var l,u,d,f,p,m,h,g,_,v,y,b,x,S,C,w,T,E,D,ee,te=r.constructor,ne=r.s==i.s?1:-1,O=r.d,k=i.d;if(!O||!O[0]||!k||!k[0])return new te(!r.s||!i.s||(O?k&&O[0]==k[0]:!k)?NaN:O&&O[0]==0||!k?ne*0:ne/0);for(c?(p=1,u=r.e-i.e):(c=Je,p=F,u=He(r.e/p)-He(i.e/p)),D=k.length,T=O.length,_=new te(ne),v=_.d=[],d=0;k[d]==(O[d]||0);d++);if(k[d]>(O[d]||0)&&u--,a==null?(S=a=te.precision,o=te.rounding):S=s?a+(r.e-i.e)+1:a,S<0)v.push(1),m=!0;else{if(S=S/p+2|0,d=0,D==1){for(f=0,k=k[0],S++;(d1&&(k=e(k,f,c),O=e(O,f,c),D=k.length,T=O.length),w=D,y=O.slice(0,D),b=y.length;b=c/2&&++E;do f=0,l=t(k,y,D,b),l<0?(x=y[0],D!=b&&(x=x*c+(y[1]||0)),f=x/E|0,f>1?(f>=c&&(f=c-1),h=e(k,f,c),g=h.length,b=y.length,l=t(h,y,g,b),l==1&&(f--,n(h,D=10;f/=10)d++;_.e=d+u*p-1,L(_,s?a+_.e+1:a,o,m)}return _}})();function L(e,t,n,r){var i,a,o,s,c,l,u,d,f,p=e.constructor;out:if(t!=null){if(d=e.d,!d)return e;for(i=1,s=d[0];s>=10;s/=10)i++;if(a=t-i,a<0)a+=F,o=t,u=d[f=0],c=u/Ue(10,i-o-1)%10|0;else if(f=Math.ceil((a+1)/F),s=d.length,f>=s)if(r){for(;s++<=f;)d.push(0);u=c=0,i=1,a%=F,o=a-F+1}else break out;else{for(u=s=d[f],i=1;s>=10;s/=10)i++;a%=F,o=a-F+i,c=o<0?0:u/Ue(10,i-o-1)%10|0}if(r=r||t<0||d[f+1]!==void 0||(o<0?u:u%Ue(10,i-o-1)),l=n<4?(c||r)&&(n==0||n==(e.s<0?3:2)):c>5||c==5&&(n==4||r||n==6&&(a>0?o>0?u/Ue(10,i-o):0:d[f-1])%10&1||n==(e.s<0?8:7)),t<1||!d[0])return d.length=0,l?(t-=e.e+1,d[0]=Ue(10,(F-t%F)%F),e.e=-t||0):d[0]=e.e=0,e;if(a==0?(d.length=f,s=1,f--):(d.length=f+1,s=Ue(10,F-a),d[f]=o>0?(u/Ue(10,i-o)%Ue(10,o)|0)*s:0),l)for(;;)if(f==0){for(a=1,o=d[0];o>=10;o/=10)a++;for(o=d[0]+=s,s=1;o>=10;o/=10)s++;a!=s&&(e.e++,d[0]==Je&&(d[0]=1));break}else{if(d[f]+=s,d[f]!=Je)break;d[f--]=0,s=1}for(a=d.length;d[--a]===0;)d.pop()}return P&&(e.e>p.maxE?(e.d=null,e.e=NaN):e.e0?a=a.charAt(0)+`.`+a.slice(1)+lt(r):o>1&&(a=a.charAt(0)+`.`+a.slice(1)),a=a+(e.e<0?`e`:`e+`)+e.e):i<0?(a=`0.`+lt(-i-1)+a,n&&(r=n-o)>0&&(a+=lt(r))):i>=o?(a+=lt(i+1-o),n&&(r=n-i-1)>0&&(a=a+`.`+lt(r))):((r=i+1)0&&(i+1===o&&(a+=`.`),a+=lt(r))),a}function at(e,t){var n=e[0];for(t*=F;n>=10;n/=10)t++;return t}function ot(e,t,n){if(t>Xe)throw P=!0,n&&(e.precision=n),Error(ze);return L(new e(Me),t,1,!0)}function st(e,t,n){if(t>Ze)throw Error(ze);return L(new e(Ne),t,n,!0)}function ct(e){var t=e.length-1,n=t*F+1;if(t=e[t],t){for(;t%10==0;t/=10)n--;for(t=e[0];t>=10;t/=10)n++}return n}function lt(e){for(var t=``;e--;)t+=`0`;return t}function ut(e,t,n,r){var i,a=new e(1),o=Math.ceil(r/F+4);for(P=!1;;){if(n%2&&(a=a.times(t),Ct(a.d,o)&&(i=!0)),n=He(n/2),n===0){n=a.d.length-1,i&&a.d[n]===0&&++a.d[n];break}t=t.times(t),Ct(t.d,o)}return P=!0,a}function dt(e){return e.d[e.d.length-1]&1}function ft(e,t,n){for(var r,i,a=new e(t[0]),o=0;++o17)return new f(e.d?e.d[0]?e.s<0?0:1/0:1:e.s?e.s<0?0:e:NaN);for(t==null?(P=!1,c=m):c=t,s=new f(.03125);e.e>-2;)e=e.times(s),d+=5;for(r=Math.log(Ue(2,d))/Math.LN10*2+5|0,c+=r,n=a=o=new f(1),f.precision=c;;){if(a=L(a.times(e),c,1),n=n.times(++u),s=o.plus(rt(a,n,c,1)),Qe(s.d).slice(0,c)===Qe(o.d).slice(0,c)){for(i=d;i--;)o=L(o.times(o),c,1);if(t==null)if(l<3&&et(o.d,c-r,p,l))f.precision=c+=10,n=a=s=new f(1),u=0,l++;else return L(o,f.precision=m,p,P=!0);else return f.precision=m,o}o=s}}function mt(e,t){var n,r,i,a,o,s,c,l,u,d,f,p=1,m=10,h=e,g=h.d,_=h.constructor,v=_.rounding,y=_.precision;if(h.s<0||!g||!g[0]||!h.e&&g[0]==1&&g.length==1)return new _(g&&!g[0]?-1/0:h.s==1?g?0:h:NaN);if(t==null?(P=!1,u=y):u=t,_.precision=u+=m,n=Qe(g),r=n.charAt(0),Math.abs(a=h.e)<0x5543df729c000){for(;r<7&&r!=1||r==1&&n.charAt(1)>3;)h=h.times(e),n=Qe(h.d),r=n.charAt(0),p++;a=h.e,r>1?(h=new _(`0.`+n),a++):h=new _(r+`.`+n.slice(1))}else return l=ot(_,u+2,y).times(a+``),h=mt(new _(r+`.`+n.slice(1)),u-m).plus(l),_.precision=y,t==null?L(h,y,v,P=!0):h;for(d=h,c=o=h=rt(h.minus(1),h.plus(1),u,1),f=L(h.times(h),u,1),i=3;;){if(o=L(o.times(f),u,1),l=c.plus(rt(o,new _(i),u,1)),Qe(l.d).slice(0,u)===Qe(c.d).slice(0,u))if(c=c.times(2),a!==0&&(c=c.plus(ot(_,u+2,y).times(a+``))),c=rt(c,new _(p),u,1),t==null)if(et(c.d,u-m,v,s))_.precision=u+=m,l=o=h=rt(d.minus(1),d.plus(1),u,1),f=L(h.times(h),u,1),i=s=1;else return L(c,_.precision=y,v,P=!0);else return _.precision=y,c;c=l,i+=2}}function ht(e){return String(e.s*e.s/0)}function gt(e,t){var n,r,i;for((n=t.indexOf(`.`))>-1&&(t=t.replace(`.`,``)),(r=t.search(/e/i))>0?(n<0&&(n=r),n+=+t.slice(r+1),t=t.substring(0,r)):n<0&&(n=t.length),r=0;t.charCodeAt(r)===48;r++);for(i=t.length;t.charCodeAt(i-1)===48;--i);if(t=t.slice(r,i),t){if(i-=r,e.e=n=n-r-1,e.d=[],r=(n+1)%F,n<0&&(r+=F),re.constructor.maxE?(e.d=null,e.e=NaN):e.e-1){if(t=t.replace(/(\d)_(?=\d)/g,`$1`),qe.test(t))return gt(e,t)}else if(t===`Infinity`||t===`NaN`)return+t||(e.s=NaN),e.e=NaN,e.d=null,e;if(Ge.test(t))n=16,t=t.toLowerCase();else if(We.test(t))n=2;else if(Ke.test(t))n=8;else throw Error(Re+t);for(a=t.search(/p/i),a>0?(c=+t.slice(a+1),t=t.substring(2,a)):t=t.slice(2),a=t.indexOf(`.`),o=a>=0,r=e.constructor,o&&(t=t.replace(`.`,``),s=t.length,a=s-a,i=ut(r,new r(n),a,a*2)),l=tt(t,n,Je),u=l.length-1,a=u;l[a]===0;--a)l.pop();return a<0?new r(e.s*0):(e.e=at(l,u),e.d=l,P=!1,o&&(e=rt(e,i,s*4)),c&&(e=e.times(Math.abs(c)<54?Ue(2,c):R.pow(2,c))),P=!0,e)}function vt(e,t){var n,r=t.d.length;if(r<3)return t.isZero()?t:yt(e,2,t,t);n=1.4*Math.sqrt(r),n=n>16?16:n|0,t=t.times(1/bt(5,n)),t=yt(e,2,t,t);for(var i,a=new e(5),o=new e(16),s=new e(20);n--;)i=t.times(t),t=t.times(a.plus(i.times(o.times(i).minus(s))));return t}function yt(e,t,n,r,i){var a,o,s,c,l=1,u=e.precision,d=Math.ceil(u/F);for(P=!1,c=n.times(n),s=new e(r);;){if(o=rt(s.times(c),new e(t++*t++),u,1),s=i?r.plus(o):r.minus(o),r=rt(o.times(c),new e(t++*t++),u,1),o=s.plus(r),o.d[d]!==void 0){for(a=d;o.d[a]===s.d[a]&&a--;);if(a==-1)break}a=s,s=r,r=o,o=a,l++}return P=!0,o.d.length=d+1,o}function bt(e,t){for(var n=e;--t;)n*=e;return n}function xt(e,t){var n,r=t.s<0,i=st(e,e.precision,1),a=i.times(.5);if(t=t.abs(),t.lte(a))return Ie=r?4:1,t;if(n=t.divToInt(i),n.isZero())Ie=r?3:2;else{if(t=t.minus(n.times(i)),t.lte(a))return Ie=dt(n)?r?2:3:r?4:1,t;Ie=dt(n)?r?1:4:r?3:2}return t.minus(i).abs()}function St(e,t,n,r){var i,a,o,s,c,l,u,d,f,p=e.constructor,m=n!==void 0;if(m?($e(n,1,Ae),r===void 0?r=p.rounding:$e(r,0,8)):(n=p.precision,r=p.rounding),!e.isFinite())u=ht(e);else{for(u=it(e),o=u.indexOf(`.`),m?(i=2,t==16?n=n*4-3:t==8&&(n=n*3-2)):i=t,o>=0&&(u=u.replace(`.`,``),f=new p(1),f.e=u.length-o,f.d=tt(it(f),10,i),f.e=f.d.length),d=tt(u,10,i),a=c=d.length;d[--c]==0;)d.pop();if(!d[0])u=m?`0p+0`:`0`;else{if(o<0?a--:(e=new p(e),e.d=d,e.e=a,e=rt(e,f,n,r,0,i),d=e.d,a=e.e,l=Fe),o=d[n],s=i/2,l||=d[n+1]!==void 0,l=r<4?(o!==void 0||l)&&(r===0||r===(e.s<0?3:2)):o>s||o===s&&(r===4||l||r===6&&d[n-1]&1||r===(e.s<0?8:7)),d.length=n,l)for(;++d[--n]>i-1;)d[n]=0,n||(++a,d.unshift(1));for(c=d.length;!d[c-1];--c);for(o=0,u=``;o1)if(t==16||t==8){for(o=t==16?4:3,--c;c%o;c++)u+=`0`;for(d=tt(u,i,t),c=d.length;!d[c-1];--c);for(o=1,u=`1.`;oc)for(a-=c;a--;)u+=`0`;else at)return e.length=t,!0}function wt(e){return new this(e).abs()}function Tt(e){return new this(e).acos()}function Et(e){return new this(e).acosh()}function Dt(e,t){return new this(e).plus(t)}function Ot(e){return new this(e).asin()}function kt(e){return new this(e).asinh()}function At(e){return new this(e).atan()}function jt(e){return new this(e).atanh()}function Mt(e,t){e=new this(e),t=new this(t);var n,r=this.precision,i=this.rounding,a=r+4;return!e.s||!t.s?n=new this(NaN):!e.d&&!t.d?(n=st(this,a,1).times(t.s>0?.25:.75),n.s=e.s):!t.d||e.isZero()?(n=t.s<0?st(this,r,i):new this(0),n.s=e.s):!e.d||t.isZero()?(n=st(this,a,1).times(.5),n.s=e.s):t.s<0?(this.precision=a,this.rounding=1,n=this.atan(rt(e,t,a,1)),t=st(this,a,1),this.precision=r,this.rounding=i,n=e.s<0?n.minus(t):n.plus(t)):n=this.atan(rt(e,t,a,1)),n}function Nt(e){return new this(e).cbrt()}function Pt(e){return L(e=new this(e),e.e+1,2)}function Ft(e,t,n){return new this(e).clamp(t,n)}function It(e){if(!e||typeof e!=`object`)throw Error(Le+`Object expected`);var t,n,r,i=e.defaults===!0,a=[`precision`,1,Ae,`rounding`,0,8,`toExpNeg`,-ke,0,`toExpPos`,0,ke,`maxE`,0,ke,`minE`,-ke,0,`modulo`,0,9];for(t=0;t=a[t+1]&&r<=a[t+2])this[n]=r;else throw Error(Re+n+`: `+r);if(n=`crypto`,i&&(this[n]=Pe[n]),(r=e[n])!==void 0)if(r===!0||r===!1||r===0||r===1)if(r)if(typeof crypto<`u`&&crypto&&(crypto.getRandomValues||crypto.randomBytes))this[n]=!0;else throw Error(Be);else this[n]=!1;else throw Error(Re+n+`: `+r);return this}function Lt(e){return new this(e).cos()}function Rt(e){return new this(e).cosh()}function zt(e){var t,n,r;function i(e){var t,n,r,a=this;if(!(a instanceof i))return new i(e);if(a.constructor=i,Wt(e)){a.s=e.s,P?!e.d||e.e>i.maxE?(a.e=NaN,a.d=null):e.e=10;n/=10)t++;P?t>i.maxE?(a.e=NaN,a.d=null):t=429e7?t[a]=crypto.getRandomValues(new Uint32Array(1))[0]:s[a++]=i%1e7;else if(crypto.randomBytes){for(t=crypto.randomBytes(r*=4);a=214e7?crypto.randomBytes(4).copy(t,a):(s.push(i%1e7),a+=4);a=r/4}else throw Error(Be);for(r=s[--a],e%=F,r&&e&&(i=Ue(10,F-e),s[a]=(r/i|0)*i);s[a]===0;a--)s.pop();if(a<0)n=0,s=[0];else{for(n=-1;s[0]===0;n-=F)s.shift();for(r=1,i=s[0];i>=10;i/=10)r++;r{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),pn=he(((e,t)=>{t.exports=fn()})),mn=(0,N.createContext)({});function hn(e){let t=(0,N.useRef)(null);return t.current===null&&(t.current=e()),t.current}var gn=typeof window<`u`?N.useLayoutEffect:N.useEffect,_n=(0,N.createContext)(null);function vn(e,t){e.indexOf(t)===-1&&e.push(t)}function yn(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}var bn=(e,t,n)=>n>t?t:n/^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(e);function Cn(e){return typeof e==`object`&&!!e}var wn=e=>/^0[^.\s]+$/u.test(e);function Tn(e){let t;return()=>(t===void 0&&(t=e()),t)}var En=e=>e,Dn=(e,t)=>n=>t(e(n)),On=(...e)=>e.reduce(Dn),kn=(e,t,n)=>{let r=t-e;return r===0?1:(n-e)/r},An=class{constructor(){this.subscriptions=[]}add(e){return vn(this.subscriptions,e),()=>yn(this.subscriptions,e)}notify(e,t,n){let r=this.subscriptions.length;if(r)if(r===1)this.subscriptions[0](e,t,n);else for(let i=0;ie*1e3,Mn=e=>e/1e3;function Nn(e,t){return t?1e3/t*e:0}var Pn=(e,t,n)=>(((1-3*n+3*t)*e+(3*n-6*t))*e+3*t)*e,Fn=1e-7,In=12;function Ln(e,t,n,r,i){let a,o,s=0;do o=t+(n-t)/2,a=Pn(o,r,i)-e,a>0?n=o:t=o;while(Math.abs(a)>Fn&&++sLn(t,0,1,e,n);return e=>e===0||e===1?e:Pn(i(e),t,r)}var zn=e=>t=>t<=.5?e(2*t)/2:(2-e(2*(1-t)))/2,Bn=e=>t=>1-e(1-t),Vn=Rn(.33,1.53,.69,.99),Hn=Bn(Vn),Un=zn(Hn),Wn=e=>e>=1?1:(e*=2)<1?.5*Hn(e):.5*(2-2**(-10*(e-1))),Gn=e=>1-Math.sin(Math.acos(e)),Kn=Bn(Gn),qn=zn(Gn),Jn=Rn(.42,0,1,1),Yn=Rn(0,0,.58,1),Xn=Rn(.42,0,.58,1),Zn=e=>Array.isArray(e)&&typeof e[0]!=`number`,Qn=e=>Array.isArray(e)&&typeof e[0]==`number`,$n={linear:En,easeIn:Jn,easeInOut:Xn,easeOut:Yn,circIn:Gn,circInOut:qn,circOut:Kn,backIn:Hn,backInOut:Un,backOut:Vn,anticipate:Wn},er=e=>typeof e==`string`,tr=e=>{if(Qn(e)){e.length;let[t,n,r,i]=e;return Rn(t,n,r,i)}else if(er(e))return $n[e],`${e}`,$n[e];return e},nr=[`setup`,`read`,`resolveKeyframes`,`preUpdate`,`update`,`preRender`,`render`,`postRender`],rr={value:null,addProjectionMetrics:null};function ir(e,t){let n=new Set,r=new Set,i=!1,a=!1,o=new WeakSet,s={delta:0,timestamp:0,isProcessing:!1},c=0;function l(t){o.has(t)&&(u.schedule(t),e()),c++,t(s)}let u={schedule:(e,t=!1,a=!1)=>{let s=a&&i?n:r;return t&&o.add(e),s.add(e),e},cancel:e=>{r.delete(e),o.delete(e)},process:e=>{if(s=e,i){a=!0;return}i=!0;let o=n;n=r,r=o,n.forEach(l),t&&rr.value&&rr.value.frameloop[t].push(c),c=0,n.clear(),i=!1,a&&(a=!1,u.process(e))}};return u}var ar=40;function or(e,t){let n=!1,r=!0,i={delta:0,timestamp:0,isProcessing:!1},a=()=>n=!0,o=nr.reduce((e,n)=>(e[n]=ir(a,t?n:void 0),e),{}),{setup:s,read:c,resolveKeyframes:l,preUpdate:u,update:d,preRender:f,render:p,postRender:m}=o,h=()=>{let a=xn.useManualTiming,o=a?i.timestamp:performance.now();n=!1,a||(i.delta=r?1e3/60:Math.max(Math.min(o-i.timestamp,ar),1)),i.timestamp=o,i.isProcessing=!0,s.process(i),c.process(i),l.process(i),u.process(i),d.process(i),f.process(i),p.process(i),m.process(i),i.isProcessing=!1,n&&t&&(r=!1,e(h))},g=()=>{n=!0,r=!0,i.isProcessing||e(h)};return{schedule:nr.reduce((e,t)=>{let r=o[t];return e[t]=(e,t=!1,i=!1)=>(n||g(),r.schedule(e,t,i)),e},{}),cancel:e=>{for(let t=0;t(dr===void 0&&pr.set(lr.isProcessing||xn.useManualTiming?lr.timestamp:performance.now()),dr),set:e=>{dr=e,queueMicrotask(fr)}},mr={layout:0,mainThread:0,waapi:0},hr=e=>t=>typeof t==`string`&&t.startsWith(e),gr=hr(`--`),_r=hr(`var(--`),vr=e=>_r(e)?yr.test(e.split(`/*`)[0].trim()):!1,yr=/var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;function br(e){return typeof e==`string`?e.split(`/*`)[0].includes(`var(--`):!1}var xr={test:e=>typeof e==`number`,parse:parseFloat,transform:e=>e},Sr={...xr,transform:e=>bn(0,1,e)},Cr={...xr,default:1},wr=e=>Math.round(e*1e5)/1e5,Tr=/-?(?:\d+(?:\.\d+)?|\.\d+)/gu;function Er(e){return e==null}var Dr=/^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu,Or=(e,t)=>n=>!!(typeof n==`string`&&Dr.test(n)&&n.startsWith(e)||t&&!Er(n)&&Object.prototype.hasOwnProperty.call(n,t)),kr=(e,t,n)=>r=>{if(typeof r!=`string`)return r;let[i,a,o,s]=r.match(Tr);return{[e]:parseFloat(i),[t]:parseFloat(a),[n]:parseFloat(o),alpha:s===void 0?1:parseFloat(s)}},Ar=e=>bn(0,255,e),jr={...xr,transform:e=>Math.round(Ar(e))},Mr={test:Or(`rgb`,`red`),parse:kr(`red`,`green`,`blue`),transform:({red:e,green:t,blue:n,alpha:r=1})=>`rgba(`+jr.transform(e)+`, `+jr.transform(t)+`, `+jr.transform(n)+`, `+wr(Sr.transform(r))+`)`};function Nr(e){let t=``,n=``,r=``,i=``;return e.length>5?(t=e.substring(1,3),n=e.substring(3,5),r=e.substring(5,7),i=e.substring(7,9)):(t=e.substring(1,2),n=e.substring(2,3),r=e.substring(3,4),i=e.substring(4,5),t+=t,n+=n,r+=r,i+=i),{red:parseInt(t,16),green:parseInt(n,16),blue:parseInt(r,16),alpha:i?parseInt(i,16)/255:1}}var Pr={test:Or(`#`),parse:Nr,transform:Mr.transform},Fr=e=>({test:t=>typeof t==`string`&&t.endsWith(e)&&t.split(` `).length===1,parse:parseFloat,transform:t=>`${t}${e}`}),Ir=Fr(`deg`),Lr=Fr(`%`),z=Fr(`px`),Rr=Fr(`vh`),zr=Fr(`vw`),Br={...Lr,parse:e=>Lr.parse(e)/100,transform:e=>Lr.transform(e*100)},Vr={test:Or(`hsl`,`hue`),parse:kr(`hue`,`saturation`,`lightness`),transform:({hue:e,saturation:t,lightness:n,alpha:r=1})=>`hsla(`+Math.round(e)+`, `+Lr.transform(wr(t))+`, `+Lr.transform(wr(n))+`, `+wr(Sr.transform(r))+`)`},Hr={test:e=>Mr.test(e)||Pr.test(e)||Vr.test(e),parse:e=>Mr.test(e)?Mr.parse(e):Vr.test(e)?Vr.parse(e):Pr.parse(e),transform:e=>typeof e==`string`?e:e.hasOwnProperty(`red`)?Mr.transform(e):Vr.transform(e),getAnimatableNone:e=>{let t=Hr.parse(e);return t.alpha=0,Hr.transform(t)}},Ur=/(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;function Wr(e){return isNaN(e)&&typeof e==`string`&&(e.match(Tr)?.length||0)+(e.match(Ur)?.length||0)>0}var Gr=`number`,Kr=`color`,qr=`var`,Jr=`var(`,Yr="${}",Xr=/var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;function Zr(e){let t=e.toString(),n=[],r={color:[],number:[],var:[]},i=[],a=0;return{values:n,split:t.replace(Xr,e=>(Hr.test(e)?(r.color.push(a),i.push(Kr),n.push(Hr.parse(e))):e.startsWith(Jr)?(r.var.push(a),i.push(qr),n.push(e)):(r.number.push(a),i.push(Gr),n.push(parseFloat(e))),++a,Yr)).split(Yr),indexes:r,types:i}}function Qr(e){return Zr(e).values}function $r({split:e,types:t}){let n=e.length;return r=>{let i=``;for(let a=0;atypeof e==`number`?0:Hr.test(e)?Hr.getAnimatableNone(e):e,ni=(e,t)=>typeof e==`number`?t?.trim().endsWith(`/`)?e:0:ti(e);function ri(e){let t=Zr(e);return $r(t)(t.values.map((e,n)=>ni(e,t.split[n])))}var ii={test:Wr,parse:Qr,createTransformer:ei,getAnimatableNone:ri};function ai(e,t,n){return n<0&&(n+=1),n>1&&--n,n<1/6?e+(t-e)*6*n:n<1/2?t:n<2/3?e+(t-e)*(2/3-n)*6:e}function oi({hue:e,saturation:t,lightness:n,alpha:r}){e/=360,t/=100,n/=100;let i=0,a=0,o=0;if(!t)i=a=o=n;else{let r=n<.5?n*(1+t):n+t-n*t,s=2*n-r;i=ai(s,r,e+1/3),a=ai(s,r,e),o=ai(s,r,e-1/3)}return{red:Math.round(i*255),green:Math.round(a*255),blue:Math.round(o*255),alpha:r}}function si(e,t){return n=>n>0?t:e}var ci=(e,t,n)=>e+(t-e)*n,li=(e,t,n)=>{let r=e*e,i=n*(t*t-r)+r;return i<0?0:Math.sqrt(i)},ui=[Pr,Mr,Vr],di=e=>ui.find(t=>t.test(e));function fi(e){let t=di(e);if(`${e}`,!t)return!1;let n=t.parse(e);return t===Vr&&(n=oi(n)),n}var pi=(e,t)=>{let n=fi(e),r=fi(t);if(!n||!r)return si(e,t);let i={...n};return e=>(i.red=li(n.red,r.red,e),i.green=li(n.green,r.green,e),i.blue=li(n.blue,r.blue,e),i.alpha=ci(n.alpha,r.alpha,e),Mr.transform(i))},mi=new Set([`none`,`hidden`]);function hi(e,t){return mi.has(e)?n=>n<=0?e:t:n=>n>=1?t:e}function gi(e,t){return n=>ci(e,t,n)}function _i(e){return typeof e==`number`?gi:typeof e==`string`?vr(e)?si:Hr.test(e)?pi:xi:Array.isArray(e)?vi:typeof e==`object`?Hr.test(e)?pi:yi:si}function vi(e,t){let n=[...e],r=n.length,i=e.map((e,n)=>_i(e)(e,t[n]));return e=>{for(let t=0;t{for(let t in r)n[t]=r[t](e);return n}}function bi(e,t){let n=[],r={color:0,var:0,number:0};for(let i=0;i{let n=ii.createTransformer(t),r=Zr(e),i=Zr(t);return r.indexes.var.length===i.indexes.var.length&&r.indexes.color.length===i.indexes.color.length&&r.indexes.number.length>=i.indexes.number.length?mi.has(e)&&!i.values.length||mi.has(t)&&!r.values.length?hi(e,t):On(vi(bi(r,i),i.values),n):(`${e}${t}`,si(e,t))};function Si(e,t,n){return typeof e==`number`&&typeof t==`number`&&typeof n==`number`?ci(e,t,n):_i(e)(e,t)}var Ci=e=>{let t=({timestamp:t})=>e(t);return{start:(e=!0)=>sr.update(t,e),stop:()=>cr(t),now:()=>lr.isProcessing?lr.timestamp:pr.now()}},wi=(e,t,n=10)=>{let r=``,i=Math.max(Math.round(t/n),2);for(let t=0;t=2e4?1/0:t}function Di(e,t=100,n){let r=n({...e,keyframes:[0,t]}),i=Math.min(Ei(r),Ti);return{type:`keyframes`,ease:e=>r.next(i*e).value/t,duration:Mn(i)}}var Oi={stiffness:100,damping:10,mass:1,velocity:0,duration:800,bounce:.3,visualDuration:.3,restSpeed:{granular:.01,default:2},restDelta:{granular:.005,default:.5},minDuration:.01,maxDuration:10,minDamping:.05,maxDamping:1};function ki(e,t){return e*Math.sqrt(1-t*t)}var Ai=12;function ji(e,t,n){let r=n;for(let n=1;n{let r=t*o,i=r*e,a=r-n,s=ki(t,o),c=Math.exp(-i);return Mi-a/s*c},a=t=>{let r=t*o*e,a=r*n+n,s=o**2*t**2*e,c=Math.exp(-r),l=ki(t**2,o);return(-i(t)+Mi>0?-1:1)*((a-s)*c)/l}):(i=t=>{let r=Math.exp(-t*e),i=(t-n)*e+1;return-Mi+r*i},a=t=>Math.exp(-t*e)*((n-t)*(e*e)));let s=5/e,c=ji(i,a,s);if(e=jn(e),isNaN(c))return{stiffness:Oi.stiffness,damping:Oi.damping,duration:e};{let t=c**2*r;return{stiffness:t,damping:o*2*Math.sqrt(r*t),duration:e}}}var Pi=[`duration`,`bounce`],Fi=[`stiffness`,`damping`,`mass`];function Ii(e,t){return t.some(t=>e[t]!==void 0)}function Li(e){let t={velocity:Oi.velocity,stiffness:Oi.stiffness,damping:Oi.damping,mass:Oi.mass,isResolvedFromDuration:!1,...e};if(!Ii(e,Fi)&&Ii(e,Pi))if(t.velocity=0,e.visualDuration){let n=e.visualDuration,r=2*Math.PI/(n*1.2),i=r*r,a=2*bn(.05,1,1-(e.bounce||0))*Math.sqrt(i);t={...t,mass:Oi.mass,stiffness:i,damping:a}}else{let n=Ni({...e,velocity:0});t={...t,...n,mass:Oi.mass},t.isResolvedFromDuration=!0}return t}function Ri(e=Oi.visualDuration,t=Oi.bounce){let n=typeof e==`object`?e:{visualDuration:e,keyframes:[0,1],bounce:t},{restSpeed:r,restDelta:i}=n,a=n.keyframes[0],o=n.keyframes[n.keyframes.length-1],s={done:!1,value:a},{stiffness:c,damping:l,mass:u,duration:d,velocity:f,isResolvedFromDuration:p}=Li({...n,velocity:-Mn(n.velocity||0)}),m=f||0,h=l/(2*Math.sqrt(c*u)),g=o-a,_=Mn(Math.sqrt(c/u)),v=Math.abs(g)<5;r||=v?Oi.restSpeed.granular:Oi.restSpeed.default,i||=v?Oi.restDelta.granular:Oi.restDelta.default;let y,b,x,S,C,w;if(h<1)x=ki(_,h),S=(m+h*_*g)/x,y=e=>o-Math.exp(-h*_*e)*(S*Math.sin(x*e)+g*Math.cos(x*e)),C=h*_*S+g*x,w=h*_*g-S*x,b=e=>Math.exp(-h*_*e)*(C*Math.sin(x*e)+w*Math.cos(x*e));else if(h===1){y=e=>o-Math.exp(-_*e)*(g+(m+_*g)*e);let e=m+_*g;b=t=>Math.exp(-_*t)*(_*e*t-m)}else{let e=_*Math.sqrt(h*h-1);y=t=>{let n=Math.exp(-h*_*t),r=Math.min(e*t,300);return o-n*((m+h*_*g)*Math.sinh(r)+e*g*Math.cosh(r))/e};let t=(m+h*_*g)/e,n=h*_*t-g*e,r=h*_*g-t*e;b=t=>{let i=Math.exp(-h*_*t),a=Math.min(e*t,300);return i*(n*Math.sinh(a)+r*Math.cosh(a))}}let T={calculatedDuration:p&&d||null,velocity:e=>jn(b(e)),next:e=>{if(!p&&h<1){let t=Math.exp(-h*_*e),n=Math.sin(x*e),a=Math.cos(x*e),c=o-t*(S*n+g*a),l=jn(t*(C*n+w*a));return s.done=Math.abs(l)<=r&&Math.abs(o-c)<=i,s.value=s.done?o:c,s}let t=y(e);if(p)s.done=e>=d;else{let n=jn(b(e));s.done=Math.abs(n)<=r&&Math.abs(o-t)<=i}return s.value=s.done?o:t,s},toString:()=>{let e=Math.min(Ei(T),Ti),t=wi(t=>T.next(e*t).value,e,30);return e+`ms `+t},toTransition:()=>{}};return T}Ri.applyToOptions=e=>{let t=Di(e,100,Ri);return e.ease=t.ease,e.duration=jn(t.duration),e.type=`keyframes`,e};var zi=5;function Bi(e,t,n){let r=Math.max(t-zi,0);return Nn(n-e(r),t-r)}function Vi({keyframes:e,velocity:t=0,power:n=.8,timeConstant:r=325,bounceDamping:i=10,bounceStiffness:a=500,modifyTarget:o,min:s,max:c,restDelta:l=.5,restSpeed:u}){let d=e[0],f={done:!1,value:d},p=e=>s!==void 0&&ec,m=e=>s===void 0?c:c===void 0||Math.abs(s-e)-h*Math.exp(-e/r),y=e=>_+v(e),b=e=>{let t=v(e),n=y(e);f.done=Math.abs(t)<=l,f.value=f.done?_:n},x,S,C=e=>{p(f.value)&&(x=e,S=Ri({keyframes:[f.value,m(f.value)],velocity:Bi(y,e,f.value),damping:i,stiffness:a,restDelta:l,restSpeed:u}))};return C(0),{calculatedDuration:null,next:e=>{let t=!1;return!S&&x===void 0&&(t=!0,b(e),C(e)),x!==void 0&&e>=x?S.next(e-x):(!t&&b(e),f)}}}function Hi(e,t,n){let r=[],i=n||xn.mix||Si,a=e.length-1;for(let n=0;nt[0];if(a===2&&t[0]===t[1])return()=>t[1];let o=e[0]===e[1];e[0]>e[a-1]&&(e=[...e].reverse(),t=[...t].reverse());let s=Hi(t,r,i),c=s.length,l=n=>{if(o&&n1)for(;rl(bn(e[0],e[a-1],t)):l}function Wi(e,t){let n=e[e.length-1];for(let r=1;r<=t;r++){let i=kn(0,t,r);e.push(ci(n,1,i))}}function Gi(e){let t=[0];return Wi(t,e.length-1),t}function Ki(e,t){return e.map(e=>e*t)}function qi(e,t){return e.map(()=>t||Xn).splice(0,e.length-1)}function Ji({duration:e=300,keyframes:t,times:n,ease:r=`easeInOut`}){let i=Zn(r)?r.map(tr):tr(r),a={done:!1,value:t[0]},o=Ui(Ki(n&&n.length===t.length?n:Gi(t),e),t,{ease:Array.isArray(i)?i:qi(t,i)});return{calculatedDuration:e,next:t=>(a.value=o(t),a.done=t>=e,a)}}var Yi=e=>e!==null;function Xi(e,{repeat:t,repeatType:n=`loop`},r,i=1){let a=e.filter(Yi),o=i<0||t&&n!==`loop`&&t%2==1?0:a.length-1;return!o||r===void 0?a[o]:r}var Zi={decay:Vi,inertia:Vi,tween:Ji,keyframes:Ji,spring:Ri};function Qi(e){typeof e.type==`string`&&(e.type=Zi[e.type])}var $i=class{constructor(){this.updateFinished()}get finished(){return this._finished}updateFinished(){this._finished=new Promise(e=>{this.resolve=e})}notifyFinished(){this.resolve()}then(e,t){return this.finished.then(e,t)}},ea=e=>e/100,ta=class extends $i{constructor(e){super(),this.state=`idle`,this.startTime=null,this.isStopped=!1,this.currentTime=0,this.holdTime=null,this.playbackSpeed=1,this.delayState={done:!1,value:void 0},this.stop=()=>{let{motionValue:e}=this.options;e&&e.updatedAt!==pr.now()&&this.tick(pr.now()),this.isStopped=!0,this.state!==`idle`&&(this.teardown(),this.options.onStop?.())},mr.mainThread++,this.options=e,this.initAnimation(),this.play(),e.autoplay===!1&&this.pause()}initAnimation(){let{options:e}=this;Qi(e);let{type:t=Ji,repeat:n=0,repeatDelay:r=0,repeatType:i,velocity:a=0}=e,{keyframes:o}=e,s=t||Ji;s!==Ji&&typeof o[0]!=`number`&&(this.mixKeyframes=On(ea,Si(o[0],o[1])),o=[0,100]);let c=s({...e,keyframes:o});i===`mirror`&&(this.mirroredGenerator=s({...e,keyframes:[...o].reverse(),velocity:-a})),c.calculatedDuration===null&&(c.calculatedDuration=Ei(c));let{calculatedDuration:l}=c;this.calculatedDuration=l,this.resolvedDuration=l+r,this.totalDuration=this.resolvedDuration*(n+1)-r,this.generator=c}updateTime(e){let t=Math.round(e-this.startTime)*this.playbackSpeed;this.holdTime===null?this.currentTime=t:this.currentTime=this.holdTime}tick(e,t=!1){let{generator:n,totalDuration:r,mixKeyframes:i,mirroredGenerator:a,resolvedDuration:o,calculatedDuration:s}=this;if(this.startTime===null)return n.next(0);let{delay:c=0,keyframes:l,repeat:u,repeatType:d,repeatDelay:f,type:p,onUpdate:m,finalKeyframe:h}=this.options;this.speed>0?this.startTime=Math.min(this.startTime,e):this.speed<0&&(this.startTime=Math.min(e-r/this.speed,this.startTime)),t?this.currentTime=e:this.updateTime(e);let g=this.currentTime-c*(this.playbackSpeed>=0?1:-1),_=this.playbackSpeed>=0?g<0:g>r;this.currentTime=Math.max(g,0),this.state===`finished`&&this.holdTime===null&&(this.currentTime=r);let v=this.currentTime,y=n;if(u){let e=Math.min(this.currentTime,r)/o,t=Math.floor(e),n=e%1;!n&&e>=1&&(n=1),n===1&&t--,t=Math.min(t,u+1),t%2&&(d===`reverse`?(n=1-n,f&&(n-=f/o)):d===`mirror`&&(y=a)),v=bn(0,1,n)*o}let b;_?(this.delayState.value=l[0],b=this.delayState):b=y.next(v),i&&!_&&(b.value=i(b.value));let{done:x}=b;!_&&s!==null&&(x=this.playbackSpeed>=0?this.currentTime>=r:this.currentTime<=0);let S=this.holdTime===null&&(this.state===`finished`||this.state===`running`&&x);return S&&p!==Vi&&(b.value=Xi(l,this.options,h,this.speed)),m&&m(b.value),S&&this.finish(),b}then(e,t){return this.finished.then(e,t)}get duration(){return Mn(this.calculatedDuration)}get iterationDuration(){let{delay:e=0}=this.options||{};return this.duration+Mn(e)}get time(){return Mn(this.currentTime)}set time(e){e=jn(e),this.currentTime=e,this.startTime===null||this.holdTime!==null||this.playbackSpeed===0?this.holdTime=e:this.driver&&(this.startTime=this.driver.now()-e/this.playbackSpeed),this.driver?this.driver.start(!1):(this.startTime=0,this.state=`paused`,this.holdTime=e,this.tick(e))}getGeneratorVelocity(){let e=this.currentTime;if(e<=0)return this.options.velocity||0;if(this.generator.velocity)return this.generator.velocity(e);let t=this.generator.next(e).value;return Bi(e=>this.generator.next(e).value,e,t)}get speed(){return this.playbackSpeed}set speed(e){let t=this.playbackSpeed!==e;t&&this.driver&&this.updateTime(pr.now()),this.playbackSpeed=e,t&&this.driver&&(this.time=Mn(this.currentTime))}play(){if(this.isStopped)return;let{driver:e=Ci,startTime:t}=this.options;this.driver||=e(e=>this.tick(e)),this.options.onPlay?.();let n=this.driver.now();this.state===`finished`?(this.updateFinished(),this.startTime=n):this.holdTime===null?this.startTime||=t??n:this.startTime=n-this.holdTime,this.state===`finished`&&this.speed<0&&(this.startTime+=this.calculatedDuration),this.holdTime=null,this.state=`running`,this.driver.start()}pause(){this.state=`paused`,this.updateTime(pr.now()),this.holdTime=this.currentTime}complete(){this.state!==`running`&&this.play(),this.state=`finished`,this.holdTime=null}finish(){this.notifyFinished(),this.teardown(),this.state=`finished`,this.options.onComplete?.()}cancel(){this.holdTime=null,this.startTime=0,this.tick(0),this.teardown(),this.options.onCancel?.()}teardown(){this.state=`idle`,this.stopDriver(),this.startTime=this.holdTime=null,mr.mainThread--}stopDriver(){this.driver&&=(this.driver.stop(),void 0)}sample(e){return this.startTime=0,this.tick(e,!0)}attachTimeline(e){return this.options.allowFlatten&&(this.options.type=`keyframes`,this.options.ease=`linear`,this.initAnimation()),this.driver?.stop(),e.observe(this)}};function na(e){for(let t=1;te*180/Math.PI,ia=e=>oa(ra(Math.atan2(e[1],e[0]))),aa={x:4,y:5,translateX:4,translateY:5,scaleX:0,scaleY:3,scale:e=>(Math.abs(e[0])+Math.abs(e[3]))/2,rotate:ia,rotateZ:ia,skewX:e=>ra(Math.atan(e[1])),skewY:e=>ra(Math.atan(e[2])),skew:e=>(Math.abs(e[1])+Math.abs(e[2]))/2},oa=e=>(e%=360,e<0&&(e+=360),e),sa=ia,ca=e=>Math.sqrt(e[0]*e[0]+e[1]*e[1]),la=e=>Math.sqrt(e[4]*e[4]+e[5]*e[5]),ua={x:12,y:13,z:14,translateX:12,translateY:13,translateZ:14,scaleX:ca,scaleY:la,scale:e=>(ca(e)+la(e))/2,rotateX:e=>oa(ra(Math.atan2(e[6],e[5]))),rotateY:e=>oa(ra(Math.atan2(-e[2],e[0]))),rotateZ:sa,rotate:sa,skewX:e=>ra(Math.atan(e[4])),skewY:e=>ra(Math.atan(e[1])),skew:e=>(Math.abs(e[1])+Math.abs(e[4]))/2};function da(e){return+!!e.includes(`scale`)}function fa(e,t){if(!e||e===`none`)return da(t);let n=e.match(/^matrix3d\(([-\d.e\s,]+)\)$/u),r,i;if(n)r=ua,i=n;else{let t=e.match(/^matrix\(([-\d.e\s,]+)\)$/u);r=aa,i=t}if(!i)return da(t);let a=r[t],o=i[1].split(`,`).map(ma);return typeof a==`function`?a(o):o[a]}var pa=(e,t)=>{let{transform:n=`none`}=getComputedStyle(e);return fa(n,t)};function ma(e){return parseFloat(e.trim())}var ha=[`transformPerspective`,`x`,`y`,`z`,`translateX`,`translateY`,`translateZ`,`scale`,`scaleX`,`scaleY`,`rotate`,`rotateX`,`rotateY`,`rotateZ`,`skew`,`skewX`,`skewY`],ga=new Set(ha),_a=e=>e===xr||e===z,va=new Set([`x`,`y`,`z`]),ya=ha.filter(e=>!va.has(e));function ba(e){let t=[];return ya.forEach(n=>{let r=e.getValue(n);r!==void 0&&(t.push([n,r.get()]),r.set(+!!n.startsWith(`scale`)))}),t}var xa={width:({x:e},{paddingLeft:t=`0`,paddingRight:n=`0`,boxSizing:r})=>{let i=e.max-e.min;return r===`border-box`?i:i-parseFloat(t)-parseFloat(n)},height:({y:e},{paddingTop:t=`0`,paddingBottom:n=`0`,boxSizing:r})=>{let i=e.max-e.min;return r===`border-box`?i:i-parseFloat(t)-parseFloat(n)},top:(e,{top:t})=>parseFloat(t),left:(e,{left:t})=>parseFloat(t),bottom:({y:e},{top:t})=>parseFloat(t)+(e.max-e.min),right:({x:e},{left:t})=>parseFloat(t)+(e.max-e.min),x:(e,{transform:t})=>fa(t,`x`),y:(e,{transform:t})=>fa(t,`y`)};xa.translateX=xa.x,xa.translateY=xa.y;var Sa=new Set,Ca=!1,wa=!1,Ta=!1;function Ea(){if(wa){let e=Array.from(Sa).filter(e=>e.needsMeasurement),t=new Set(e.map(e=>e.element)),n=new Map;t.forEach(e=>{let t=ba(e);t.length&&(n.set(e,t),e.render())}),e.forEach(e=>e.measureInitialState()),t.forEach(e=>{e.render();let t=n.get(e);t&&t.forEach(([t,n])=>{e.getValue(t)?.set(n)})}),e.forEach(e=>e.measureEndState()),e.forEach(e=>{e.suspendedScrollY!==void 0&&window.scrollTo(0,e.suspendedScrollY)})}wa=!1,Ca=!1,Sa.forEach(e=>e.complete(Ta)),Sa.clear()}function Da(){Sa.forEach(e=>{e.readKeyframes(),e.needsMeasurement&&(wa=!0)})}function Oa(){Ta=!0,Da(),Ea(),Ta=!1}var ka=class{constructor(e,t,n,r,i,a=!1){this.state=`pending`,this.isAsync=!1,this.needsMeasurement=!1,this.unresolvedKeyframes=[...e],this.onComplete=t,this.name=n,this.motionValue=r,this.element=i,this.isAsync=a}scheduleResolve(){this.state=`scheduled`,this.isAsync?(Sa.add(this),Ca||(Ca=!0,sr.read(Da),sr.resolveKeyframes(Ea))):(this.readKeyframes(),this.complete())}readKeyframes(){let{unresolvedKeyframes:e,name:t,element:n,motionValue:r}=this;if(e[0]===null){let i=r?.get(),a=e[e.length-1];if(i!==void 0)e[0]=i;else if(n&&t){let r=n.readValue(t,a);r!=null&&(e[0]=r)}e[0]===void 0&&(e[0]=a),r&&i===void 0&&r.set(e[0])}na(e)}setFinalKeyframe(){}measureInitialState(){}renderEndStyles(){}measureEndState(){}complete(e=!1){this.state=`complete`,this.onComplete(this.unresolvedKeyframes,this.finalKeyframe,e),Sa.delete(this)}cancel(){this.state===`scheduled`&&(Sa.delete(this),this.state=`pending`)}resume(){this.state===`pending`&&this.scheduleResolve()}},Aa=e=>e.startsWith(`--`);function ja(e,t,n){Aa(t)?e.style.setProperty(t,n):e.style[t]=n}var Ma={};function Na(e,t){let n=Tn(e);return()=>Ma[t]??n()}var Pa=Na(()=>window.ScrollTimeline!==void 0,`scrollTimeline`),Fa=Na(()=>{try{document.createElement(`div`).animate({opacity:0},{easing:`linear(0, 1)`})}catch{return!1}return!0},`linearEasing`),Ia=([e,t,n,r])=>`cubic-bezier(${e}, ${t}, ${n}, ${r})`,La={linear:`linear`,ease:`ease`,easeIn:`ease-in`,easeOut:`ease-out`,easeInOut:`ease-in-out`,circIn:Ia([0,.65,.55,1]),circOut:Ia([.55,0,1,.45]),backIn:Ia([.31,.01,.66,-.59]),backOut:Ia([.33,1.53,.69,.99])};function Ra(e,t){if(e)return typeof e==`function`?Fa()?wi(e,t):`ease-out`:Qn(e)?Ia(e):Array.isArray(e)?e.map(e=>Ra(e,t)||La.easeOut):La[e]}function za(e,t,n,{delay:r=0,duration:i=300,repeat:a=0,repeatType:o=`loop`,ease:s=`easeOut`,times:c}={},l=void 0){let u={[t]:n};c&&(u.offset=c);let d=Ra(s,i);Array.isArray(d)&&(u.easing=d),rr.value&&mr.waapi++;let f={delay:r,duration:i,easing:Array.isArray(d)?`linear`:d,fill:`both`,iterations:a+1,direction:o===`reverse`?`alternate`:`normal`};l&&(f.pseudoElement=l);let p=e.animate(u,f);return rr.value&&p.finished.finally(()=>{mr.waapi--}),p}function Ba(e){return typeof e==`function`&&`applyToOptions`in e}function Va({type:e,...t}){return Ba(e)&&Fa()?e.applyToOptions(t):(t.duration??=300,t.ease??=`easeOut`,t)}var Ha=class extends $i{constructor(e){if(super(),this.finishedTime=null,this.isStopped=!1,this.manualStartTime=null,!e)return;let{element:t,name:n,keyframes:r,pseudoElement:i,allowFlatten:a=!1,finalKeyframe:o,onComplete:s}=e;this.isPseudoElement=!!i,this.allowFlatten=a,this.options=e,e.type;let c=Va(e);this.animation=za(t,n,r,c,i),c.autoplay===!1&&this.animation.pause(),this.animation.onfinish=()=>{if(this.finishedTime=this.time,!i){let e=Xi(r,this.options,o,this.speed);this.updateMotionValue&&this.updateMotionValue(e),ja(t,n,e),this.animation.cancel()}s?.(),this.notifyFinished()}}play(){this.isStopped||(this.manualStartTime=null,this.animation.play(),this.state===`finished`&&this.updateFinished())}pause(){this.animation.pause()}complete(){this.animation.finish?.()}cancel(){try{this.animation.cancel()}catch{}}stop(){if(this.isStopped)return;this.isStopped=!0;let{state:e}=this;e===`idle`||e===`finished`||(this.updateMotionValue?this.updateMotionValue():this.commitStyles(),this.isPseudoElement||this.cancel())}commitStyles(){let e=this.options?.element;!this.isPseudoElement&&e?.isConnected&&this.animation.commitStyles?.()}get duration(){let e=this.animation.effect?.getComputedTiming?.().duration||0;return Mn(Number(e))}get iterationDuration(){let{delay:e=0}=this.options||{};return this.duration+Mn(e)}get time(){return Mn(Number(this.animation.currentTime)||0)}set time(e){let t=this.finishedTime!==null;this.manualStartTime=null,this.finishedTime=null,this.animation.currentTime=jn(e),t&&this.animation.pause()}get speed(){return this.animation.playbackRate}set speed(e){e<0&&(this.finishedTime=null),this.animation.playbackRate=e}get state(){return this.finishedTime===null?this.animation.playState:`finished`}get startTime(){return this.manualStartTime??Number(this.animation.startTime)}set startTime(e){this.manualStartTime=this.animation.startTime=e}attachTimeline({timeline:e,rangeStart:t,rangeEnd:n,observe:r}){return this.allowFlatten&&this.animation.effect?.updateTiming({easing:`linear`}),this.animation.onfinish=null,e&&Pa()?(this.animation.timeline=e,t&&(this.animation.rangeStart=t),n&&(this.animation.rangeEnd=n),En):r(this)}},Ua={anticipate:Wn,backInOut:Un,circInOut:qn};function Wa(e){return e in Ua}function Ga(e){typeof e.ease==`string`&&Wa(e.ease)&&(e.ease=Ua[e.ease])}var Ka=10,qa=class extends Ha{constructor(e){Ga(e),Qi(e),super(e),e.startTime!==void 0&&e.autoplay!==!1&&(this.startTime=e.startTime),this.options=e}updateMotionValue(e){let{motionValue:t,onUpdate:n,onComplete:r,element:i,...a}=this.options;if(!t)return;if(e!==void 0){t.set(e);return}let o=new ta({...a,autoplay:!1}),s=Math.max(Ka,pr.now()-this.startTime),c=bn(0,Ka,s-Ka),l=o.sample(s).value,{name:u}=this.options;i&&u&&ja(i,u,l),t.setWithVelocity(o.sample(Math.max(0,s-c)).value,l,c),o.stop()}},Ja=(e,t)=>t===`zIndex`?!1:!!(typeof e==`number`||Array.isArray(e)||typeof e==`string`&&(ii.test(e)||e===`0`)&&!e.startsWith(`url(`));function Ya(e){let t=e[0];if(e.length===1)return!0;for(let n=0;nObject.hasOwnProperty.call(Element.prototype,`animate`));function ro(e){let{motionValue:t,name:n,repeatDelay:r,repeatType:i,damping:a,type:o,keyframes:s}=e;if(!(t?.owner?.current instanceof HTMLElement))return!1;let{onUpdate:c,transformTemplate:l}=t.owner.getProps();return no()&&n&&(Qa.has(n)||to.has(n)&&eo(s))&&(n!==`transform`||!l)&&!c&&!r&&i!==`mirror`&&a!==0&&o!==`inertia`}var io=40,ao=class extends $i{constructor({autoplay:e=!0,delay:t=0,type:n=`keyframes`,repeat:r=0,repeatDelay:i=0,repeatType:a=`loop`,keyframes:o,name:s,motionValue:c,element:l,...u}){super(),this.stop=()=>{this._animation&&(this._animation.stop(),this.stopTimeline?.()),this.keyframeResolver?.cancel()},this.createdAt=pr.now();let d={autoplay:e,delay:t,type:n,repeat:r,repeatDelay:i,repeatType:a,name:s,motionValue:c,element:l,...u},f=l?.KeyframeResolver||ka;this.keyframeResolver=new f(o,(e,t,n)=>this.onKeyframesResolved(e,t,d,!n),s,c,l),this.keyframeResolver?.scheduleResolve()}onKeyframesResolved(e,t,n,r){this.keyframeResolver=void 0;let{name:i,type:a,velocity:o,delay:s,isHandoff:c,onUpdate:l}=n;this.resolvedAt=pr.now();let u=!0;Xa(e,i,a,o)||(u=!1,(xn.instantAnimations||!s)&&l?.(Xi(e,n,t)),e[0]=e[e.length-1],Za(n),n.repeat=0);let d={startTime:r?this.resolvedAt&&this.resolvedAt-this.createdAt>io?this.resolvedAt:this.createdAt:void 0,finalKeyframe:t,...n,keyframes:e},f=u&&!c&&ro(d),p=d.motionValue?.owner?.current,m;if(f)try{m=new qa({...d,element:p})}catch{m=new ta(d)}else m=new ta(d);m.finished.then(()=>{this.notifyFinished()}).catch(En),this.pendingTimeline&&=(this.stopTimeline=m.attachTimeline(this.pendingTimeline),void 0),this._animation=m}get finished(){return this._animation?this.animation.finished:this._finished}then(e,t){return this.finished.finally(e).then(()=>{})}get animation(){return this._animation||(this.keyframeResolver?.resume(),Oa()),this._animation}get duration(){return this.animation.duration}get iterationDuration(){return this.animation.iterationDuration}get time(){return this.animation.time}set time(e){this.animation.time=e}get speed(){return this.animation.speed}get state(){return this.animation.state}set speed(e){this.animation.speed=e}get startTime(){return this.animation.startTime}attachTimeline(e){return this._animation?this.stopTimeline=this.animation.attachTimeline(e):this.pendingTimeline=e,()=>this.stop()}play(){this.animation.play()}pause(){this.animation.pause()}complete(){this.animation.complete()}cancel(){this._animation&&this.animation.cancel(),this.keyframeResolver?.cancel()}};function oo(e,t,n,r=0,i=1){let a=Array.from(e).sort((e,t)=>e.sortNodePosition(t)).indexOf(t),o=e.size,s=(o-1)*r;return typeof n==`function`?n(a,o):i===1?a*r:s-a*r}var so=/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;function co(e){let t=so.exec(e);if(!t)return[,];let[,n,r,i]=t;return[`--${n??r}`,i]}function lo(e,t,n=1){`${e}`;let[r,i]=co(e);if(!r)return;let a=window.getComputedStyle(t).getPropertyValue(r);if(a){let e=a.trim();return Sn(e)?parseFloat(e):e}return vr(i)?lo(i,t,n+1):i}var uo={type:`spring`,stiffness:500,damping:25,restSpeed:10},fo=e=>({type:`spring`,stiffness:550,damping:e===0?2*Math.sqrt(550):30,restSpeed:10}),po={type:`keyframes`,duration:.8},B={type:`keyframes`,ease:[.25,.1,.35,1],duration:.3},mo=(e,{keyframes:t})=>t.length>2?po:ga.has(e)?e.startsWith(`scale`)?fo(t[1]):uo:B;function ho(e,t){if(e?.inherit&&t){let{inherit:n,...r}=e;return{...t,...r}}return e}function go(e,t){let n=e?.[t]??e?.default??e;return n===e?n:ho(n,e)}var _o=new Set([`when`,`delay`,`delayChildren`,`staggerChildren`,`staggerDirection`,`repeat`,`repeatType`,`repeatDelay`,`from`,`elapsed`]);function vo(e){for(let t in e)if(!_o.has(t))return!0;return!1}var yo=(e,t,n,r={},i,a)=>o=>{let s=go(r,e)||{},c=s.delay||r.delay||0,{elapsed:l=0}=r;l-=jn(c);let u={keyframes:Array.isArray(n)?n:[null,n],ease:`easeOut`,velocity:t.getVelocity(),...s,delay:-l,onUpdate:e=>{t.set(e),s.onUpdate&&s.onUpdate(e)},onComplete:()=>{o(),s.onComplete&&s.onComplete()},name:e,motionValue:t,element:a?void 0:i};vo(s)||Object.assign(u,mo(e,u)),u.duration&&=jn(u.duration),u.repeatDelay&&=jn(u.repeatDelay),u.from!==void 0&&(u.keyframes[0]=u.from);let d=!1;if((u.type===!1||u.duration===0&&!u.repeatDelay)&&(Za(u),u.delay===0&&(d=!0)),(xn.instantAnimations||xn.skipAnimations||i?.shouldSkipAnimations)&&(d=!0,Za(u),u.delay=0),u.allowFlatten=!s.type&&!s.ease,d&&!a&&t.get()!==void 0){let e=Xi(u.keyframes,s);if(e!==void 0){sr.update(()=>{u.onUpdate(e),u.onComplete()});return}}return s.isSync?new ta(u):new ao(u)};function bo(e){let t=[{},{}];return e?.values.forEach((e,n)=>{t[0][n]=e.get(),t[1][n]=e.getVelocity()}),t}function xo(e,t,n,r){if(typeof t==`function`){let[i,a]=bo(r);t=t(n===void 0?e.custom:n,i,a)}if(typeof t==`string`&&(t=e.variants&&e.variants[t]),typeof t==`function`){let[i,a]=bo(r);t=t(n===void 0?e.custom:n,i,a)}return t}function So(e,t,n){let r=e.getProps();return xo(r,t,n===void 0?r.custom:n,e)}var Co=new Set([`width`,`height`,`top`,`left`,`right`,`bottom`,...ha]),wo=30,To=e=>!isNaN(parseFloat(e)),Eo={current:void 0},Do=class{constructor(e,t={}){this.canTrackVelocity=null,this.events={},this.updateAndNotify=e=>{let t=pr.now();if(this.updatedAt!==t&&this.setPrevFrameValue(),this.prev=this.current,this.setCurrent(e),this.current!==this.prev&&(this.events.change?.notify(this.current),this.dependents))for(let e of this.dependents)e.dirty()},this.hasAnimated=!1,this.setCurrent(e),this.owner=t.owner}setCurrent(e){this.current=e,this.updatedAt=pr.now(),this.canTrackVelocity===null&&e!==void 0&&(this.canTrackVelocity=To(this.current))}setPrevFrameValue(e=this.current){this.prevFrameValue=e,this.prevUpdatedAt=this.updatedAt}onChange(e){return this.on(`change`,e)}on(e,t){this.events[e]||(this.events[e]=new An);let n=this.events[e].add(t);return e===`change`?()=>{n(),sr.read(()=>{this.events.change.getSize()||this.stop()})}:n}clearListeners(){for(let e in this.events)this.events[e].clear()}attach(e,t){this.passiveEffect=e,this.stopPassiveEffect=t}set(e){this.passiveEffect?this.passiveEffect(e,this.updateAndNotify):this.updateAndNotify(e)}setWithVelocity(e,t,n){this.set(t),this.prev=void 0,this.prevFrameValue=e,this.prevUpdatedAt=this.updatedAt-n}jump(e,t=!0){this.updateAndNotify(e),this.prev=e,this.prevUpdatedAt=this.prevFrameValue=void 0,t&&this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}dirty(){this.events.change?.notify(this.current)}addDependent(e){this.dependents||=new Set,this.dependents.add(e)}removeDependent(e){this.dependents&&this.dependents.delete(e)}get(){return Eo.current&&Eo.current.push(this),this.current}getPrevious(){return this.prev}getVelocity(){let e=pr.now();if(!this.canTrackVelocity||this.prevFrameValue===void 0||e-this.updatedAt>wo)return 0;let t=Math.min(this.updatedAt-this.prevUpdatedAt,wo);return Nn(parseFloat(this.current)-parseFloat(this.prevFrameValue),t)}start(e){return this.stop(),new Promise(t=>{this.hasAnimated=!0,this.animation=e(t),this.events.animationStart&&this.events.animationStart.notify()}).then(()=>{this.events.animationComplete&&this.events.animationComplete.notify(),this.clearAnimation()})}stop(){this.animation&&(this.animation.stop(),this.events.animationCancel&&this.events.animationCancel.notify()),this.clearAnimation()}isAnimating(){return!!this.animation}clearAnimation(){delete this.animation}destroy(){this.dependents?.clear(),this.events.destroy?.notify(),this.clearListeners(),this.stop(),this.stopPassiveEffect&&this.stopPassiveEffect()}};function Oo(e,t){return new Do(e,t)}var ko=e=>Array.isArray(e);function Ao(e,t,n){e.hasValue(t)?e.getValue(t).set(n):e.addValue(t,Oo(n))}function jo(e){return ko(e)?e[e.length-1]||0:e}function Mo(e,t){let{transitionEnd:n={},transition:r={},...i}=So(e,t)||{};i={...i,...n};for(let t in i)Ao(e,t,jo(i[t]))}var V=e=>!!(e&&e.getVelocity);function No(e){return!!(V(e)&&e.add)}function Po(e,t){let n=e.getValue(`willChange`);if(No(n))return n.add(t);if(!n&&xn.WillChange){let n=new xn.WillChange(`auto`);e.addValue(`willChange`,n),n.add(t)}}function Fo(e){return e.replace(/([A-Z])/g,e=>`-${e.toLowerCase()}`)}var Io=`data-`+Fo(`framerAppearId`);function Lo(e){return e.props[Io]}function Ro({protectedKeys:e,needsAnimating:t},n){let r=e.hasOwnProperty(n)&&t[n]!==!0;return t[n]=!1,r}function zo(e,t,{delay:n=0,transitionOverride:r,type:i}={}){let{transition:a,transitionEnd:o,...s}=t,c=e.getDefaultTransition();a=a?ho(a,c):c;let l=a?.reduceMotion;r&&(a=r);let u=[],d=i&&e.animationState&&e.animationState.getState()[i];for(let t in s){let r=e.getValue(t,e.latestValues[t]??null),i=s[t];if(i===void 0||d&&Ro(d,t))continue;let o={delay:n,...go(a||{},t)},c=r.get();if(c!==void 0&&!r.isAnimating()&&!Array.isArray(i)&&i===c&&!o.velocity){sr.update(()=>r.set(i));continue}let f=!1;if(window.MotionHandoffAnimation){let n=Lo(e);if(n){let e=window.MotionHandoffAnimation(n,t,sr);e!==null&&(o.startTime=e,f=!0)}}Po(e,t);let p=l??e.shouldReduceMotion;r.start(yo(t,r,i,p&&Co.has(t)?{type:!1}:o,e,f));let m=r.animation;m&&u.push(m)}if(o){let t=()=>sr.update(()=>{o&&Mo(e,o)});u.length?Promise.all(u).then(t):t()}return u}function Bo(e,t,n={}){let r=So(e,t,n.type===`exit`?e.presenceContext?.custom:void 0),{transition:i=e.getDefaultTransition()||{}}=r||{};n.transitionOverride&&(i=n.transitionOverride);let a=r?()=>Promise.all(zo(e,r,n)):()=>Promise.resolve(),o=e.variantChildren&&e.variantChildren.size?(r=0)=>{let{delayChildren:a=0,staggerChildren:o,staggerDirection:s}=i;return Vo(e,t,r,a,o,s,n)}:()=>Promise.resolve(),{when:s}=i;if(s){let[e,t]=s===`beforeChildren`?[a,o]:[o,a];return e().then(()=>t())}else return Promise.all([a(),o(n.delay)])}function Vo(e,t,n=0,r=0,i=0,a=1,o){let s=[];for(let c of e.variantChildren)c.notify(`AnimationStart`,t),s.push(Bo(c,t,{...o,delay:n+(typeof r==`function`?0:r)+oo(e.variantChildren,c,r,i,a)}).then(()=>c.notify(`AnimationComplete`,t)));return Promise.all(s)}function Ho(e,t,n={}){e.notify(`AnimationStart`,t);let r;if(Array.isArray(t)){let i=t.map(t=>Bo(e,t,n));r=Promise.all(i)}else if(typeof t==`string`)r=Bo(e,t,n);else{let i=typeof t==`function`?So(e,t,n.custom):t;r=Promise.all(zo(e,i,n))}return r.then(()=>{e.notify(`AnimationComplete`,t)})}var Uo={test:e=>e===`auto`,parse:e=>e},Wo=e=>t=>t.test(e),Go=[xr,z,Lr,Ir,zr,Rr,Uo],Ko=e=>Go.find(Wo(e));function qo(e){return typeof e==`number`?e===0:e===null?!0:e===`none`||e===`0`||wn(e)}var Jo=new Set([`brightness`,`contrast`,`saturate`,`opacity`]);function Yo(e){let[t,n]=e.slice(0,-1).split(`(`);if(t===`drop-shadow`)return e;let[r]=n.match(Tr)||[];if(!r)return e;let i=n.replace(r,``),a=+!!Jo.has(t);return r!==n&&(a*=100),t+`(`+a+i+`)`}var Xo=/\b([a-z-]*)\(.*?\)/gu,Zo={...ii,getAnimatableNone:e=>{let t=e.match(Xo);return t?t.map(Yo).join(` `):e}},Qo={...ii,getAnimatableNone:e=>{let t=ii.parse(e);return ii.createTransformer(e)(t.map(e=>typeof e==`number`?0:typeof e==`object`?{...e,alpha:1}:e))}},$o={...xr,transform:Math.round},es={borderWidth:z,borderTopWidth:z,borderRightWidth:z,borderBottomWidth:z,borderLeftWidth:z,borderRadius:z,borderTopLeftRadius:z,borderTopRightRadius:z,borderBottomRightRadius:z,borderBottomLeftRadius:z,width:z,maxWidth:z,height:z,maxHeight:z,top:z,right:z,bottom:z,left:z,inset:z,insetBlock:z,insetBlockStart:z,insetBlockEnd:z,insetInline:z,insetInlineStart:z,insetInlineEnd:z,padding:z,paddingTop:z,paddingRight:z,paddingBottom:z,paddingLeft:z,paddingBlock:z,paddingBlockStart:z,paddingBlockEnd:z,paddingInline:z,paddingInlineStart:z,paddingInlineEnd:z,margin:z,marginTop:z,marginRight:z,marginBottom:z,marginLeft:z,marginBlock:z,marginBlockStart:z,marginBlockEnd:z,marginInline:z,marginInlineStart:z,marginInlineEnd:z,fontSize:z,backgroundPositionX:z,backgroundPositionY:z,rotate:Ir,rotateX:Ir,rotateY:Ir,rotateZ:Ir,scale:Cr,scaleX:Cr,scaleY:Cr,scaleZ:Cr,skew:Ir,skewX:Ir,skewY:Ir,distance:z,translateX:z,translateY:z,translateZ:z,x:z,y:z,z,perspective:z,transformPerspective:z,opacity:Sr,originX:Br,originY:Br,originZ:z,zIndex:$o,fillOpacity:Sr,strokeOpacity:Sr,numOctaves:$o},ts={...es,color:Hr,backgroundColor:Hr,outlineColor:Hr,fill:Hr,stroke:Hr,borderColor:Hr,borderTopColor:Hr,borderRightColor:Hr,borderBottomColor:Hr,borderLeftColor:Hr,filter:Zo,WebkitFilter:Zo,mask:Qo,WebkitMask:Qo},ns=e=>ts[e],rs=new Set([Zo,Qo]);function is(e,t){let n=ns(e);return rs.has(n)||(n=ii),n.getAnimatableNone?n.getAnimatableNone(t):void 0}var as=new Set([`auto`,`none`,`0`]);function os(e,t,n){let r=0,i;for(;r{e.getValue(t).set(n)}),this.resolveNoneKeyframes()}};function cs(e,t,n){if(e==null)return[];if(e instanceof EventTarget)return[e];if(typeof e==`string`){let r=document;t&&(r=t.current);let i=n?.[e]??r.querySelectorAll(e);return i?Array.from(i):[]}return Array.from(e).filter(e=>e!=null)}var ls=(e,t)=>t&&typeof e==`number`?t.transform(e):e;function us(e){return Cn(e)&&`offsetHeight`in e&&!(`ownerSVGElement`in e)}var{schedule:ds,cancel:fs}=or(queueMicrotask,!1),ps={x:!1,y:!1};function ms(){return ps.x||ps.y}function hs(e){return e===`x`||e===`y`?ps[e]?null:(ps[e]=!0,()=>{ps[e]=!1}):ps.x||ps.y?null:(ps.x=ps.y=!0,()=>{ps.x=ps.y=!1})}function gs(e,t){let n=cs(e),r=new AbortController;return[n,{passive:!0,...t,signal:r.signal},()=>r.abort()]}function _s(e){return!(e.pointerType===`touch`||ms())}function vs(e,t,n={}){let[r,i,a]=gs(e,n);return r.forEach(e=>{let n=!1,r=!1,a,o=()=>{e.removeEventListener(`pointerleave`,u)},s=e=>{a&&=(a(e),void 0),o()},c=e=>{n=!1,window.removeEventListener(`pointerup`,c),window.removeEventListener(`pointercancel`,c),r&&(r=!1,s(e))},l=()=>{n=!0,window.addEventListener(`pointerup`,c,i),window.addEventListener(`pointercancel`,c,i)},u=e=>{if(e.pointerType!==`touch`){if(n){r=!0;return}s(e)}};e.addEventListener(`pointerenter`,n=>{if(!_s(n))return;r=!1;let o=t(e,n);typeof o==`function`&&(a=o,e.addEventListener(`pointerleave`,u,i))},i),e.addEventListener(`pointerdown`,l,i)}),a}var ys=(e,t)=>t?e===t?!0:ys(e,t.parentElement):!1,bs=e=>e.pointerType===`mouse`?typeof e.button!=`number`||e.button<=0:e.isPrimary!==!1,xs=new Set([`BUTTON`,`INPUT`,`SELECT`,`TEXTAREA`,`A`]);function Ss(e){return xs.has(e.tagName)||e.isContentEditable===!0}var Cs=new Set([`INPUT`,`SELECT`,`TEXTAREA`]);function ws(e){return Cs.has(e.tagName)||e.isContentEditable===!0}var Ts=new WeakSet;function Es(e){return t=>{t.key===`Enter`&&e(t)}}function Ds(e,t){e.dispatchEvent(new PointerEvent(`pointer`+t,{isPrimary:!0,bubbles:!0}))}var Os=(e,t)=>{let n=e.currentTarget;if(!n)return;let r=Es(()=>{if(Ts.has(n))return;Ds(n,`down`);let e=Es(()=>{Ds(n,`up`)});n.addEventListener(`keyup`,e,t),n.addEventListener(`blur`,()=>Ds(n,`cancel`),t)});n.addEventListener(`keydown`,r,t),n.addEventListener(`blur`,()=>n.removeEventListener(`keydown`,r),t)};function ks(e){return bs(e)&&!ms()}var As=new WeakSet;function js(e,t,n={}){let[r,i,a]=gs(e,n),o=e=>{let r=e.currentTarget;if(!ks(e)||As.has(e))return;Ts.add(r),n.stopPropagation&&As.add(e);let a=t(r,e),o=(e,t)=>{window.removeEventListener(`pointerup`,s),window.removeEventListener(`pointercancel`,c),Ts.has(r)&&Ts.delete(r),ks(e)&&typeof a==`function`&&a(e,{success:t})},s=e=>{o(e,r===window||r===document||n.useGlobalTarget||ys(r,e.target))},c=e=>{o(e,!1)};window.addEventListener(`pointerup`,s,i),window.addEventListener(`pointercancel`,c,i)};return r.forEach(e=>{(n.useGlobalTarget?window:e).addEventListener(`pointerdown`,o,i),us(e)&&(e.addEventListener(`focus`,e=>Os(e,i)),!Ss(e)&&!e.hasAttribute(`tabindex`)&&(e.tabIndex=0))}),a}function Ms(e){return Cn(e)&&`ownerSVGElement`in e}var Ns=new WeakMap,Ps,Fs=(e,t,n)=>(r,i)=>i&&i[0]?i[0][e+`Size`]:Ms(r)&&`getBBox`in r?r.getBBox()[t]:r[n],Is=Fs(`inline`,`width`,`offsetWidth`),Ls=Fs(`block`,`height`,`offsetHeight`);function Rs({target:e,borderBoxSize:t}){Ns.get(e)?.forEach(n=>{n(e,{get width(){return Is(e,t)},get height(){return Ls(e,t)}})})}function zs(e){e.forEach(Rs)}function Bs(){typeof ResizeObserver>`u`||(Ps=new ResizeObserver(zs))}function Vs(e,t){Ps||Bs();let n=cs(e);return n.forEach(e=>{let n=Ns.get(e);n||(n=new Set,Ns.set(e,n)),n.add(t),Ps?.observe(e)}),()=>{n.forEach(e=>{let n=Ns.get(e);n?.delete(t),n?.size||Ps?.unobserve(e)})}}var Hs=new Set,Us;function Ws(){Us=()=>{let e={get width(){return window.innerWidth},get height(){return window.innerHeight}};Hs.forEach(t=>t(e))},window.addEventListener(`resize`,Us)}function Gs(e){return Hs.add(e),Us||Ws(),()=>{Hs.delete(e),!Hs.size&&typeof Us==`function`&&(window.removeEventListener(`resize`,Us),Us=void 0)}}function Ks(e,t){return typeof e==`function`?Gs(e):Vs(e,t)}function qs(e){return Ms(e)&&e.tagName===`svg`}var Js=[...Go,Hr,ii],Ys=e=>Js.find(Wo(e)),Xs=()=>({translate:0,scale:1,origin:0,originPoint:0}),Zs=()=>({x:Xs(),y:Xs()}),Qs=()=>({min:0,max:0}),$s=()=>({x:Qs(),y:Qs()}),ec=new WeakMap;function tc(e){return typeof e==`object`&&!!e&&typeof e.start==`function`}function nc(e){return typeof e==`string`||Array.isArray(e)}var rc=[`animate`,`whileInView`,`whileFocus`,`whileHover`,`whileTap`,`whileDrag`,`exit`],ic=[`initial`,...rc];function ac(e){return tc(e.animate)||ic.some(t=>nc(e[t]))}function oc(e){return!!(ac(e)||e.variants)}function sc(e,t,n){for(let r in t){let i=t[r],a=n[r];if(V(i))e.addValue(r,i);else if(V(a))e.addValue(r,Oo(i,{owner:e}));else if(a!==i)if(e.hasValue(r)){let t=e.getValue(r);t.liveStyle===!0?t.jump(i):t.hasAnimated||t.set(i)}else{let t=e.getStaticValue(r);e.addValue(r,Oo(t===void 0?i:t,{owner:e}))}}for(let r in n)t[r]===void 0&&e.removeValue(r);return t}var cc={current:null},lc={current:!1},uc=typeof window<`u`;function dc(){if(lc.current=!0,uc)if(window.matchMedia){let e=window.matchMedia(`(prefers-reduced-motion)`),t=()=>cc.current=e.matches;e.addEventListener(`change`,t),t()}else cc.current=!1}var fc=[`AnimationStart`,`AnimationComplete`,`Update`,`BeforeLayoutMeasure`,`LayoutMeasure`,`LayoutAnimationStart`,`LayoutAnimationComplete`],pc={};function mc(e){pc=e}function hc(){return pc}var gc=class{scrapeMotionValuesFromProps(e,t,n){return{}}constructor({parent:e,props:t,presenceContext:n,reducedMotionConfig:r,skipAnimations:i,blockInitialAnimation:a,visualState:o},s={}){this.current=null,this.children=new Set,this.isVariantNode=!1,this.isControllingVariants=!1,this.shouldReduceMotion=null,this.shouldSkipAnimations=!1,this.values=new Map,this.KeyframeResolver=ka,this.features={},this.valueSubscriptions=new Map,this.prevMotionValues={},this.hasBeenMounted=!1,this.events={},this.propEventSubscriptions={},this.notifyUpdate=()=>this.notify(`Update`,this.latestValues),this.render=()=>{this.current&&(this.triggerBuild(),this.renderInstance(this.current,this.renderState,this.props.style,this.projection))},this.renderScheduledAt=0,this.scheduleRender=()=>{let e=pr.now();this.renderScheduledAtthis.bindToMotionValue(t,e)),this.reducedMotionConfig===`never`?this.shouldReduceMotion=!1:this.reducedMotionConfig===`always`?this.shouldReduceMotion=!0:(lc.current||dc(),this.shouldReduceMotion=cc.current),this.shouldSkipAnimations=this.skipAnimationsConfig??!1,this.parent?.addChild(this),this.update(this.props,this.presenceContext),this.hasBeenMounted=!0}unmount(){this.projection&&this.projection.unmount(),cr(this.notifyUpdate),cr(this.render),this.valueSubscriptions.forEach(e=>e()),this.valueSubscriptions.clear(),this.removeFromVariantTree&&this.removeFromVariantTree(),this.parent?.removeChild(this);for(let e in this.events)this.events[e].clear();for(let e in this.features){let t=this.features[e];t&&(t.unmount(),t.isMounted=!1)}this.current=null}addChild(e){this.children.add(e),this.enteringChildren??=new Set,this.enteringChildren.add(e)}removeChild(e){this.children.delete(e),this.enteringChildren&&this.enteringChildren.delete(e)}bindToMotionValue(e,t){if(this.valueSubscriptions.has(e)&&this.valueSubscriptions.get(e)(),t.accelerate&&Qa.has(e)&&this.current instanceof HTMLElement){let{factory:n,keyframes:r,times:i,ease:a,duration:o}=t.accelerate,s=new Ha({element:this.current,name:e,keyframes:r,times:i,ease:a,duration:jn(o)}),c=n(s);this.valueSubscriptions.set(e,()=>{c(),s.cancel()});return}let n=ga.has(e);n&&this.onBindTransform&&this.onBindTransform();let r=t.on(`change`,t=>{this.latestValues[e]=t,this.props.onUpdate&&sr.preRender(this.notifyUpdate),n&&this.projection&&(this.projection.isTransformDirty=!0),this.scheduleRender()}),i;typeof window<`u`&&window.MotionCheckAppearSync&&(i=window.MotionCheckAppearSync(this,e,t)),this.valueSubscriptions.set(e,()=>{r(),i&&i(),t.owner&&t.stop()})}sortNodePosition(e){return!this.current||!this.sortInstanceNodePosition||this.type!==e.type?0:this.sortInstanceNodePosition(this.current,e.current)}updateFeatures(){let e=`animation`;for(e in pc){let t=pc[e];if(!t)continue;let{isEnabled:n,Feature:r}=t;if(!this.features[e]&&r&&n(this.props)&&(this.features[e]=new r(this)),this.features[e]){let t=this.features[e];t.isMounted?t.update():(t.mount(),t.isMounted=!0)}}}triggerBuild(){this.build(this.renderState,this.latestValues,this.props)}measureViewportBox(){return this.current?this.measureInstanceViewportBox(this.current,this.props):$s()}getStaticValue(e){return this.latestValues[e]}setStaticValue(e,t){this.latestValues[e]=t}update(e,t){(e.transformTemplate||this.props.transformTemplate)&&this.scheduleRender(),this.prevProps=this.props,this.props=e,this.prevPresenceContext=this.presenceContext,this.presenceContext=t;for(let t=0;tt.variantChildren.delete(e)}addValue(e,t){let n=this.values.get(e);t!==n&&(n&&this.removeValue(e),this.bindToMotionValue(e,t),this.values.set(e,t),this.latestValues[e]=t.get())}removeValue(e){this.values.delete(e);let t=this.valueSubscriptions.get(e);t&&(t(),this.valueSubscriptions.delete(e)),delete this.latestValues[e],this.removeValueFromRenderState(e,this.renderState)}hasValue(e){return this.values.has(e)}getValue(e,t){if(this.props.values&&this.props.values[e])return this.props.values[e];let n=this.values.get(e);return n===void 0&&t!==void 0&&(n=Oo(t===null?void 0:t,{owner:this}),this.addValue(e,n)),n}readValue(e,t){let n=this.latestValues[e]!==void 0||!this.current?this.latestValues[e]:this.getBaseTargetFromProps(this.props,e)??this.readValueFromInstance(this.current,e,this.options);return n!=null&&(typeof n==`string`&&(Sn(n)||wn(n))?n=parseFloat(n):!Ys(n)&&ii.test(t)&&(n=is(e,t)),this.setBaseTarget(e,V(n)?n.get():n)),V(n)?n.get():n}setBaseTarget(e,t){this.baseTarget[e]=t}getBaseTarget(e){let{initial:t}=this.props,n;if(typeof t==`string`||typeof t==`object`){let r=xo(this.props,t,this.presenceContext?.custom);r&&(n=r[e])}if(t&&n!==void 0)return n;let r=this.getBaseTargetFromProps(this.props,e);return r!==void 0&&!V(r)?r:this.initialValues[e]!==void 0&&n===void 0?void 0:this.baseTarget[e]}on(e,t){return this.events[e]||(this.events[e]=new An),this.events[e].add(t)}notify(e,...t){this.events[e]&&this.events[e].notify(...t)}scheduleRenderMicrotask(){ds.render(this.render)}},_c=class extends gc{constructor(){super(...arguments),this.KeyframeResolver=ss}sortInstanceNodePosition(e,t){return e.compareDocumentPosition(t)&2?1:-1}getBaseTargetFromProps(e,t){let n=e.style;return n?n[t]:void 0}removeValueFromRenderState(e,{vars:t,style:n}){delete t[e],delete n[e]}handleChildMotionValue(){this.childSubscription&&(this.childSubscription(),delete this.childSubscription);let{children:e}=this.props;V(e)&&(this.childSubscription=e.on(`change`,e=>{this.current&&(this.current.textContent=`${e}`)}))}},vc=class{constructor(e){this.isMounted=!1,this.node=e}update(){}};function yc({top:e,left:t,right:n,bottom:r}){return{x:{min:t,max:n},y:{min:e,max:r}}}function bc({x:e,y:t}){return{top:t.min,right:e.max,bottom:t.max,left:e.min}}function xc(e,t){if(!t)return e;let n=t({x:e.left,y:e.top}),r=t({x:e.right,y:e.bottom});return{top:n.y,left:n.x,bottom:r.y,right:r.x}}function Sc(e){return e===void 0||e===1}function Cc({scale:e,scaleX:t,scaleY:n}){return!Sc(e)||!Sc(t)||!Sc(n)}function wc(e){return Cc(e)||Tc(e)||e.z||e.rotate||e.rotateX||e.rotateY||e.skewX||e.skewY}function Tc(e){return Ec(e.x)||Ec(e.y)}function Ec(e){return e&&e!==`0%`}function Dc(e,t,n){return n+t*(e-n)}function Oc(e,t,n,r,i){return i!==void 0&&(e=Dc(e,i,r)),Dc(e,n,r)+t}function kc(e,t=0,n=1,r,i){e.min=Oc(e.min,t,n,r,i),e.max=Oc(e.max,t,n,r,i)}function Ac(e,{x:t,y:n}){kc(e.x,t.translate,t.scale,t.originPoint),kc(e.y,n.translate,n.scale,n.originPoint)}var jc=.999999999999,Mc=1.0000000000001;function Nc(e,t,n,r=!1){let i=n.length;if(!i)return;t.x=t.y=1;let a,o;for(let s=0;sjc&&(t.x=1),t.yjc&&(t.y=1)}function Pc(e,t){e.min+=t,e.max+=t}function Fc(e,t,n,r,i=.5){kc(e,t,n,ci(e.min,e.max,i),r)}function Ic(e,t){return typeof e==`string`?parseFloat(e)/100*(t.max-t.min):e}function Lc(e,t,n){let r=n??e;Fc(e.x,Ic(t.x,r.x),t.scaleX,t.scale,t.originX),Fc(e.y,Ic(t.y,r.y),t.scaleY,t.scale,t.originY)}function Rc(e,t){return yc(xc(e.getBoundingClientRect(),t))}function zc(e,t,n){let r=Rc(e,n),{scroll:i}=t;return i&&(Pc(r.x,i.offset.x),Pc(r.y,i.offset.y)),r}var Bc={x:`translateX`,y:`translateY`,z:`translateZ`,transformPerspective:`perspective`},Vc=ha.length;function Hc(e,t,n){let r=``,i=!0;for(let a=0;a{if(!t.target)return e;if(typeof e==`string`)if(z.test(e))e=parseFloat(e);else return e;return`${Gc(e,t.target.x)}% ${Gc(e,t.target.y)}%`}},qc={correct:(e,{treeScale:t,projectionDelta:n})=>{let r=e,i=ii.parse(e);if(i.length>5)return r;let a=ii.createTransformer(e),o=typeof i[0]==`number`?0:1,s=n.x.scale*t.x,c=n.y.scale*t.y;i[0+o]/=s,i[1+o]/=c;let l=ci(s,c,.5);return typeof i[2+o]==`number`&&(i[2+o]/=l),typeof i[3+o]==`number`&&(i[3+o]/=l),a(i)}},Jc={borderRadius:{...Kc,applyTo:[`borderTopLeftRadius`,`borderTopRightRadius`,`borderBottomLeftRadius`,`borderBottomRightRadius`]},borderTopLeftRadius:Kc,borderTopRightRadius:Kc,borderBottomLeftRadius:Kc,borderBottomRightRadius:Kc,boxShadow:qc};function Yc(e,{layout:t,layoutId:n}){return ga.has(e)||e.startsWith(`origin`)||(t||n!==void 0)&&(!!Jc[e]||e===`opacity`)}function Xc(e,t,n){let r=e.style,i=t?.style,a={};if(!r)return a;for(let t in r)(V(r[t])||i&&V(i[t])||Yc(t,e)||n?.getValue(t)?.liveStyle!==void 0)&&(a[t]=r[t]);return a}function Zc(e){return window.getComputedStyle(e)}var Qc=class extends _c{constructor(){super(...arguments),this.type=`html`,this.renderInstance=Wc}readValueFromInstance(e,t){if(ga.has(t))return this.projection?.isProjecting?da(t):pa(e,t);{let n=Zc(e),r=(gr(t)?n.getPropertyValue(t):n[t])||0;return typeof r==`string`?r.trim():r}}measureInstanceViewportBox(e,{transformPagePoint:t}){return Rc(e,t)}build(e,t,n){Uc(e,t,n.transformTemplate)}scrapeMotionValuesFromProps(e,t,n){return Xc(e,t,n)}},$c={offset:`stroke-dashoffset`,array:`stroke-dasharray`},el={offset:`strokeDashoffset`,array:`strokeDasharray`};function tl(e,t,n=1,r=0,i=!0){e.pathLength=1;let a=i?$c:el;e[a.offset]=`${-r}`,e[a.array]=`${t} ${n}`}var nl=[`offsetDistance`,`offsetPath`,`offsetRotate`,`offsetAnchor`];function rl(e,{attrX:t,attrY:n,attrScale:r,pathLength:i,pathSpacing:a=1,pathOffset:o=0,...s},c,l,u){if(Uc(e,s,l),c){e.style.viewBox&&(e.attrs.viewBox=e.style.viewBox);return}e.attrs=e.style,e.style={};let{attrs:d,style:f}=e;d.transform&&(f.transform=d.transform,delete d.transform),(f.transform||d.transformOrigin)&&(f.transformOrigin=d.transformOrigin??`50% 50%`,delete d.transformOrigin),f.transform&&(f.transformBox=u?.transformBox??`fill-box`,delete d.transformBox);for(let e of nl)d[e]!==void 0&&(f[e]=d[e],delete d[e]);t!==void 0&&(d.x=t),n!==void 0&&(d.y=n),r!==void 0&&(d.scale=r),i!==void 0&&tl(d,i,a,o,!1)}var il=new Set([`baseFrequency`,`diffuseConstant`,`kernelMatrix`,`kernelUnitLength`,`keySplines`,`keyTimes`,`limitingConeAngle`,`markerHeight`,`markerWidth`,`numOctaves`,`targetX`,`targetY`,`surfaceScale`,`specularConstant`,`specularExponent`,`stdDeviation`,`tableValues`,`viewBox`,`gradientTransform`,`pathLength`,`startOffset`,`textLength`,`lengthAdjust`]),al=e=>typeof e==`string`&&e.toLowerCase()===`svg`;function ol(e,t,n,r){Wc(e,t,void 0,r);for(let n in t.attrs)e.setAttribute(il.has(n)?n:Fo(n),t.attrs[n])}function sl(e,t,n){let r=Xc(e,t,n);for(let n in e)if(V(e[n])||V(t[n])){let t=ha.indexOf(n)===-1?n:`attr`+n.charAt(0).toUpperCase()+n.substring(1);r[t]=e[n]}return r}var cl=class extends _c{constructor(){super(...arguments),this.type=`svg`,this.isSVGTag=!1,this.measureInstanceViewportBox=$s}getBaseTargetFromProps(e,t){return e[t]}readValueFromInstance(e,t){if(ga.has(t)){let e=ns(t);return e&&e.default||0}return t=il.has(t)?t:Fo(t),e.getAttribute(t)}scrapeMotionValuesFromProps(e,t,n){return sl(e,t,n)}build(e,t,n){rl(e,t,this.isSVGTag,n.transformTemplate,n.style)}renderInstance(e,t,n,r){ol(e,t,n,r)}mount(e){this.isSVGTag=al(e.tagName),super.mount(e)}},ll=ic.length;function ul(e){if(!e)return;if(!e.isControllingVariants){let t=e.parent&&ul(e.parent)||{};return e.props.initial!==void 0&&(t.initial=e.props.initial),t}let t={};for(let n=0;nPromise.all(t.map(({animation:t,options:n})=>Ho(e,t,n)))}function hl(e){let t=ml(e),n=vl(),r=!0,i=!1,a=t=>(n,r)=>{let i=So(e,r,t===`exit`?e.presenceContext?.custom:void 0);if(i){let{transition:e,transitionEnd:t,...r}=i;n={...n,...r,...t}}return n};function o(n){t=n(e)}function s(o){let{props:s}=e,c=ul(e.parent)||{},l=[],u=new Set,d={},f=1/0;for(let t=0;tf&&g,x=!1,S=Array.isArray(h)?h:[h],C=S.reduce(a(p),{});_===!1&&(C={});let{prevResolvedValues:w={}}=m,T={...w,...C},E=t=>{b=!0,u.has(t)&&(x=!0,u.delete(t)),m.needsAnimating[t]=!0;let n=e.getValue(t);n&&(n.liveStyle=!1)};for(let e in T){let t=C[e],n=w[e];if(d.hasOwnProperty(e))continue;let r=!1;r=ko(t)&&ko(n)?!dl(t,n):t!==n,r?t==null?u.add(e):E(e):t!==void 0&&u.has(e)?E(e):m.protectedKeys[e]=!0}m.prevProp=h,m.prevResolvedValues=C,m.isActive&&(d={...d,...C}),(r||i)&&e.blockInitialAnimation&&(b=!1);let D=v&&y;b&&(!D||x)&&l.push(...S.map(t=>{let n={type:p};if(typeof t==`string`&&(r||i)&&!D&&e.manuallyAnimateOnMount&&e.parent){let{parent:r}=e,i=So(r,t);if(r.enteringChildren&&i){let{delayChildren:t}=i.transition||{};n.delay=oo(r.enteringChildren,e,t)}}return{animation:t,options:n}}))}if(u.size){let t={};if(typeof s.initial!=`boolean`){let n=So(e,Array.isArray(s.initial)?s.initial[0]:s.initial);n&&n.transition&&(t.transition=n.transition)}u.forEach(n=>{let r=e.getBaseTarget(n),i=e.getValue(n);i&&(i.liveStyle=!0),t[n]=r??null}),l.push({animation:t})}let p=!!l.length;return r&&(s.initial===!1||s.initial===s.animate)&&!e.manuallyAnimateOnMount&&(p=!1),r=!1,i=!1,p?t(l):Promise.resolve()}function c(t,r){if(n[t].isActive===r)return Promise.resolve();e.variantChildren?.forEach(e=>e.animationState?.setActive(t,r)),n[t].isActive=r;let i=s(t);for(let e in n)n[e].protectedKeys={};return i}return{animateChanges:s,setActive:c,setAnimateFunction:o,getState:()=>n,reset:()=>{n=vl(),i=!0}}}function gl(e,t){return typeof t==`string`?t!==e:Array.isArray(t)?!dl(t,e):!1}function _l(e=!1){return{isActive:e,protectedKeys:{},needsAnimating:{},prevResolvedValues:{}}}function vl(){return{animate:_l(!0),whileInView:_l(),whileHover:_l(),whileTap:_l(),whileDrag:_l(),whileFocus:_l(),exit:_l()}}function yl(e,t){e.min=t.min,e.max=t.max}function bl(e,t){yl(e.x,t.x),yl(e.y,t.y)}function xl(e,t){e.translate=t.translate,e.scale=t.scale,e.originPoint=t.originPoint,e.origin=t.origin}var Sl=1e-4,Cl=1-Sl,wl=1+Sl,Tl=.01,El=0-Tl,Dl=0+Tl;function Ol(e){return e.max-e.min}function kl(e,t,n){return Math.abs(e-t)<=n}function Al(e,t,n,r=.5){e.origin=r,e.originPoint=ci(t.min,t.max,e.origin),e.scale=Ol(n)/Ol(t),e.translate=ci(n.min,n.max,e.origin)-e.originPoint,(e.scale>=Cl&&e.scale<=wl||isNaN(e.scale))&&(e.scale=1),(e.translate>=El&&e.translate<=Dl||isNaN(e.translate))&&(e.translate=0)}function jl(e,t,n,r){Al(e.x,t.x,n.x,r?r.originX:void 0),Al(e.y,t.y,n.y,r?r.originY:void 0)}function Ml(e,t,n,r=0){e.min=(r?ci(n.min,n.max,r):n.min)+t.min,e.max=e.min+Ol(t)}function Nl(e,t,n,r){Ml(e.x,t.x,n.x,r?.x),Ml(e.y,t.y,n.y,r?.y)}function Pl(e,t,n,r=0){let i=r?ci(n.min,n.max,r):n.min;e.min=t.min-i,e.max=e.min+Ol(t)}function Fl(e,t,n,r){Pl(e.x,t.x,n.x,r?.x),Pl(e.y,t.y,n.y,r?.y)}function Il(e,t,n,r,i){return e-=t,e=Dc(e,1/n,r),i!==void 0&&(e=Dc(e,1/i,r)),e}function Ll(e,t=0,n=1,r=.5,i,a=e,o=e){if(Lr.test(t)&&(t=parseFloat(t),t=ci(o.min,o.max,t/100)-o.min),typeof t!=`number`)return;let s=ci(a.min,a.max,r);e===a&&(s-=t),e.min=Il(e.min,t,n,s,i),e.max=Il(e.max,t,n,s,i)}function Rl(e,t,[n,r,i],a,o){Ll(e,t[n],t[r],t[i],t.scale,a,o)}var zl=[`x`,`scaleX`,`originX`],Bl=[`y`,`scaleY`,`originY`];function Vl(e,t,n,r){Rl(e.x,t,zl,n?n.x:void 0,r?r.x:void 0),Rl(e.y,t,Bl,n?n.y:void 0,r?r.y:void 0)}function Hl(e){return e.translate===0&&e.scale===1}function Ul(e){return Hl(e.x)&&Hl(e.y)}function Wl(e,t){return e.min===t.min&&e.max===t.max}function H(e,t){return Wl(e.x,t.x)&&Wl(e.y,t.y)}function U(e,t){return Math.round(e.min)===Math.round(t.min)&&Math.round(e.max)===Math.round(t.max)}function Gl(e,t){return U(e.x,t.x)&&U(e.y,t.y)}function Kl(e){return Ol(e.x)/Ol(e.y)}function ql(e,t){return e.translate===t.translate&&e.scale===t.scale&&e.originPoint===t.originPoint}function Jl(e){return[e(`x`),e(`y`)]}function Yl(e,t,n){let r=``,i=e.x.translate/t.x,a=e.y.translate/t.y,o=n?.z||0;if((i||a||o)&&(r=`translate3d(${i}px, ${a}px, ${o}px) `),(t.x!==1||t.y!==1)&&(r+=`scale(${1/t.x}, ${1/t.y}) `),n){let{transformPerspective:e,rotate:t,rotateX:i,rotateY:a,skewX:o,skewY:s}=n;e&&(r=`perspective(${e}px) ${r}`),t&&(r+=`rotate(${t}deg) `),i&&(r+=`rotateX(${i}deg) `),a&&(r+=`rotateY(${a}deg) `),o&&(r+=`skewX(${o}deg) `),s&&(r+=`skewY(${s}deg) `)}let s=e.x.scale*t.x,c=e.y.scale*t.y;return(s!==1||c!==1)&&(r+=`scale(${s}, ${c})`),r||`none`}var Xl=[`borderTopLeftRadius`,`borderTopRightRadius`,`borderBottomLeftRadius`,`borderBottomRightRadius`],Zl=Xl.length,Ql=e=>typeof e==`string`?parseFloat(e):e,$l=e=>typeof e==`number`||z.test(e);function eu(e,t,n,r,i,a){i?(e.opacity=ci(0,n.opacity??1,nu(r)),e.opacityExit=ci(t.opacity??1,0,ru(r))):a&&(e.opacity=ci(t.opacity??1,n.opacity??1,r));for(let i=0;irt?1:n(kn(e,t,r))}function au(e,t,n){let r=V(e)?e:Oo(e);return r.start(yo(``,r,t,n)),r.animation}function ou(e,t,n,r={passive:!0}){return e.addEventListener(t,n,r),()=>e.removeEventListener(t,n)}var su=(e,t)=>e.depth-t.depth,cu=class{constructor(){this.children=[],this.isDirty=!1}add(e){vn(this.children,e),this.isDirty=!0}remove(e){yn(this.children,e),this.isDirty=!0}forEach(e){this.isDirty&&this.children.sort(su),this.isDirty=!1,this.children.forEach(e)}};function lu(e,t){let n=pr.now(),r=({timestamp:i})=>{let a=i-n;a>=t&&(cr(r),e(a-t))};return sr.setup(r,!0),()=>cr(r)}function uu(e){return V(e)?e.get():e}var du=class{constructor(){this.members=[]}add(e){vn(this.members,e);for(let t=this.members.length-1;t>=0;t--){let n=this.members[t];if(n===e||n===this.lead||n===this.prevLead)continue;let r=n.instance;(!r||r.isConnected===!1)&&!n.snapshot&&(yn(this.members,n),n.unmount())}e.scheduleRender()}remove(e){if(yn(this.members,e),e===this.prevLead&&(this.prevLead=void 0),e===this.lead){let e=this.members[this.members.length-1];e&&this.promote(e)}}relegate(e){for(let t=this.members.indexOf(e)-1;t>=0;t--){let e=this.members[t];if(e.isPresent!==!1&&e.instance?.isConnected!==!1)return this.promote(e),!0}return!1}promote(e,t){let n=this.lead;if(e!==n&&(this.prevLead=n,this.lead=e,e.show(),n)){n.updateSnapshot(),e.scheduleRender();let{layoutDependency:r}=n.options,{layoutDependency:i}=e.options;(r===void 0||r!==i)&&(e.resumeFrom=n,t&&(n.preserveOpacity=!0),n.snapshot&&(e.snapshot=n.snapshot,e.snapshot.latestValues=n.animationValues||n.latestValues),e.root?.isUpdating&&(e.isLayoutDirty=!0)),e.options.crossfade===!1&&n.hide()}}exitAnimationComplete(){this.members.forEach(e=>{e.options.onExitComplete?.(),e.resumingFrom?.options.onExitComplete?.()})}scheduleRender(){this.members.forEach(e=>e.instance&&e.scheduleRender(!1))}removeLeadSnapshot(){this.lead?.snapshot&&(this.lead.snapshot=void 0)}},fu={hasAnimatedSinceResize:!0,hasEverUpdated:!1},pu={nodes:0,calculatedTargetDeltas:0,calculatedProjections:0},mu=[``,`X`,`Y`,`Z`],hu=1e3,gu=0;function _u(e,t,n,r){let{latestValues:i}=t;i[e]&&(n[e]=i[e],t.setStaticValue(e,0),r&&(r[e]=0))}function vu(e){if(e.hasCheckedOptimisedAppear=!0,e.root===e)return;let{visualElement:t}=e.options;if(!t)return;let n=Lo(t);if(window.MotionHasOptimisedAnimation(n,`transform`)){let{layout:t,layoutId:r}=e.options;window.MotionCancelOptimisedAnimation(n,`transform`,sr,!(t||r))}let{parent:r}=e;r&&!r.hasCheckedOptimisedAppear&&vu(r)}function yu({attachResizeListener:e,defaultParent:t,measureScroll:n,checkIsScrollRoot:r,resetTransform:i}){return class{constructor(e={},n=t?.()){this.id=gu++,this.animationId=0,this.animationCommitId=0,this.children=new Set,this.options={},this.isTreeAnimating=!1,this.isAnimationBlocked=!1,this.isLayoutDirty=!1,this.isProjectionDirty=!1,this.isSharedProjectionDirty=!1,this.isTransformDirty=!1,this.updateManuallyBlocked=!1,this.updateBlockedByResize=!1,this.isUpdating=!1,this.isSVG=!1,this.needsReset=!1,this.shouldResetTransform=!1,this.hasCheckedOptimisedAppear=!1,this.treeScale={x:1,y:1},this.eventHandlers=new Map,this.hasTreeAnimated=!1,this.layoutVersion=0,this.updateScheduled=!1,this.scheduleUpdate=()=>this.update(),this.projectionUpdateScheduled=!1,this.checkUpdateFailed=()=>{this.isUpdating&&(this.isUpdating=!1,this.clearAllSnapshots())},this.updateProjection=()=>{this.projectionUpdateScheduled=!1,rr.value&&(pu.nodes=pu.calculatedTargetDeltas=pu.calculatedProjections=0),this.nodes.forEach(Su),this.nodes.forEach(ju),this.nodes.forEach(Mu),this.nodes.forEach(Cu),rr.addProjectionMetrics&&rr.addProjectionMetrics(pu)},this.resolvedRelativeTargetAt=0,this.linkedParentVersion=0,this.hasProjected=!1,this.isVisible=!0,this.animationProgress=0,this.sharedNodes=new Map,this.latestValues=e,this.root=n?n.root||n:this,this.path=n?[...n.path,n]:[],this.parent=n,this.depth=n?n.depth+1:0;for(let e=0;ethis.root.updateBlockedByResize=!1;sr.read(()=>{r=window.innerWidth}),e(t,()=>{let e=window.innerWidth;e!==r&&(r=e,this.root.updateBlockedByResize=!0,n&&n(),n=lu(i,250),fu.hasAnimatedSinceResize&&(fu.hasAnimatedSinceResize=!1,this.nodes.forEach(Au)))})}n&&this.root.registerSharedNode(n,this),this.options.animate!==!1&&i&&(n||r)&&this.addEventListener(`didUpdate`,({delta:e,hasLayoutChanged:t,hasRelativeLayoutChanged:n,layout:r})=>{if(this.isTreeAnimationBlocked()){this.target=void 0,this.relativeTarget=void 0;return}let a=this.options.transition||i.getDefaultTransition()||zu,{onLayoutAnimationStart:o,onLayoutAnimationComplete:s}=i.getProps(),c=!this.targetLayout||!Gl(this.targetLayout,r),l=!t&&n;if(this.options.layoutRoot||this.resumeFrom||l||t&&(c||!this.currentAnimation)){this.resumeFrom&&(this.resumingFrom=this.resumeFrom,this.resumingFrom.resumingFrom=void 0);let t={...go(a,`layout`),onPlay:o,onComplete:s};(i.shouldReduceMotion||this.options.layoutRoot)&&(t.delay=0,t.type=!1),this.startAnimation(t),this.setAnimationOrigin(e,l)}else t||Au(this),this.isLead()&&this.options.onExitComplete&&this.options.onExitComplete();this.targetLayout=r})}unmount(){this.options.layoutId&&this.willUpdate(),this.root.nodes.remove(this);let e=this.getStack();e&&e.remove(this),this.parent&&this.parent.children.delete(this),this.instance=void 0,this.eventHandlers.clear(),cr(this.updateProjection)}blockUpdate(){this.updateManuallyBlocked=!0}unblockUpdate(){this.updateManuallyBlocked=!1}isUpdateBlocked(){return this.updateManuallyBlocked||this.updateBlockedByResize}isTreeAnimationBlocked(){return this.isAnimationBlocked||this.parent&&this.parent.isTreeAnimationBlocked()||!1}startUpdate(){this.isUpdateBlocked()||(this.isUpdating=!0,this.nodes&&this.nodes.forEach(Nu),this.animationId++)}getTransformTemplate(){let{visualElement:e}=this.options;return e&&e.getProps().transformTemplate}willUpdate(e=!0){if(this.root.hasTreeAnimated=!0,this.root.isUpdateBlocked()){this.options.onExitComplete&&this.options.onExitComplete();return}if(window.MotionCancelOptimisedAnimation&&!this.hasCheckedOptimisedAppear&&vu(this),!this.root.isUpdating&&this.root.startUpdate(),this.isLayoutDirty)return;this.isLayoutDirty=!0;for(let e=0;e{this.isLayoutDirty?this.root.didUpdate():this.root.checkUpdateFailed()})}updateSnapshot(){this.snapshot||!this.instance||(this.snapshot=this.measure(),this.snapshot&&!Ol(this.snapshot.measuredBox.x)&&!Ol(this.snapshot.measuredBox.y)&&(this.snapshot=void 0))}updateLayout(){if(!this.instance||(this.updateScroll(),!(this.options.alwaysMeasureLayout&&this.isLead())&&!this.isLayoutDirty))return;if(this.resumeFrom&&!this.resumeFrom.instance)for(let e=0;e{let n=t/1e3;Fu(a.x,e.x,n),Fu(a.y,e.y,n),this.setTargetDelta(a),this.relativeTarget&&this.relativeTargetOrigin&&this.layout&&this.relativeParent&&this.relativeParent.layout&&(Fl(o,this.layout.layoutBox,this.relativeParent.layout.layoutBox,this.options.layoutAnchor||void 0),Lu(this.relativeTarget,this.relativeTargetOrigin,o,n),d&&H(this.relativeTarget,d)&&(this.isProjectionDirty=!1),d||=$s(),bl(d,this.relativeTarget)),s&&(this.animationValues=i,eu(i,r,this.latestValues,n,u,l)),this.root.scheduleUpdateProjection(),this.scheduleRender(),this.animationProgress=n},this.mixTargetDelta(this.options.layoutRoot?1e3:0)}startAnimation(e){this.notifyListeners(`animationStart`),this.currentAnimation?.stop(),this.resumingFrom?.currentAnimation?.stop(),this.pendingAnimation&&=(cr(this.pendingAnimation),void 0),this.pendingAnimation=sr.update(()=>{fu.hasAnimatedSinceResize=!0,mr.layout++,this.motionValue||=Oo(0),this.motionValue.jump(0,!1),this.currentAnimation=au(this.motionValue,[0,1e3],{...e,velocity:0,isSync:!0,onUpdate:t=>{this.mixTargetDelta(t),e.onUpdate&&e.onUpdate(t)},onStop:()=>{mr.layout--},onComplete:()=>{mr.layout--,e.onComplete&&e.onComplete(),this.completeAnimation()}}),this.resumingFrom&&(this.resumingFrom.currentAnimation=this.currentAnimation),this.pendingAnimation=void 0})}completeAnimation(){this.resumingFrom&&(this.resumingFrom.currentAnimation=void 0,this.resumingFrom.preserveOpacity=void 0);let e=this.getStack();e&&e.exitAnimationComplete(),this.resumingFrom=this.currentAnimation=this.animationValues=void 0,this.notifyListeners(`animationComplete`)}finishAnimation(){this.currentAnimation&&(this.mixTargetDelta&&this.mixTargetDelta(hu),this.currentAnimation.stop()),this.completeAnimation()}applyTransformsToTarget(){let e=this.getLead(),{targetWithTransforms:t,target:n,layout:r,latestValues:i}=e;if(!(!t||!n||!r)){if(this!==e&&this.layout&&r&&Wu(this.options.animationType,this.layout.layoutBox,r.layoutBox)){n=this.target||$s();let t=Ol(this.layout.layoutBox.x);n.x.min=e.target.x.min,n.x.max=n.x.min+t;let r=Ol(this.layout.layoutBox.y);n.y.min=e.target.y.min,n.y.max=n.y.min+r}bl(t,n),Lc(t,i),jl(this.projectionDeltaWithTransform,this.layoutCorrected,t,i)}}registerSharedNode(e,t){this.sharedNodes.has(e)||this.sharedNodes.set(e,new du),this.sharedNodes.get(e).add(t);let n=t.options.initialPromotionConfig;t.promote({transition:n?n.transition:void 0,preserveFollowOpacity:n&&n.shouldPreserveFollowOpacity?n.shouldPreserveFollowOpacity(t):void 0})}isLead(){let e=this.getStack();return e?e.lead===this:!0}getLead(){let{layoutId:e}=this.options;return e&&this.getStack()?.lead||this}getPrevLead(){let{layoutId:e}=this.options;return e?this.getStack()?.prevLead:void 0}getStack(){let{layoutId:e}=this.options;if(e)return this.root.sharedNodes.get(e)}promote({needsReset:e,transition:t,preserveFollowOpacity:n}={}){let r=this.getStack();r&&r.promote(this,n),e&&(this.projectionDelta=void 0,this.needsReset=!0),t&&this.setOptions({transition:t})}relegate(){let e=this.getStack();return e?e.relegate(this):!1}resetSkewAndRotation(){let{visualElement:e}=this.options;if(!e)return;let t=!1,{latestValues:n}=e;if((n.z||n.rotate||n.rotateX||n.rotateY||n.rotateZ||n.skewX||n.skewY)&&(t=!0),!t)return;let r={};n.z&&_u(`z`,e,r,this.animationValues);for(let t=0;te.currentAnimation?.stop()),this.root.nodes.forEach(Tu),this.root.sharedNodes.clear()}}}function bu(e){e.updateLayout()}function xu(e){let t=e.resumeFrom?.snapshot||e.snapshot;if(e.isLead()&&e.layout&&t&&e.hasListeners(`didUpdate`)){let{layoutBox:n,measuredBox:r}=e.layout,{animationType:i}=e.options,a=t.source!==e.layout.source;if(i===`size`)Jl(e=>{let r=a?t.measuredBox[e]:t.layoutBox[e],i=Ol(r);r.min=n[e].min,r.max=r.min+i});else if(i===`x`||i===`y`){let e=i===`x`?`y`:`x`;yl(a?t.measuredBox[e]:t.layoutBox[e],n[e])}else Wu(i,t.layoutBox,n)&&Jl(r=>{let i=a?t.measuredBox[r]:t.layoutBox[r],o=Ol(n[r]);i.max=i.min+o,e.relativeTarget&&!e.currentAnimation&&(e.isProjectionDirty=!0,e.relativeTarget[r].max=e.relativeTarget[r].min+o)});let o=Zs();jl(o,n,t.layoutBox);let s=Zs();a?jl(s,e.applyTransform(r,!0),t.measuredBox):jl(s,n,t.layoutBox);let c=!Ul(o),l=!1;if(!e.resumeFrom){let r=e.getClosestProjectingParent();if(r&&!r.resumeFrom){let{snapshot:i,layout:a}=r;if(i&&a){let o=e.options.layoutAnchor||void 0,s=$s();Fl(s,t.layoutBox,i.layoutBox,o);let c=$s();Fl(c,n,a.layoutBox,o),Gl(s,c)||(l=!0),r.options.layoutRoot&&(e.relativeTarget=c,e.relativeTargetOrigin=s,e.relativeParent=r)}}}e.notifyListeners(`didUpdate`,{layout:n,snapshot:t,delta:s,layoutDelta:o,hasLayoutChanged:c,hasRelativeLayoutChanged:l})}else if(e.isLead()){let{onExitComplete:t}=e.options;t&&t()}e.options.transition=void 0}function Su(e){rr.value&&pu.nodes++,e.parent&&(e.isProjecting()||(e.isProjectionDirty=e.parent.isProjectionDirty),e.isSharedProjectionDirty||=!!(e.isProjectionDirty||e.parent.isProjectionDirty||e.parent.isSharedProjectionDirty),e.isTransformDirty||=e.parent.isTransformDirty)}function Cu(e){e.isProjectionDirty=e.isSharedProjectionDirty=e.isTransformDirty=!1}function wu(e){e.clearSnapshot()}function Tu(e){e.clearMeasurements()}function Eu(e){e.isLayoutDirty=!0,e.updateLayout()}function Du(e){e.isLayoutDirty=!1}function Ou(e){e.isAnimationBlocked&&e.layout&&!e.isLayoutDirty&&(e.snapshot=e.layout,e.isLayoutDirty=!0)}function ku(e){let{visualElement:t}=e.options;t&&t.getProps().onBeforeLayoutMeasure&&t.notify(`BeforeLayoutMeasure`),e.resetTransform()}function Au(e){e.finishAnimation(),e.targetDelta=e.relativeTarget=e.target=void 0,e.isProjectionDirty=!0}function ju(e){e.resolveTargetDelta()}function Mu(e){e.calcProjection()}function Nu(e){e.resetSkewAndRotation()}function Pu(e){e.removeLeadSnapshot()}function Fu(e,t,n){e.translate=ci(t.translate,0,n),e.scale=ci(t.scale,1,n),e.origin=t.origin,e.originPoint=t.originPoint}function Iu(e,t,n,r){e.min=ci(t.min,n.min,r),e.max=ci(t.max,n.max,r)}function Lu(e,t,n,r){Iu(e.x,t.x,n.x,r),Iu(e.y,t.y,n.y,r)}function Ru(e){return e.animationValues&&e.animationValues.opacityExit!==void 0}var zu={duration:.45,ease:[.4,0,.1,1]},Bu=e=>typeof navigator<`u`&&navigator.userAgent&&navigator.userAgent.toLowerCase().includes(e),Vu=Bu(`applewebkit/`)&&!Bu(`chrome/`)?Math.round:En;function Hu(e){e.min=Vu(e.min),e.max=Vu(e.max)}function Uu(e){Hu(e.x),Hu(e.y)}function Wu(e,t,n){return e===`position`||e===`preserve-aspect`&&!kl(Kl(t),Kl(n),.2)}function Gu(e){return e!==e.root&&e.scroll?.wasRoot}var Ku=yu({attachResizeListener:(e,t)=>ou(e,`resize`,t),measureScroll:()=>({x:document.documentElement.scrollLeft||document.body?.scrollLeft||0,y:document.documentElement.scrollTop||document.body?.scrollTop||0}),checkIsScrollRoot:()=>!0}),qu={current:void 0},Ju=yu({measureScroll:e=>({x:e.scrollLeft,y:e.scrollTop}),defaultParent:()=>{if(!qu.current){let e=new Ku({});e.mount(window),e.setOptions({layoutScroll:!0}),qu.current=e}return qu.current},resetTransform:(e,t)=>{e.style.transform=t===void 0?`none`:t},checkIsScrollRoot:e=>window.getComputedStyle(e).position===`fixed`}),Yu=(0,N.createContext)({transformPagePoint:e=>e,isStatic:!1,reducedMotion:`never`});function Xu(e,t){if(typeof e==`function`)return e(t);e!=null&&(e.current=t)}function Zu(...e){return t=>{let n=!1,r=e.map(e=>{let r=Xu(e,t);return!n&&typeof r==`function`&&(n=!0),r});if(n)return()=>{for(let t=0;t{let{width:e,height:u,top:d,left:f,right:p,bottom:m}=c.current;if(t||a===!1||!s.current||!e||!u)return;let h=n===`left`?`left: ${f}`:`right: ${p}`,g=r===`bottom`?`bottom: ${m}`:`top: ${d}`;s.current.dataset.motionPopId=o;let _=document.createElement(`style`);l&&(_.nonce=l);let v=i??document.head;return v.appendChild(_),_.sheet&&_.sheet.insertRule(` + [data-motion-pop-id="${o}"] { + position: absolute !important; + width: ${e}px !important; + height: ${u}px !important; + ${h}px !important; + ${g}px !important; + } + `),()=>{s.current?.removeAttribute(`data-motion-pop-id`),v.contains(_)&&v.removeChild(_)}},[t]),(0,W.jsx)($u,{isPresent:t,childRef:s,sizeRef:c,pop:a,children:a===!1?e:N.cloneElement(e,{ref:u})})}var td=({children:e,initial:t,isPresent:n,onExitComplete:r,custom:i,presenceAffectsLayout:a,mode:o,anchorX:s,anchorY:c,root:l})=>{let u=hn(nd),d=(0,N.useId)(),f=!0,p=(0,N.useMemo)(()=>(f=!1,{id:d,initial:t,isPresent:n,custom:i,onExitComplete:e=>{u.set(e,!0);for(let e of u.values())if(!e)return;r&&r()},register:e=>(u.set(e,!1),()=>u.delete(e))}),[n,u,r]);return a&&f&&(p={...p}),(0,N.useMemo)(()=>{u.forEach((e,t)=>u.set(t,!1))},[n]),N.useEffect(()=>{!n&&!u.size&&r&&r()},[n]),e=(0,W.jsx)(ed,{pop:o===`popLayout`,isPresent:n,anchorX:s,anchorY:c,root:l,children:e}),(0,W.jsx)(_n.Provider,{value:p,children:e})};function nd(){return new Map}function rd(e=!0){let t=(0,N.useContext)(_n);if(t===null)return[!0,null];let{isPresent:n,onExitComplete:r,register:i}=t,a=(0,N.useId)();(0,N.useEffect)(()=>{if(e)return i(a)},[e]);let o=(0,N.useCallback)(()=>e&&r&&r(a),[a,r,e]);return!n&&r?[!1,o]:[!0]}var id=e=>e.key||``;function ad(e){let t=[];return N.Children.forEach(e,e=>{(0,N.isValidElement)(e)&&t.push(e)}),t}var od=({children:e,custom:t,initial:n=!0,onExitComplete:r,presenceAffectsLayout:i=!0,mode:a=`sync`,propagate:o=!1,anchorX:s=`left`,anchorY:c=`top`,root:l})=>{let[u,d]=rd(o),f=(0,N.useMemo)(()=>ad(e),[e]),p=o&&!u?[]:f.map(id),m=(0,N.useRef)(!0),h=(0,N.useRef)(f),g=hn(()=>new Map),_=(0,N.useRef)(new Set),[v,y]=(0,N.useState)(f),[b,x]=(0,N.useState)(f);gn(()=>{m.current=!1,h.current=f;for(let e=0;e{let v=id(e),y=o&&!u?!1:f===b||p.includes(v);return(0,W.jsx)(td,{isPresent:y,initial:!m.current||n?void 0:!1,custom:t,presenceAffectsLayout:i,mode:a,root:l,onExitComplete:y?void 0:()=>{if(_.current.has(v))return;if(g.has(v))_.current.add(v),g.set(v,!0);else return;let e=!0;g.forEach(t=>{t||(e=!1)}),e&&(C?.(),x(h.current),o&&d?.(),r&&r())},anchorX:s,anchorY:c,children:e},v)})})},sd=(0,N.createContext)({strict:!1}),cd={animation:[`animate`,`variants`,`whileHover`,`whileTap`,`exit`,`whileInView`,`whileFocus`,`whileDrag`],exit:[`exit`],drag:[`drag`,`dragControls`],focus:[`whileFocus`],hover:[`whileHover`,`onHoverStart`,`onHoverEnd`],tap:[`whileTap`,`onTap`,`onTapStart`,`onTapCancel`],pan:[`onPan`,`onPanStart`,`onPanSessionStart`,`onPanEnd`],inView:[`whileInView`,`onViewportEnter`,`onViewportLeave`],layout:[`layout`,`layoutId`]},ld=!1;function ud(){if(ld)return;let e={};for(let t in cd)e[t]={isEnabled:e=>cd[t].some(t=>!!e[t])};mc(e),ld=!0}function dd(){return ud(),hc()}function fd(e){let t=dd();for(let n in e)t[n]={...t[n],...e[n]};mc(t)}var pd=new Set(`animate.exit.variants.initial.style.values.variants.transition.transformTemplate.custom.inherit.onBeforeLayoutMeasure.onAnimationStart.onAnimationComplete.onUpdate.onDragStart.onDrag.onDragEnd.onMeasureDragConstraints.onDirectionLock.onDragTransitionEnd._dragX._dragY.onHoverStart.onHoverEnd.onViewportEnter.onViewportLeave.globalTapTarget.propagate.ignoreStrict.viewport`.split(`.`));function md(e){return e.startsWith(`while`)||e.startsWith(`drag`)&&e!==`draggable`||e.startsWith(`layout`)||e.startsWith(`onTap`)||e.startsWith(`onPan`)||e.startsWith(`onLayout`)||pd.has(e)}var hd=ge({default:()=>gd}),gd,_d=me((()=>{throw gd={},Error(`Could not resolve "@emotion/is-prop-valid" imported by "framer-motion". Is it installed?`)})),vd=e=>!md(e);function yd(e){typeof e==`function`&&(vd=t=>t.startsWith(`on`)?!md(t):e(t))}try{yd((_d(),ye(hd)).default)}catch{}function bd(e,t,n){let r={};for(let i in e)i===`values`&&typeof e.values==`object`||V(e[i])||(vd(i)||n===!0&&md(i)||!t&&!md(i)||e.draggable&&i.startsWith(`onDrag`))&&(r[i]=e[i]);return r}var xd=(0,N.createContext)({});function Sd(e,t){if(ac(e)){let{initial:t,animate:n}=e;return{initial:t===!1||nc(t)?t:void 0,animate:nc(n)?n:void 0}}return e.inherit===!1?{}:t}function Cd(e){let{initial:t,animate:n}=Sd(e,(0,N.useContext)(xd));return(0,N.useMemo)(()=>({initial:t,animate:n}),[wd(t),wd(n)])}function wd(e){return Array.isArray(e)?e.join(` `):e}var Td=()=>({style:{},transform:{},transformOrigin:{},vars:{}});function Ed(e,t,n){for(let r in t)!V(t[r])&&!Yc(r,n)&&(e[r]=t[r])}function G({transformTemplate:e},t){return(0,N.useMemo)(()=>{let n=Td();return Uc(n,t,e),Object.assign({},n.vars,n.style)},[t])}function Dd(e,t){let n=e.style||{},r={};return Ed(r,n,e),Object.assign(r,G(e,t)),r}function Od(e,t){let n={},r=Dd(e,t);return e.drag&&e.dragListener!==!1&&(n.draggable=!1,r.userSelect=r.WebkitUserSelect=r.WebkitTouchCallout=`none`,r.touchAction=e.drag===!0?`none`:`pan-${e.drag===`x`?`y`:`x`}`),e.tabIndex===void 0&&(e.onTap||e.onTapStart||e.whileTap)&&(n.tabIndex=0),n.style=r,n}var kd=()=>({...Td(),attrs:{}});function Ad(e,t,n,r){let i=(0,N.useMemo)(()=>{let n=kd();return rl(n,t,al(r),e.transformTemplate,e.style),{...n.attrs,style:{...n.style}}},[t]);if(e.style){let t={};Ed(t,e.style,e),i.style={...t,...i.style}}return i}var jd=[`animate`,`circle`,`defs`,`desc`,`ellipse`,`g`,`image`,`line`,`filter`,`marker`,`mask`,`metadata`,`path`,`pattern`,`polygon`,`polyline`,`rect`,`stop`,`switch`,`symbol`,`svg`,`text`,`tspan`,`use`,`view`];function Md(e){return typeof e!=`string`||e.includes(`-`)?!1:!!(jd.indexOf(e)>-1||/[A-Z]/u.test(e))}function Nd(e,t,n,{latestValues:r},i,a=!1,o){let s=(o??Md(e)?Ad:Od)(t,r,i,e),c=bd(t,typeof e==`string`,a),l=e===N.Fragment?{}:{...c,...s,ref:n},{children:u}=t,d=(0,N.useMemo)(()=>V(u)?u.get():u,[u]);return(0,N.createElement)(e,{...l,children:d})}function Pd({scrapeMotionValuesFromProps:e,createRenderState:t},n,r,i){return{latestValues:Fd(n,r,i,e),renderState:t()}}function Fd(e,t,n,r){let i={},a=r(e,{});for(let e in a)i[e]=uu(a[e]);let{initial:o,animate:s}=e,c=ac(e),l=oc(e);t&&l&&!c&&e.inherit!==!1&&(o===void 0&&(o=t.initial),s===void 0&&(s=t.animate));let u=n?n.initial===!1:!1;u||=o===!1;let d=u?s:o;if(d&&typeof d!=`boolean`&&!tc(d)){let t=Array.isArray(d)?d:[d];for(let n=0;n(t,n)=>{let r=(0,N.useContext)(xd),i=(0,N.useContext)(_n),a=()=>Pd(e,t,r,i);return n?a():hn(a)},Ld=Id({scrapeMotionValuesFromProps:Xc,createRenderState:Td}),Rd=Id({scrapeMotionValuesFromProps:sl,createRenderState:kd}),zd=Symbol.for(`motionComponentSymbol`);function Bd(e,t,n){let r=(0,N.useRef)(n);(0,N.useInsertionEffect)(()=>{r.current=n});let i=(0,N.useRef)(null);return(0,N.useCallback)(n=>{n&&e.onMount?.(n);let a=r.current;if(typeof a==`function`)if(n){let e=a(n);typeof e==`function`&&(i.current=e)}else i.current?(i.current(),i.current=null):a(n);else a&&(a.current=n);t&&(n?t.mount(n):t.unmount())},[t])}var Vd=(0,N.createContext)({});function Hd(e){return e&&typeof e==`object`&&Object.prototype.hasOwnProperty.call(e,`current`)}function Ud(e,t,n,r,i,a){let{visualElement:o}=(0,N.useContext)(xd),s=(0,N.useContext)(sd),c=(0,N.useContext)(_n),l=(0,N.useContext)(Yu),u=l.reducedMotion,d=l.skipAnimations,f=(0,N.useRef)(null),p=(0,N.useRef)(!1);r||=s.renderer,!f.current&&r&&(f.current=r(e,{visualState:t,parent:o,props:n,presenceContext:c,blockInitialAnimation:c?c.initial===!1:!1,reducedMotionConfig:u,skipAnimations:d,isSVG:a}),p.current&&f.current&&(f.current.manuallyAnimateOnMount=!0));let m=f.current,h=(0,N.useContext)(Vd);m&&!m.projection&&i&&(m.type===`html`||m.type===`svg`)&&Wd(f.current,n,i,h);let g=(0,N.useRef)(!1);(0,N.useInsertionEffect)(()=>{m&&g.current&&m.update(n,c)});let _=n[Io],v=(0,N.useRef)(!!_&&typeof window<`u`&&!window.MotionHandoffIsComplete?.(_)&&window.MotionHasOptimisedAnimation?.(_));return gn(()=>{p.current=!0,m&&(g.current=!0,window.MotionIsMounted=!0,m.updateFeatures(),m.scheduleRenderMicrotask(),v.current&&m.animationState&&m.animationState.animateChanges())}),(0,N.useEffect)(()=>{m&&(!v.current&&m.animationState&&m.animationState.animateChanges(),v.current&&=(queueMicrotask(()=>{window.MotionHandoffMarkAsComplete?.(_)}),!1),m.enteringChildren=void 0)}),m}function Wd(e,t,n,r){let{layoutId:i,layout:a,drag:o,dragConstraints:s,layoutScroll:c,layoutRoot:l,layoutAnchor:u,layoutCrossfade:d}=t;e.projection=new n(e.latestValues,t[`data-framer-portal-id`]?void 0:Gd(e.parent)),e.projection.setOptions({layoutId:i,layout:a,alwaysMeasureLayout:!!o||s&&Hd(s),visualElement:e,animationType:typeof a==`string`?a:`both`,initialPromotionConfig:r,crossfade:d,layoutScroll:c,layoutRoot:l,layoutAnchor:u})}function Gd(e){if(e)return e.options.allowProjection===!1?Gd(e.parent):e.projection}function Kd(e,{forwardMotionProps:t=!1,type:n}={},r,i){r&&fd(r);let a=n?n===`svg`:Md(e),o=a?Rd:Ld;function s(n,s){let c,l={...(0,N.useContext)(Yu),...n,layoutId:qd(n)},{isStatic:u}=l,d=Cd(n),f=o(n,u);if(!u&&typeof window<`u`){Jd(l,r);let t=Yd(l);c=t.MeasureLayout,d.visualElement=Ud(e,f,l,i,t.ProjectionNode,a)}return(0,W.jsxs)(xd.Provider,{value:d,children:[c&&d.visualElement?(0,W.jsx)(c,{visualElement:d.visualElement,...l}):null,Nd(e,n,Bd(f,d.visualElement,s),f,u,t,a)]})}s.displayName=`motion.${typeof e==`string`?e:`create(${e.displayName??e.name??``})`}`;let c=(0,N.forwardRef)(s);return c[zd]=e,c}function qd({layoutId:e}){let t=(0,N.useContext)(mn).id;return t&&e!==void 0?t+`-`+e:e}function Jd(e,t){(0,N.useContext)(sd).strict}function Yd(e){let{drag:t,layout:n}=dd();if(!t&&!n)return{};let r={...t,...n};return{MeasureLayout:t?.isEnabled(e)||n?.isEnabled(e)?r.MeasureLayout:void 0,ProjectionNode:r.ProjectionNode}}function Xd(e,t){if(typeof Proxy>`u`)return Kd;let n=new Map,r=(n,r)=>Kd(n,r,e,t);return new Proxy((e,t)=>r(e,t),{get:(i,a)=>a===`create`?r:(n.has(a)||n.set(a,Kd(a,void 0,e,t)),n.get(a))})}var Zd=(e,t)=>t.isSVG??Md(e)?new cl(t):new Qc(t,{allowProjection:e!==N.Fragment}),Qd=class extends vc{constructor(e){super(e),e.animationState||=hl(e)}updateAnimationControlsSubscription(){let{animate:e}=this.node.getProps();tc(e)&&(this.unmountControls=e.subscribe(this.node))}mount(){this.updateAnimationControlsSubscription()}update(){let{animate:e}=this.node.getProps(),{animate:t}=this.node.prevProps||{};e!==t&&this.updateAnimationControlsSubscription()}unmount(){this.node.animationState.reset(),this.unmountControls?.()}},$d=0,ef={animation:{Feature:Qd},exit:{Feature:class extends vc{constructor(){super(...arguments),this.id=$d++,this.isExitComplete=!1}update(){if(!this.node.presenceContext)return;let{isPresent:e,onExitComplete:t}=this.node.presenceContext,{isPresent:n}=this.node.prevPresenceContext||{};if(!this.node.animationState||e===n)return;if(e&&n===!1){if(this.isExitComplete){let{initial:e,custom:t}=this.node.getProps();if(typeof e==`string`){let n=So(this.node,e,t);if(n){let{transition:e,transitionEnd:t,...r}=n;for(let e in r)this.node.getValue(e)?.jump(r[e])}}this.node.animationState.reset(),this.node.animationState.animateChanges()}else this.node.animationState.setActive(`exit`,!1);this.isExitComplete=!1;return}let r=this.node.animationState.setActive(`exit`,!e);t&&!e&&r.then(()=>{this.isExitComplete=!0,t(this.id)})}mount(){let{register:e,onExitComplete:t}=this.node.presenceContext||{};t&&t(this.id),e&&(this.unmount=e(this.id))}unmount(){}}}};function tf(e){return{point:{x:e.pageX,y:e.pageY}}}var nf=e=>t=>bs(t)&&e(t,tf(t));function rf(e,t,n,r){return ou(e,t,nf(n),r)}var af=({current:e})=>e?e.ownerDocument.defaultView:null,of=(e,t)=>Math.abs(e-t);function sf(e,t){let n=of(e.x,t.x),r=of(e.y,t.y);return Math.sqrt(n**2+r**2)}var cf=new Set([`auto`,`scroll`]),lf=class{constructor(e,t,{transformPagePoint:n,contextWindow:r=window,dragSnapToOrigin:i=!1,distanceThreshold:a=3,element:o}={}){if(this.startEvent=null,this.lastMoveEvent=null,this.lastMoveEventInfo=null,this.lastRawMoveEventInfo=null,this.handlers={},this.contextWindow=window,this.scrollPositions=new Map,this.removeScrollListeners=null,this.onElementScroll=e=>{this.handleScroll(e.target)},this.onWindowScroll=()=>{this.handleScroll(window)},this.updatePoint=()=>{if(!(this.lastMoveEvent&&this.lastMoveEventInfo))return;this.lastRawMoveEventInfo&&(this.lastMoveEventInfo=uf(this.lastRawMoveEventInfo,this.transformPagePoint));let e=ff(this.lastMoveEventInfo,this.history),t=this.startEvent!==null,n=sf(e.offset,{x:0,y:0})>=this.distanceThreshold;if(!t&&!n)return;let{point:r}=e,{timestamp:i}=lr;this.history.push({...r,timestamp:i});let{onStart:a,onMove:o}=this.handlers;t||(a&&a(this.lastMoveEvent,e),this.startEvent=this.lastMoveEvent),o&&o(this.lastMoveEvent,e)},this.handlePointerMove=(e,t)=>{this.lastMoveEvent=e,this.lastRawMoveEventInfo=t,this.lastMoveEventInfo=uf(t,this.transformPagePoint),sr.update(this.updatePoint,!0)},this.handlePointerUp=(e,t)=>{this.end();let{onEnd:n,onSessionEnd:r,resumeAnimation:i}=this.handlers;if((this.dragSnapToOrigin||!this.startEvent)&&i&&i(),!(this.lastMoveEvent&&this.lastMoveEventInfo))return;let a=ff(e.type===`pointercancel`?this.lastMoveEventInfo:uf(t,this.transformPagePoint),this.history);this.startEvent&&n&&n(e,a),r&&r(e,a)},!bs(e))return;this.dragSnapToOrigin=i,this.handlers=t,this.transformPagePoint=n,this.distanceThreshold=a,this.contextWindow=r||window;let s=uf(tf(e),this.transformPagePoint),{point:c}=s,{timestamp:l}=lr;this.history=[{...c,timestamp:l}];let{onSessionStart:u}=t;u&&u(e,ff(s,this.history)),this.removeListeners=On(rf(this.contextWindow,`pointermove`,this.handlePointerMove),rf(this.contextWindow,`pointerup`,this.handlePointerUp),rf(this.contextWindow,`pointercancel`,this.handlePointerUp)),o&&this.startScrollTracking(o)}startScrollTracking(e){let t=e.parentElement;for(;t;){let e=getComputedStyle(t);(cf.has(e.overflowX)||cf.has(e.overflowY))&&this.scrollPositions.set(t,{x:t.scrollLeft,y:t.scrollTop}),t=t.parentElement}this.scrollPositions.set(window,{x:window.scrollX,y:window.scrollY}),window.addEventListener(`scroll`,this.onElementScroll,{capture:!0}),window.addEventListener(`scroll`,this.onWindowScroll),this.removeScrollListeners=()=>{window.removeEventListener(`scroll`,this.onElementScroll,{capture:!0}),window.removeEventListener(`scroll`,this.onWindowScroll)}}handleScroll(e){let t=this.scrollPositions.get(e);if(!t)return;let n=e===window,r=n?{x:window.scrollX,y:window.scrollY}:{x:e.scrollLeft,y:e.scrollTop},i={x:r.x-t.x,y:r.y-t.y};i.x===0&&i.y===0||(n?this.lastMoveEventInfo&&(this.lastMoveEventInfo.point.x+=i.x,this.lastMoveEventInfo.point.y+=i.y):this.history.length>0&&(this.history[0].x-=i.x,this.history[0].y-=i.y),this.scrollPositions.set(e,r),sr.update(this.updatePoint,!0))}updateHandlers(e){this.handlers=e}end(){this.removeListeners&&this.removeListeners(),this.removeScrollListeners&&this.removeScrollListeners(),this.scrollPositions.clear(),cr(this.updatePoint)}};function uf(e,t){return t?{point:t(e.point)}:e}function df(e,t){return{x:e.x-t.x,y:e.y-t.y}}function ff({point:e},t){return{point:e,delta:df(e,mf(t)),offset:df(e,pf(t)),velocity:hf(t,.1)}}function pf(e){return e[0]}function mf(e){return e[e.length-1]}function hf(e,t){if(e.length<2)return{x:0,y:0};let n=e.length-1,r=null,i=mf(e);for(;n>=0&&(r=e[n],!(i.timestamp-r.timestamp>jn(t)));)n--;if(!r)return{x:0,y:0};r===e[0]&&e.length>2&&i.timestamp-r.timestamp>jn(t)*2&&(r=e[1]);let a=Mn(i.timestamp-r.timestamp);if(a===0)return{x:0,y:0};let o={x:(i.x-r.x)/a,y:(i.y-r.y)/a};return o.x===1/0&&(o.x=0),o.y===1/0&&(o.y=0),o}function gf(e,{min:t,max:n},r){return t!==void 0&&en&&(e=r?ci(n,e,r.max):Math.min(e,n)),e}function _f(e,t,n){return{min:t===void 0?void 0:e.min+t,max:n===void 0?void 0:e.max+n-(e.max-e.min)}}function vf(e,{top:t,left:n,bottom:r,right:i}){return{x:_f(e.x,n,i),y:_f(e.y,t,r)}}function yf(e,t){let n=t.min-e.min,r=t.max-e.max;return t.max-t.minr?n=kn(t.min,t.max-r,e.min):r>i&&(n=kn(e.min,e.max-i,t.min)),bn(0,1,n)}function Sf(e,t){let n={};return t.min!==void 0&&(n.min=t.min-e.min),t.max!==void 0&&(n.max=t.max-e.min),n}var Cf=.35;function wf(e=Cf){return e===!1?e=0:e===!0&&(e=Cf),{x:Tf(e,`left`,`right`),y:Tf(e,`top`,`bottom`)}}function Tf(e,t,n){return{min:Ef(e,t),max:Ef(e,n)}}function Ef(e,t){return typeof e==`number`?e:e[t]||0}var Df=new WeakMap,Of=class{constructor(e){this.openDragLock=null,this.isDragging=!1,this.currentDirection=null,this.originPoint={x:0,y:0},this.constraints=!1,this.hasMutatedConstraints=!1,this.elastic=$s(),this.latestPointerEvent=null,this.latestPanInfo=null,this.visualElement=e}start(e,{snapToCursor:t=!1,distanceThreshold:n}={}){let{presenceContext:r}=this.visualElement;if(r&&r.isPresent===!1)return;let i=e=>{t&&this.snapToCursor(tf(e).point),this.stopAnimation()},a=(e,t)=>{let{drag:n,dragPropagation:r,onDragStart:i}=this.getProps();if(n&&!r&&(this.openDragLock&&this.openDragLock(),this.openDragLock=hs(n),!this.openDragLock))return;this.latestPointerEvent=e,this.latestPanInfo=t,this.isDragging=!0,this.currentDirection=null,this.resolveConstraints(),this.visualElement.projection&&(this.visualElement.projection.isAnimationBlocked=!0,this.visualElement.projection.target=void 0),Jl(e=>{let t=this.getAxisMotionValue(e).get()||0;if(Lr.test(t)){let{projection:n}=this.visualElement;if(n&&n.layout){let r=n.layout.layoutBox[e];r&&(t=Ol(r)*(parseFloat(t)/100))}}this.originPoint[e]=t}),i&&sr.update(()=>i(e,t),!1,!0),Po(this.visualElement,`transform`);let{animationState:a}=this.visualElement;a&&a.setActive(`whileDrag`,!0)},o=(e,t)=>{this.latestPointerEvent=e,this.latestPanInfo=t;let{dragPropagation:n,dragDirectionLock:r,onDirectionLock:i,onDrag:a}=this.getProps();if(!n&&!this.openDragLock)return;let{offset:o}=t;if(r&&this.currentDirection===null){this.currentDirection=Mf(o),this.currentDirection!==null&&i&&i(this.currentDirection);return}this.updateAxis(`x`,t.point,o),this.updateAxis(`y`,t.point,o),this.visualElement.render(),a&&sr.update(()=>a(e,t),!1,!0)},s=(e,t)=>{this.latestPointerEvent=e,this.latestPanInfo=t,this.stop(e,t),this.latestPointerEvent=null,this.latestPanInfo=null},c=()=>{let{dragSnapToOrigin:e}=this.getProps();(e||this.constraints)&&this.startAnimation({x:0,y:0})},{dragSnapToOrigin:l}=this.getProps();this.panSession=new lf(e,{onSessionStart:i,onStart:a,onMove:o,onSessionEnd:s,resumeAnimation:c},{transformPagePoint:this.visualElement.getTransformPagePoint(),dragSnapToOrigin:l,distanceThreshold:n,contextWindow:af(this.visualElement),element:this.visualElement.current})}stop(e,t){let n=e||this.latestPointerEvent,r=t||this.latestPanInfo,i=this.isDragging;if(this.cancel(),!i||!r||!n)return;let{velocity:a}=r;this.startAnimation(a);let{onDragEnd:o}=this.getProps();o&&sr.postRender(()=>o(n,r))}cancel(){this.isDragging=!1;let{projection:e,animationState:t}=this.visualElement;e&&(e.isAnimationBlocked=!1),this.endPanSession();let{dragPropagation:n}=this.getProps();!n&&this.openDragLock&&(this.openDragLock(),this.openDragLock=null),t&&t.setActive(`whileDrag`,!1)}endPanSession(){this.panSession&&this.panSession.end(),this.panSession=void 0}updateAxis(e,t,n){let{drag:r}=this.getProps();if(!n||!jf(e,r,this.currentDirection))return;let i=this.getAxisMotionValue(e),a=this.originPoint[e]+n[e];this.constraints&&this.constraints[e]&&(a=gf(a,this.constraints[e],this.elastic[e])),i.set(a)}resolveConstraints(){let{dragConstraints:e,dragElastic:t}=this.getProps(),n=this.visualElement.projection&&!this.visualElement.projection.layout?this.visualElement.projection.measure(!1):this.visualElement.projection?.layout,r=this.constraints;e&&Hd(e)?this.constraints||=this.resolveRefConstraints():e&&n?this.constraints=vf(n.layoutBox,e):this.constraints=!1,this.elastic=wf(t),r!==this.constraints&&!Hd(e)&&n&&this.constraints&&!this.hasMutatedConstraints&&Jl(e=>{this.constraints!==!1&&this.getAxisMotionValue(e)&&(this.constraints[e]=Sf(n.layoutBox[e],this.constraints[e]))})}resolveRefConstraints(){let{dragConstraints:e,onMeasureDragConstraints:t}=this.getProps();if(!e||!Hd(e))return!1;let n=e.current,{projection:r}=this.visualElement;if(!r||!r.layout)return!1;let i=zc(n,r.root,this.visualElement.getTransformPagePoint()),a=bf(r.layout.layoutBox,i);if(t){let e=t(bc(a));this.hasMutatedConstraints=!!e,e&&(a=yc(e))}return a}startAnimation(e){let{drag:t,dragMomentum:n,dragElastic:r,dragTransition:i,dragSnapToOrigin:a,onDragTransitionEnd:o}=this.getProps(),s=this.constraints||{},c=Jl(o=>{if(!jf(o,t,this.currentDirection))return;let c=s&&s[o]||{};(a===!0||a===o)&&(c={min:0,max:0});let l=r?200:1e6,u=r?40:1e7,d={type:`inertia`,velocity:n?e[o]:0,bounceStiffness:l,bounceDamping:u,timeConstant:750,restDelta:1,restSpeed:10,...i,...c};return this.startAxisValueAnimation(o,d)});return Promise.all(c).then(o)}startAxisValueAnimation(e,t){let n=this.getAxisMotionValue(e);return Po(this.visualElement,e),n.start(yo(e,n,0,t,this.visualElement,!1))}stopAnimation(){Jl(e=>this.getAxisMotionValue(e).stop())}getAxisMotionValue(e){let t=`_drag${e.toUpperCase()}`,n=this.visualElement.getProps();return n[t]||this.visualElement.getValue(e,(n.initial?n.initial[e]:void 0)||0)}snapToCursor(e){Jl(t=>{let{drag:n}=this.getProps();if(!jf(t,n,this.currentDirection))return;let{projection:r}=this.visualElement,i=this.getAxisMotionValue(t);if(r&&r.layout){let{min:n,max:a}=r.layout.layoutBox[t],o=i.get()||0;i.set(e[t]-ci(n,a,.5)+o)}})}scalePositionWithinConstraints(){if(!this.visualElement.current)return;let{drag:e,dragConstraints:t}=this.getProps(),{projection:n}=this.visualElement;if(!Hd(t)||!n||!this.constraints)return;this.stopAnimation();let r={x:0,y:0};Jl(e=>{let t=this.getAxisMotionValue(e);if(t&&this.constraints!==!1){let n=t.get();r[e]=xf({min:n,max:n},this.constraints[e])}});let{transformTemplate:i}=this.visualElement.getProps();this.visualElement.current.style.transform=i?i({},``):`none`,n.root&&n.root.updateScroll(),n.updateLayout(),this.constraints=!1,this.resolveConstraints(),Jl(t=>{if(!jf(t,e,null))return;let n=this.getAxisMotionValue(t),{min:i,max:a}=this.constraints[t];n.set(ci(i,a,r[t]))}),this.visualElement.render()}addListeners(){if(!this.visualElement.current)return;Df.set(this.visualElement,this);let e=this.visualElement.current,t=rf(e,`pointerdown`,t=>{let{drag:n,dragListener:r=!0}=this.getProps(),i=t.target,a=i!==e&&ws(i);n&&r&&!a&&this.start(t)}),n,r=()=>{let{dragConstraints:t}=this.getProps();Hd(t)&&t.current&&(this.constraints=this.resolveRefConstraints(),n||=Af(e,t.current,()=>this.scalePositionWithinConstraints()))},{projection:i}=this.visualElement,a=i.addEventListener(`measure`,r);i&&!i.layout&&(i.root&&i.root.updateScroll(),i.updateLayout()),sr.read(r);let o=ou(window,`resize`,()=>this.scalePositionWithinConstraints()),s=i.addEventListener(`didUpdate`,(({delta:e,hasLayoutChanged:t})=>{this.isDragging&&t&&(Jl(t=>{let n=this.getAxisMotionValue(t);n&&(this.originPoint[t]+=e[t].translate,n.set(n.get()+e[t].translate))}),this.visualElement.render())}));return()=>{o(),t(),a(),s&&s(),n&&n()}}getProps(){let e=this.visualElement.getProps(),{drag:t=!1,dragDirectionLock:n=!1,dragPropagation:r=!1,dragConstraints:i=!1,dragElastic:a=Cf,dragMomentum:o=!0}=e;return{...e,drag:t,dragDirectionLock:n,dragPropagation:r,dragConstraints:i,dragElastic:a,dragMomentum:o}}};function kf(e){let t=!0;return()=>{if(t){t=!1;return}e()}}function Af(e,t,n){let r=Ks(e,kf(n)),i=Ks(t,kf(n));return()=>{r(),i()}}function jf(e,t,n){return(t===!0||t===e)&&(n===null||n===e)}function Mf(e,t=10){let n=null;return Math.abs(e.y)>t?n=`y`:Math.abs(e.x)>t&&(n=`x`),n}var Nf=class extends vc{constructor(e){super(e),this.removeGroupControls=En,this.removeListeners=En,this.controls=new Of(e)}mount(){let{dragControls:e}=this.node.getProps();e&&(this.removeGroupControls=e.subscribe(this.controls)),this.removeListeners=this.controls.addListeners()||En}update(){let{dragControls:e}=this.node.getProps(),{dragControls:t}=this.node.prevProps||{};e!==t&&(this.removeGroupControls(),e&&(this.removeGroupControls=e.subscribe(this.controls)))}unmount(){this.removeGroupControls(),this.removeListeners(),this.controls.isDragging||this.controls.endPanSession()}},Pf=e=>(t,n)=>{e&&sr.update(()=>e(t,n),!1,!0)},Ff=class extends vc{constructor(){super(...arguments),this.removePointerDownListener=En}onPointerDown(e){this.session=new lf(e,this.createPanHandlers(),{transformPagePoint:this.node.getTransformPagePoint(),contextWindow:af(this.node)})}createPanHandlers(){let{onPanSessionStart:e,onPanStart:t,onPan:n,onPanEnd:r}=this.node.getProps();return{onSessionStart:Pf(e),onStart:Pf(t),onMove:Pf(n),onEnd:(e,t)=>{delete this.session,r&&sr.postRender(()=>r(e,t))}}}mount(){this.removePointerDownListener=rf(this.node.current,`pointerdown`,e=>this.onPointerDown(e))}update(){this.session&&this.session.updateHandlers(this.createPanHandlers())}unmount(){this.removePointerDownListener(),this.session&&this.session.end()}},If=!1,Lf=class extends N.Component{componentDidMount(){let{visualElement:e,layoutGroup:t,switchLayoutGroup:n,layoutId:r}=this.props,{projection:i}=e;i&&(t.group&&t.group.add(i),n&&n.register&&r&&n.register(i),If&&i.root.didUpdate(),i.addEventListener(`animationComplete`,()=>{this.safeToRemove()}),i.setOptions({...i.options,layoutDependency:this.props.layoutDependency,onExitComplete:()=>this.safeToRemove()})),fu.hasEverUpdated=!0}getSnapshotBeforeUpdate(e){let{layoutDependency:t,visualElement:n,drag:r,isPresent:i}=this.props,{projection:a}=n;return a?(a.isPresent=i,e.layoutDependency!==t&&a.setOptions({...a.options,layoutDependency:t}),If=!0,r||e.layoutDependency!==t||t===void 0||e.isPresent!==i?a.willUpdate():this.safeToRemove(),e.isPresent!==i&&(i?a.promote():a.relegate()||sr.postRender(()=>{let e=a.getStack();(!e||!e.members.length)&&this.safeToRemove()})),null):null}componentDidUpdate(){let{visualElement:e,layoutAnchor:t}=this.props,{projection:n}=e;n&&(n.options.layoutAnchor=t,n.root.didUpdate(),ds.postRender(()=>{!n.currentAnimation&&n.isLead()&&this.safeToRemove()}))}componentWillUnmount(){let{visualElement:e,layoutGroup:t,switchLayoutGroup:n}=this.props,{projection:r}=e;If=!0,r&&(r.scheduleCheckAfterUnmount(),t&&t.group&&t.group.remove(r),n&&n.deregister&&n.deregister(r))}safeToRemove(){let{safeToRemove:e}=this.props;e&&e()}render(){return null}};function Rf(e){let[t,n]=rd(),r=(0,N.useContext)(mn);return(0,W.jsx)(Lf,{...e,layoutGroup:r,switchLayoutGroup:(0,N.useContext)(Vd),isPresent:t,safeToRemove:n})}var zf={pan:{Feature:Ff},drag:{Feature:Nf,ProjectionNode:Ju,MeasureLayout:Rf}};function Bf(e,t,n){let{props:r}=e;e.animationState&&r.whileHover&&e.animationState.setActive(`whileHover`,n===`Start`);let i=r[`onHover`+n];i&&sr.postRender(()=>i(t,tf(t)))}var Vf=class extends vc{mount(){let{current:e}=this.node;e&&(this.unmount=vs(e,(e,t)=>(Bf(this.node,t,`Start`),e=>Bf(this.node,e,`End`))))}unmount(){}},Hf=class extends vc{constructor(){super(...arguments),this.isActive=!1}onFocus(){let e=!1;try{e=this.node.current.matches(`:focus-visible`)}catch{e=!0}!e||!this.node.animationState||(this.node.animationState.setActive(`whileFocus`,!0),this.isActive=!0)}onBlur(){!this.isActive||!this.node.animationState||(this.node.animationState.setActive(`whileFocus`,!1),this.isActive=!1)}mount(){this.unmount=On(ou(this.node.current,`focus`,()=>this.onFocus()),ou(this.node.current,`blur`,()=>this.onBlur()))}unmount(){}};function Uf(e,t,n){let{props:r}=e;if(e.current instanceof HTMLButtonElement&&e.current.disabled)return;e.animationState&&r.whileTap&&e.animationState.setActive(`whileTap`,n===`Start`);let i=r[`onTap`+(n===`End`?``:n)];i&&sr.postRender(()=>i(t,tf(t)))}var Wf=class extends vc{mount(){let{current:e}=this.node;if(!e)return;let{globalTapTarget:t,propagate:n}=this.node.props;this.unmount=js(e,(e,t)=>(Uf(this.node,t,`Start`),(e,{success:t})=>Uf(this.node,e,t?`End`:`Cancel`)),{useGlobalTarget:t,stopPropagation:n?.tap===!1})}unmount(){}},Gf=new WeakMap,Kf=new WeakMap,qf=e=>{let t=Gf.get(e.target);t&&t(e)},Jf=e=>{e.forEach(qf)};function Yf({root:e,...t}){let n=e||document;Kf.has(n)||Kf.set(n,{});let r=Kf.get(n),i=JSON.stringify(t);return r[i]||(r[i]=new IntersectionObserver(Jf,{root:e,...t})),r[i]}function Xf(e,t,n){let r=Yf(t);return Gf.set(e,n),r.observe(e),()=>{Gf.delete(e),r.unobserve(e)}}var Zf={some:0,all:1},Qf=class extends vc{constructor(){super(...arguments),this.hasEnteredView=!1,this.isInView=!1}startObserver(){this.stopObserver?.();let{viewport:e={}}=this.node.getProps(),{root:t,margin:n,amount:r=`some`,once:i}=e,a={root:t?t.current:void 0,rootMargin:n,threshold:typeof r==`number`?r:Zf[r]},o=e=>{let{isIntersecting:t}=e;if(this.isInView===t||(this.isInView=t,i&&!t&&this.hasEnteredView))return;t&&(this.hasEnteredView=!0),this.node.animationState&&this.node.animationState.setActive(`whileInView`,t);let{onViewportEnter:n,onViewportLeave:r}=this.node.getProps(),a=t?n:r;a&&a(e)};this.stopObserver=Xf(this.node.current,a,o)}mount(){this.startObserver()}update(){if(typeof IntersectionObserver>`u`)return;let{props:e,prevProps:t}=this.node;[`amount`,`margin`,`root`].some($f(e,t))&&this.startObserver()}unmount(){this.stopObserver?.(),this.hasEnteredView=!1,this.isInView=!1}};function $f({viewport:e={}},{viewport:t={}}={}){return n=>e[n]!==t[n]}var ep={inView:{Feature:Qf},tap:{Feature:Wf},focus:{Feature:Hf},hover:{Feature:Vf}},tp={layout:{ProjectionNode:Ju,MeasureLayout:Rf}},np=Xd({...ef,...ep,...zf,...tp},Zd),rp=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),ip=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),ap=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),op=e=>{let t=ap(e);return t.charAt(0).toUpperCase()+t.slice(1)},sp={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},cp=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},lp=(0,N.createContext)({}),up=()=>(0,N.useContext)(lp),dp=(0,N.forwardRef)(({color:e,size:t,strokeWidth:n,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>{let{size:l=24,strokeWidth:u=2,absoluteStrokeWidth:d=!1,color:f=`currentColor`,className:p=``}=up()??{},m=r??d?Number(n??u)*24/Number(t??l):n??u;return(0,N.createElement)(`svg`,{ref:c,...sp,width:t??l??sp.width,height:t??l??sp.height,stroke:e??f,strokeWidth:m,className:rp(`lucide`,p,i),...!a&&!cp(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,N.createElement)(e,t)),...Array.isArray(a)?a:[a]])}),fp=(e,t)=>{let n=(0,N.forwardRef)(({className:n,...r},i)=>(0,N.createElement)(dp,{ref:i,iconNode:t,className:rp(`lucide-${ip(op(e))}`,`lucide-${e}`,n),...r}));return n.displayName=op(e),n},pp=fp(`activity`,[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]]),mp=fp(`book-open`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z`,key:`ruj8y`}]]),hp=fp(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),gp=fp(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),_p=fp(`credit-card`,[[`rect`,{width:`20`,height:`14`,x:`2`,y:`5`,rx:`2`,key:`ynyp8z`}],[`line`,{x1:`2`,x2:`22`,y1:`10`,y2:`10`,key:`1b3vmo`}]]),vp=fp(`library`,[[`path`,{d:`m16 6 4 14`,key:`ji33uf`}],[`path`,{d:`M12 6v14`,key:`1n7gus`}],[`path`,{d:`M8 8v12`,key:`1gg7y9`}],[`path`,{d:`M4 4v16`,key:`6qkkli`}]]),yp=fp(`loader-circle`,[[`path`,{d:`M21 12a9 9 0 1 1-6.219-8.56`,key:`13zald`}]]),bp=fp(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]),xp=fp(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),Sp=fp(`shopping-bag`,[[`path`,{d:`M16 10a4 4 0 0 1-8 0`,key:`1ltviw`}],[`path`,{d:`M3.103 6.034h17.794`,key:`awc11p`}],[`path`,{d:`M3.4 5.467a2 2 0 0 0-.4 1.2V20a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6.667a2 2 0 0 0-.4-1.2l-2-2.667A2 2 0 0 0 17 2H7a2 2 0 0 0-1.6.8z`,key:`o988cm`}]]),Cp=fp(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),wp=fp(`wallet`,[[`path`,{d:`M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1`,key:`18etb6`}],[`path`,{d:`M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4`,key:`xoc0q4`}]]);function Tp(e){var t,n,r=``;if(typeof e==`string`||typeof e==`number`)r+=e;else if(typeof e==`object`)if(Array.isArray(e)){var i=e.length;for(t=0;t(\[(\d*)\])*)$/;function Pp(e){let t=e.type;if(Np.test(e.type)&&`components`in e){t=`(`;let n=e.components.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function Rp(e){return Lp.test(e)}function zp(e){return kp(Lp,e)}var Bp=/^event (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function Vp(e){return Bp.test(e)}function Hp(e){return kp(Bp,e)}var Up=/^function (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)(?: (?external|public{1}))?(?: (?pure|view|nonpayable|payable{1}))?(?: returns\s?\((?.*?)\))?$/;function Wp(e){return Up.test(e)}function Gp(e){return kp(Up,e)}var Kp=/^struct (?[a-zA-Z$_][a-zA-Z0-9$_]*) \{(?.*?)\}$/;function qp(e){return Kp.test(e)}function Jp(e){return kp(Kp,e)}var Yp=/^constructor\((?.*?)\)(?:\s(?payable{1}))?$/;function Xp(e){return Yp.test(e)}function Zp(e){return kp(Yp,e)}var Qp=/^fallback\(\) external(?:\s(?payable{1}))?$/;function $p(e){return Qp.test(e)}function em(e){return kp(Qp,e)}var tm=/^receive\(\) external payable$/;function nm(e){return tm.test(e)}var rm=new Set([`indexed`]),im=new Set([`calldata`,`memory`,`storage`]),am=class extends Op{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownTypeError`})}},om=class extends Op{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSolidityTypeError`})}},sm=class extends Op{constructor({param:e}){super(`Invalid ABI parameter.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParameterError`})}},cm=class extends Op{constructor({param:e,name:t}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`"${t}" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SolidityProtectedKeywordError`})}},lm=class extends Op{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidModifierError`})}},um=class extends Op{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`,`Data location can only be specified for array, struct, or mapping types, but "${n}" was given.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidFunctionModifierError`})}},dm=class extends Op{constructor({abiParameter:e}){super(`Invalid ABI parameter.`,{details:JSON.stringify(e,null,2),metaMessages:[`ABI parameter type is invalid.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiTypeParameterError`})}},fm=class extends Op{constructor({signature:e,type:t}){super(`Invalid ${t} signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidSignatureError`})}},pm=class extends Op{constructor({signature:e}){super(`Unknown signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSignatureError`})}},mm=class extends Op{constructor({signature:e}){super(`Invalid struct signature.`,{details:e,metaMessages:[`No properties exist.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidStructSignatureError`})}},hm=class extends Op{constructor({type:e}){super(`Circular reference detected.`,{metaMessages:[`Struct "${e}" is a circular reference.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`CircularReferenceError`})}},gm=class extends Op{constructor({current:e,depth:t}){super(`Unbalanced parentheses.`,{metaMessages:[`"${e.trim()}" has too many ${t>0?`opening`:`closing`} parentheses.`],details:`Depth "${t}"`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParenthesisError`})}};function _m(e,t,n){let r=``;if(n)for(let e of Object.entries(n)){if(!e)continue;let t=``;for(let n of e[1])t+=`[${n.type}${n.name?`:${n.name}`:``}]`;r+=`(${e[0]}{${t}})`}return t?`${t}:${e}${r}`:`${e}${r}`}var vm=new Map([[`address`,{type:`address`}],[`bool`,{type:`bool`}],[`bytes`,{type:`bytes`}],[`bytes32`,{type:`bytes32`}],[`int`,{type:`int256`}],[`int256`,{type:`int256`}],[`string`,{type:`string`}],[`uint`,{type:`uint256`}],[`uint8`,{type:`uint8`}],[`uint16`,{type:`uint16`}],[`uint24`,{type:`uint24`}],[`uint32`,{type:`uint32`}],[`uint64`,{type:`uint64`}],[`uint96`,{type:`uint96`}],[`uint112`,{type:`uint112`}],[`uint160`,{type:`uint160`}],[`uint192`,{type:`uint192`}],[`uint256`,{type:`uint256`}],[`address owner`,{type:`address`,name:`owner`}],[`address to`,{type:`address`,name:`to`}],[`bool approved`,{type:`bool`,name:`approved`}],[`bytes _data`,{type:`bytes`,name:`_data`}],[`bytes data`,{type:`bytes`,name:`data`}],[`bytes signature`,{type:`bytes`,name:`signature`}],[`bytes32 hash`,{type:`bytes32`,name:`hash`}],[`bytes32 r`,{type:`bytes32`,name:`r`}],[`bytes32 root`,{type:`bytes32`,name:`root`}],[`bytes32 s`,{type:`bytes32`,name:`s`}],[`string name`,{type:`string`,name:`name`}],[`string symbol`,{type:`string`,name:`symbol`}],[`string tokenURI`,{type:`string`,name:`tokenURI`}],[`uint tokenId`,{type:`uint256`,name:`tokenId`}],[`uint8 v`,{type:`uint8`,name:`v`}],[`uint256 balance`,{type:`uint256`,name:`balance`}],[`uint256 tokenId`,{type:`uint256`,name:`tokenId`}],[`uint256 value`,{type:`uint256`,name:`value`}],[`event:address indexed from`,{type:`address`,name:`from`,indexed:!0}],[`event:address indexed to`,{type:`address`,name:`to`,indexed:!0}],[`event:uint indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}],[`event:uint256 indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}]]);function ym(e,t={}){if(Wp(e))return bm(e,t);if(Vp(e))return xm(e,t);if(Rp(e))return Sm(e,t);if(Xp(e))return Cm(e,t);if($p(e))return wm(e);if(nm(e))return{type:`receive`,stateMutability:`payable`};throw new pm({signature:e})}function bm(e,t={}){let n=Gp(e);if(!n)throw new fm({signature:e,type:`function`});let r=km(n.parameters),i=[],a=r.length;for(let e=0;e[a-zA-Z$_][a-zA-Z0-9$_]*(?:\spayable)?)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,Em=/^\((?.+?)\)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,Dm=/^u?int$/;function Om(e,t){let n=_m(e,t?.type,t?.structs);if(vm.has(n))return vm.get(n);let r=Mp.test(e),i=kp(r?Em:Tm,e);if(!i)throw new sm({param:e});if(i.name&&Mm(i.name))throw new cm({param:e,name:i.name});let a=i.name?{name:i.name}:{},o=i.modifier===`indexed`?{indexed:!0}:{},s=t?.structs??{},c,l={};if(r){c=`tuple`;let e=km(i.type),t=[],n=e.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?$/;function Im(e=[],t={},n=new Set){let r=[],i=e.length;for(let a=0;at(e,n)}function Rm(e,{includeName:t=!1}={}){if(e.type!==`function`&&e.type!==`event`&&e.type!==`error`)throw new hh(e.type);return`${e.name}(${zm(e.inputs,{includeName:t})})`}function zm(e,{includeName:t=!1}={}){return e?e.map(e=>Bm(e,{includeName:t})).join(t?`, `:`,`):``}function Bm(e,{includeName:t}){return e.type.startsWith(`tuple`)?`(${zm(e.components,{includeName:t})})${e.type.slice(5)}`:e.type+(t&&e.name?` ${e.name}`:``)}function Vm(e,{strict:t=!0}={}){return!e||typeof e!=`string`?!1:t?/^0x[0-9a-fA-F]*$/.test(e):e.startsWith(`0x`)}function Hm(e){return Vm(e,{strict:!1})?Math.ceil((e.length-2)/2):e.length}var Um=`2.48.4`,Wm={getDocsUrl:({docsBaseUrl:e,docsPath:t=``,docsSlug:n})=>t?`${e??`https://viem.sh`}${t}${n?`#${n}`:``}`:void 0,version:`viem@${Um}`},q=class e extends Error{constructor(t,n={}){let r=n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details,i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=Wm.getDocsUrl?.({...n,docsPath:i}),o=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...a?[`Docs: ${a}`]:[],...r?[`Details: ${r}`]:[],...Wm.version?[`Version: ${Wm.version}`]:[]].join(` +`);super(o,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.name=n.name??this.name,this.shortMessage=t,this.version=Um}walk(e){return Gm(this,e)}};function Gm(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause!==void 0?Gm(e.cause,t):t?null:e}var Km=class extends q{constructor({docsPath:e}){super([`A constructor was not found on the ABI.`,`Make sure you are using the correct ABI and that the constructor exists on it.`].join(` +`),{docsPath:e,name:`AbiConstructorNotFoundError`})}},qm=class extends q{constructor({docsPath:e}){super(["Constructor arguments were provided (`args`), but a constructor parameters (`inputs`) were not found on the ABI.","Make sure you are using the correct ABI, and that the `inputs` attribute on the constructor exists."].join(` +`),{docsPath:e,name:`AbiConstructorParamsNotFoundError`})}},Jm=class extends q{constructor({data:e,params:t,size:n}){super([`Data size of ${n} bytes is too small for given parameters.`].join(` +`),{metaMessages:[`Params: (${zm(t,{includeName:!0})})`,`Data: ${e} (${n} bytes)`],name:`AbiDecodingDataSizeTooSmallError`}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`params`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`size`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=e,this.params=t,this.size=n}},Ym=class extends q{constructor({cause:e}={}){super(`Cannot decode zero data ("0x") with ABI parameters.`,{name:`AbiDecodingZeroDataError`,cause:e})}},Xm=class extends q{constructor({expectedLength:e,givenLength:t,type:n}){super([`ABI encoding array length mismatch for type ${n}.`,`Expected length: ${e}`,`Given length: ${t}`].join(` +`),{name:`AbiEncodingArrayLengthMismatchError`})}},Zm=class extends q{constructor({expectedSize:e,value:t}){super(`Size of bytes "${t}" (bytes${Hm(t)}) does not match expected size (bytes${e}).`,{name:`AbiEncodingBytesSizeMismatchError`})}},Qm=class extends q{constructor({expectedLength:e,givenLength:t}){super([`ABI encoding params/values length mismatch.`,`Expected length (params): ${e}`,`Given length (values): ${t}`].join(` +`),{name:`AbiEncodingLengthMismatchError`})}},$m=class extends q{constructor(e,{docsPath:t}){super([`Arguments (\`args\`) were provided to "${e}", but "${e}" on the ABI does not contain any parameters (\`inputs\`).`,`Cannot encode error result without knowing what the parameter types are.`,`Make sure you are using the correct ABI and that the inputs exist on it.`].join(` +`),{docsPath:t,name:`AbiErrorInputsNotFoundError`})}},eh=class extends q{constructor(e,{docsPath:t}={}){super([`Error ${e?`"${e}" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`].join(` +`),{docsPath:t,name:`AbiErrorNotFoundError`})}},th=class extends q{constructor(e,{docsPath:t,cause:n}){super([`Encoded error signature "${e}" not found on ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`,`You can look up the decoded signature here: https://4byte.sourcify.dev/?q=${e}.`].join(` +`),{docsPath:t,name:`AbiErrorSignatureNotFoundError`,cause:n}),Object.defineProperty(this,`signature`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.signature=e}},nh=class extends q{constructor({docsPath:e}){super(`Cannot extract event signature from empty topics.`,{docsPath:e,name:`AbiEventSignatureEmptyTopicsError`})}},rh=class extends q{constructor(e,{docsPath:t}){super([`Encoded event signature "${e}" not found on ABI.`,`Make sure you are using the correct ABI and that the event exists on it.`,`You can look up the signature here: https://4byte.sourcify.dev/?q=${e}.`].join(` +`),{docsPath:t,name:`AbiEventSignatureNotFoundError`})}},ih=class extends q{constructor(e,{docsPath:t}={}){super([`Event ${e?`"${e}" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the event exists on it.`].join(` +`),{docsPath:t,name:`AbiEventNotFoundError`})}},ah=class extends q{constructor(e,{docsPath:t}={}){super([`Function ${e?`"${e}" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the function exists on it.`].join(` +`),{docsPath:t,name:`AbiFunctionNotFoundError`})}},oh=class extends q{constructor(e,{docsPath:t}){super([`Function "${e}" does not contain any \`outputs\` on ABI.`,`Cannot decode function result without knowing what the parameter types are.`,`Make sure you are using the correct ABI and that the function exists on it.`].join(` +`),{docsPath:t,name:`AbiFunctionOutputsNotFoundError`})}},sh=class extends q{constructor(e,{docsPath:t}){super([`Encoded function signature "${e}" not found on ABI.`,`Make sure you are using the correct ABI and that the function exists on it.`,`You can look up the signature here: https://4byte.sourcify.dev/?q=${e}.`].join(` +`),{docsPath:t,name:`AbiFunctionSignatureNotFoundError`})}},ch=class extends q{constructor(e,t){super(`Found ambiguous types in overloaded ABI items.`,{metaMessages:[`\`${e.type}\` in \`${Rm(e.abiItem)}\`, and`,`\`${t.type}\` in \`${Rm(t.abiItem)}\``,``,`These types encode differently and cannot be distinguished at runtime.`,`Remove one of the ambiguous items in the ABI.`],name:`AbiItemAmbiguityError`})}},lh=class extends q{constructor({expectedSize:e,givenSize:t}){super(`Expected bytes${e}, got bytes${t}.`,{name:`BytesSizeMismatchError`})}},uh=class extends q{constructor({abiItem:e,data:t,params:n,size:r}){super([`Data size of ${r} bytes is too small for non-indexed event parameters.`].join(` +`),{metaMessages:[`Params: (${zm(n,{includeName:!0})})`,`Data: ${t} (${r} bytes)`],name:`DecodeLogDataMismatch`}),Object.defineProperty(this,`abiItem`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`params`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`size`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiItem=e,this.data=t,this.params=n,this.size=r}},dh=class extends q{constructor({abiItem:e,param:t}){super([`Expected a topic for indexed event parameter${t.name?` "${t.name}"`:``} on event "${Rm(e,{includeName:!0})}".`].join(` +`),{name:`DecodeLogTopicsMismatch`}),Object.defineProperty(this,`abiItem`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiItem=e}},fh=class extends q{constructor(e,{docsPath:t}){super([`Type "${e}" is not a valid encoding type.`,`Please provide a valid ABI type.`].join(` +`),{docsPath:t,name:`InvalidAbiEncodingType`})}},ph=class extends q{constructor(e,{docsPath:t}){super([`Type "${e}" is not a valid decoding type.`,`Please provide a valid ABI type.`].join(` +`),{docsPath:t,name:`InvalidAbiDecodingType`})}},mh=class extends q{constructor(e){super([`Value "${e}" is not a valid array.`].join(` +`),{name:`InvalidArrayError`})}},hh=class extends q{constructor(e){super([`"${e}" is not a valid definition type.`,`Valid types: "function", "event", "error"`].join(` +`),{name:`InvalidDefinitionTypeError`})}},gh=class extends q{constructor(e){super(`Filter type "${e}" is not supported.`,{name:`FilterTypeNotSupportedError`})}},_h=class extends q{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset "${e}" is out-of-bounds (size: ${n}).`,{name:`SliceOffsetOutOfBoundsError`})}},vh=class extends q{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (${e}) exceeds padding size (${t}).`,{name:`SizeExceedsPaddingSizeError`})}},yh=class extends q{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} is expected to be ${t} ${n} long, but is ${e} ${n} long.`,{name:`InvalidBytesLengthError`})}};function bh(e,{dir:t,size:n=32}={}){return typeof e==`string`?xh(e,{dir:t,size:n}):Sh(e,{dir:t,size:n})}function xh(e,{dir:t,size:n=32}={}){if(n===null)return e;let r=e.replace(`0x`,``);if(r.length>n*2)throw new vh({size:Math.ceil(r.length/2),targetSize:n,type:`hex`});return`0x${r[t===`right`?`padEnd`:`padStart`](n*2,`0`)}`}function Sh(e,{dir:t,size:n=32}={}){if(n===null)return e;if(e.length>n)throw new vh({size:e.length,targetSize:n,type:`bytes`});let r=new Uint8Array(n);for(let i=0;it)throw new Eh({givenSize:Hm(e),maxSize:t})}function kh(e,t={}){let{signed:n}=t;t.size&&Oh(e,{size:t.size});let r=BigInt(e);if(!n)return r;let i=(e.length-2)/2;return r<=(1n<t.toString(16).padStart(2,`0`));function Nh(e,t={}){return typeof e==`number`||typeof e==`bigint`?J(e,t):typeof e==`string`?Lh(e,t):typeof e==`boolean`?Ph(e,t):Fh(e,t)}function Ph(e,t={}){let n=`0x${Number(e)}`;return typeof t.size==`number`?(Oh(n,{size:t.size}),bh(n,{size:t.size})):n}function Fh(e,t={}){let n=``;for(let t=0;ta||i=Vh.zero&&e<=Vh.nine)return e-Vh.zero;if(e>=Vh.A&&e<=Vh.F)return e-(Vh.A-10);if(e>=Vh.a&&e<=Vh.f)return e-(Vh.a-10)}function Uh(e,t={}){let n=e;t.size&&(Oh(n,{size:t.size}),n=bh(n,{dir:`right`,size:t.size}));let r=n.slice(2);r.length%2&&(r=`0${r}`);let i=r.length/2,a=new Uint8Array(i);for(let e=0,t=0;e>Yh)*Zh)%Xh,t&Jh&&(i^=qh<<(qh<n>32?s(e,t,n):se(e,t,n),ag=(e,n,r)=>r>32?f(e,n,r):t(e,n,r);function og(e,t=24){let n=new Uint32Array(10);for(let r=24-t;r<24;r++){for(let t=0;t<10;t++)n[t]=e[t]^e[t+10]^e[t+20]^e[t+30]^e[t+40];for(let t=0;t<10;t+=2){let r=(t+8)%10,i=(t+2)%10,a=n[i],o=n[i+1],s=ig(a,o,1)^n[r],c=ag(a,o,1)^n[r+1];for(let n=0;n<50;n+=10)e[t+n]^=s,e[t+n+1]^=c}let t=e[2],i=e[3];for(let n=0;n<24;n++){let r=$h[n],a=ig(t,i,r),o=ag(t,i,r),s=Qh[n];t=e[s],i=e[s+1],e[s]=a,e[s+1]=o}for(let t=0;t<50;t+=10){for(let r=0;r<10;r++)n[r]=e[t+r];for(let r=0;r<10;r++)e[t+r]^=~n[(r+2)%10]&n[(r+4)%10]}e[0]^=ng[r],e[1]^=rg[r]}r(n)}var sg=class e extends ae{constructor(e,t,n,r=!1,i=24){if(super(),this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,this.enableXOF=!1,this.blockLen=e,this.suffix=t,this.outputLen=n,this.enableXOF=r,this.rounds=i,m(n),!(0=r&&this.keccak();let a=Math.min(r-this.posOut,i-n);e.set(t.subarray(this.posOut,this.posOut+a),n),this.posOut+=a,n+=a}return e}xofInto(e){if(!this.enableXOF)throw Error(`XOF is not possible for this instance`);return this.writeInto(e)}xof(e){return m(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(i(e,this),this.finished)throw Error(`digest() was already called`);return this.writeInto(e),this.destroy(),e}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,r(this.state)}_cloneInto(t){let{blockLen:n,suffix:r,outputLen:i,rounds:a,enableXOF:o}=this;return t||=new e(n,r,i,o,a),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=a,t.suffix=r,t.outputLen=i,t.enableXOF=o,t.destroyed=this.destroyed,t}},cg=(e,t,n)=>E(()=>new sg(t,e,n));cg(6,144,224/8),cg(6,136,256/8),cg(6,104,384/8),cg(6,72,512/8),cg(1,144,224/8);var lg=cg(1,136,256/8);cg(1,104,384/8),cg(1,72,512/8);var ug=(e,t,n)=>T((r={})=>new sg(t,e,r.dkLen===void 0?n:r.dkLen,!0));ug(31,168,128/8),ug(31,136,256/8);function dg(e,t){let n=t||`hex`,r=lg(Vm(e,{strict:!1})?zh(e):e);return n===`bytes`?r:Nh(r)}var fg=e=>dg(zh(e));function pg(e){return fg(e)}function mg(e){let t=!0,n=``,r=0,i=``,a=!1;for(let o=0;omg(typeof e==`string`?e:Ip(e));function gg(e){return pg(hg(e))}var _g=gg,vg=class extends q{constructor({address:e}){super(`Address "${e}" is invalid.`,{metaMessages:[`- Address must be a hex value of 20 bytes (40 hex characters).`,`- Address must match its checksum counterpart.`],name:`InvalidAddressError`})}},yg=class extends Map{constructor(e){super(),Object.defineProperty(this,`maxSize`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&(super.delete(e),super.set(e,t)),t}set(e,t){if(super.has(e)&&super.delete(e),super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=super.keys().next().value;e!==void 0&&super.delete(e)}return this}},bg=new yg(8192);function xg(e,t){if(bg.has(`${e}.${t}`))return bg.get(`${e}.${t}`);let n=t?`${t}${e.toLowerCase()}`:e.substring(2).toLowerCase(),r=dg(Gh(n),`bytes`),i=(t?n.substring(`${t}0x`.length):n).split(``);for(let e=0;e<40;e+=2)r[e>>1]>>4>=8&&i[e]&&(i[e]=i[e].toUpperCase()),(r[e>>1]&15)>=8&&i[e+1]&&(i[e+1]=i[e+1].toUpperCase());let a=`0x${i.join(``)}`;return bg.set(`${e}.${t}`,a),a}function Sg(e,t){if(!Tg(e,{strict:!1}))throw new vg({address:e});return xg(e,t)}var Cg=/^0x[a-fA-F0-9]{40}$/,wg=new yg(8192);function Tg(e,t){let{strict:n=!0}=t??{},r=`${e}.${n}`;if(wg.has(r))return wg.get(r);let i=Cg.test(e)?e.toLowerCase()===e?!0:n?xg(e)===e:!0:!1;return wg.set(r,i),i}function Eg(e){return typeof e[0]==`string`?Og(e):Dg(e)}function Dg(e){let t=0;for(let n of e)t+=n.length;let n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.length;return n}function Og(e){return`0x${e.reduce((e,t)=>e+t.replace(`0x`,``),``)}`}function kg(e,t,n,{strict:r}={}){return Vm(e,{strict:!1})?Ng(e,t,n,{strict:r}):Mg(e,t,n,{strict:r})}function Ag(e,t){if(typeof t==`number`&&t>0&&t>Hm(e)-1)throw new _h({offset:t,position:`start`,size:Hm(e)})}function jg(e,t,n){if(typeof t==`number`&&typeof n==`number`&&Hm(e)!==n-t)throw new _h({offset:n,position:`end`,size:Hm(e)})}function Mg(e,t,n,{strict:r}={}){Ag(e,t);let i=e.slice(t,n);return r&&jg(i,t,n),i}function Ng(e,t,n,{strict:r}={}){Ag(e,t);let i=`0x${e.replace(`0x`,``).slice((t??0)*2,(n??e.length)*2)}`;return r&&jg(i,t,n),i}var Pg=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,Fg=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;function Ig(e,t){if(e.length!==t.length)throw new Qm({expectedLength:e.length,givenLength:t.length});let n=zg(Lg({params:e,values:t}));return n.length===0?`0x`:n}function Lg({params:e,values:t}){let n=[];for(let r=0;r0?Eg([t,e]):t}}if(i)return{dynamic:!0,encoded:e}}return{dynamic:!1,encoded:Eg(a.map(({encoded:e})=>e))}}function Hg(e,{param:t}){let[,n]=t.type.split(`bytes`),r=Hm(e);if(!n){let t=e;return r%32!=0&&(t=xh(t,{dir:`right`,size:Math.ceil((e.length-2)/2/32)*32})),{dynamic:!0,encoded:Eg([xh(J(r,{size:32})),t])}}if(r!==Number.parseInt(n,10))throw new Zm({expectedSize:Number.parseInt(n,10),value:e});return{dynamic:!1,encoded:xh(e,{dir:`right`})}}function Ug(e){if(typeof e!=`boolean`)throw new q(`Invalid boolean value: "${e}" (type: ${typeof e}). Expected: \`true\` or \`false\`.`);return{dynamic:!1,encoded:xh(Ph(e))}}function Wg(e,{signed:t,size:n=256}){if(typeof n==`number`){let r=2n**(BigInt(n)-(t?1n:0n))-1n,i=t?-r-1n:0n;if(e>r||ee))}}function qg(e){let t=e.match(/^(.*)\[(\d+)?\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}var Jg=e=>kg(gg(e),0,4);function Yg(e){let{abi:t,args:n=[],name:r}=e,i=Vm(r,{strict:!1}),a=t.filter(e=>i?e.type===`function`?Jg(e)===r:e.type===`event`?_g(e)===r:!1:`name`in e&&e.name===r);if(a.length===0)return;if(a.length===1)return a[0];let o;for(let e of a)if(`inputs`in e){if(!n||n.length===0){if(!e.inputs||e.inputs.length===0)return e;continue}if(e.inputs&&e.inputs.length!==0&&e.inputs.length===n.length&&n.every((t,n)=>{let r=`inputs`in e&&e.inputs[n];return r?Xg(t,r):!1})){if(o&&`inputs`in o&&o.inputs){let t=Zg(e.inputs,o.inputs,n);if(t)throw new ch({abiItem:e,type:t[0]},{abiItem:o,type:t[1]})}o=e}}return o||a[0]}function Xg(e,t){let n=typeof e,r=t.type;switch(r){case`address`:return Tg(e,{strict:!1});case`bool`:return n===`boolean`;case`function`:return n===`string`;case`string`:return n===`string`;default:return r===`tuple`&&`components`in t?Object.values(t.components).every((t,r)=>n===`object`&&Xg(Object.values(e)[r],t)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(r)?n===`number`||n===`bigint`:/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(r)?n===`string`||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(r)?Array.isArray(e)&&e.every(e=>Xg(e,{...t,type:r.replace(/(\[[0-9]{0,}\])$/,``)})):!1}}function Zg(e,t,n){for(let r in e){let i=e[r],a=t[r];if(i.type===`tuple`&&a.type===`tuple`&&`components`in i&&`components`in a)return Zg(i.components,a.components,n[r]);let o=[i.type,a.type];if(o.includes(`address`)&&o.includes(`bytes20`)||(o.includes(`address`)&&o.includes(`string`)||o.includes(`address`)&&o.includes(`bytes`))&&Tg(n[r],{strict:!1}))return o}}var Qg=`/docs/contract/encodeEventTopics`;function $g(e){let{abi:t,eventName:n,args:r}=e,i=t[0];if(n){let e=Yg({abi:t,name:n});if(!e)throw new ih(n,{docsPath:Qg});i=e}if(i.type!==`event`)throw new ih(void 0,{docsPath:Qg});let a=_g(Rm(i)),o=[];if(r&&`inputs`in i){let e=i.inputs?.filter(e=>`indexed`in e&&e.indexed),t=Array.isArray(r)?r:Object.values(r).length>0?e?.map(e=>r[e.name])??[]:[];t.length>0&&(o=e?.map((e,n)=>Array.isArray(t[n])?t[n].map((r,i)=>e_({param:e,value:t[n][i]})):t[n]!==void 0&&t[n]!==null?e_({param:e,value:t[n]}):null)??[])}return[a,...o]}function e_({param:e,value:t}){if(e.type===`string`||e.type===`bytes`)return dg(zh(t));if(e.type===`tuple`||e.type.match(/^(.*)\[(\d+)?\]$/))throw new gh(e.type);return Ig([e],[t])}function t_(e,{method:t}){let n={};return e.transport.type===`fallback`&&e.transport.onResponse?.(({method:e,response:r,status:i,transport:a})=>{i===`success`&&t===e&&(n[r]=a.request)}),(t=>n[t]||e.request)}async function n_(e,t){let{address:n,abi:r,args:i,eventName:a,fromBlock:o,strict:s,toBlock:c}=t,l=t_(e,{method:`eth_newFilter`}),u=a?$g({abi:r,args:i,eventName:a}):void 0,d=await e.request({method:`eth_newFilter`,params:[{address:n,fromBlock:typeof o==`bigint`?J(o):o,toBlock:typeof c==`bigint`?J(c):c,topics:u}]});return{abi:r,args:i,eventName:a,id:d,request:l(d),strict:!!s,type:`event`}}function r_(e){return typeof e==`string`?{address:e,type:`json-rpc`}:e}var i_=`/docs/contract/encodeFunctionData`;function a_(e){let{abi:t,args:n,functionName:r}=e,i=t[0];if(r){let e=Yg({abi:t,args:n,name:r});if(!e)throw new ah(r,{docsPath:i_});i=e}if(i.type!==`function`)throw new ah(void 0,{docsPath:i_});return{abi:[i],functionName:Jg(Rm(i))}}function o_(e){let{args:t}=e,{abi:n,functionName:r}=e.abi.length===1&&e.functionName?.startsWith(`0x`)?e:a_(e),i=n[0];return Og([r,(`inputs`in i&&i.inputs?Ig(i.inputs,t??[]):void 0)??`0x`])}var s_={1:"An `assert` condition failed.",17:`Arithmetic operation resulted in underflow or overflow.`,18:"Division or modulo by zero (e.g. `5 / 0` or `23 % 0`).",33:`Attempted to convert to an invalid type.`,34:`Attempted to access a storage byte array that is incorrectly encoded.`,49:"Performed `.pop()` on an empty array",50:`Array index is out of bounds.`,65:`Allocated too much memory or created an array which is too large.`,81:`Attempted to call a zero-initialized variable of internal function type.`},c_={inputs:[{name:`message`,type:`string`}],name:`Error`,type:`error`},l_={inputs:[{name:`reason`,type:`uint256`}],name:`Panic`,type:`error`},u_=class extends q{constructor({offset:e}){super(`Offset \`${e}\` cannot be negative.`,{name:`NegativeOffsetError`})}},d_=class extends q{constructor({length:e,position:t}){super(`Position \`${t}\` is out of bounds (\`0 < position < ${e}\`).`,{name:`PositionOutOfBoundsError`})}},f_=class extends q{constructor({count:e,limit:t}){super(`Recursive read limit of \`${t}\` exceeded (recursive read count: \`${e}\`).`,{name:`RecursiveReadLimitExceededError`})}},p_={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:1/0,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new f_({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new d_({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new u_({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new u_({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let n=t??this.position;return this.assertPosition(n+e-1),this.bytes.subarray(n,n+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let n=this.inspectBytes(e);return this.position+=t??e,n},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===1/0)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}};function m_(e,{recursiveReadLimit:t=8192}={}){let n=Object.create(p_);return n.bytes=e,n.dataView=new DataView(e.buffer??e,e.byteOffset,e.byteLength),n.positionReadCount=new Map,n.recursiveReadLimit=t,n}function h_(e,t={}){return t.size!==void 0&&Oh(e,{size:t.size}),kh(Fh(e,t),t)}function g_(e,t={}){let n=e;if(t.size!==void 0&&(Oh(n,{size:t.size}),n=Dh(n)),n.length>1||n[0]>1)throw new wh(n);return!!n[0]}function __(e,t={}){return t.size!==void 0&&Oh(e,{size:t.size}),jh(Fh(e,t),t)}function v_(e,t={}){let n=e;return t.size!==void 0&&(Oh(n,{size:t.size}),n=Dh(n,{dir:`right`})),new TextDecoder().decode(n)}function y_(e,t){let n=typeof t==`string`?Uh(t):t,r=m_(n);if(Hm(n)===0&&e.length>0)throw new Ym;if(Hm(t)&&Hm(t)<32)throw new Jm({data:typeof t==`string`?t:Fh(t),params:e,size:Hm(t)});let i=0,a=[];for(let t=0;t48?h_(i,{signed:n}):__(i,{signed:n}),32]}function O_(e,t,{staticPosition:n}){let r=t.components.length===0||t.components.some(({name:e})=>!e),i=r?[]:{},a=0;if(A_(t)){let o=n+__(e.readBytes(S_));for(let n=0;ne.type===`error`&&i===Jg(Rm(e)));if(!a)throw new th(i,{docsPath:`/docs/contract/decodeErrorResult`,cause:r});return{abiItem:a,args:`inputs`in a&&a.inputs&&a.inputs.length>0?y_(a.inputs,kg(n,4)):void 0,errorName:a.name}}var M_=(e,t,n)=>JSON.stringify(e,(e,n)=>{let r=typeof n==`bigint`?n.toString():n;return typeof t==`function`?t(e,r):r},n);function N_({abiItem:e,args:t,includeFunctionName:n=!0,includeName:r=!1}){if(`name`in e&&`inputs`in e&&e.inputs)return`${n?e.name:``}(${e.inputs.map((e,n)=>`${r&&e.name?`${e.name}: `:``}${typeof t[n]==`object`?M_(t[n]):t[n]}`).join(`, `)})`}var P_={gwei:9,wei:18},F_={ether:-9,wei:9};function I_(e,t){let n=e.toString(),r=n.startsWith(`-`);r&&(n=n.slice(1)),n=n.padStart(t,`0`);let[i,a]=[n.slice(0,n.length-t),n.slice(n.length-t)];return a=a.replace(/(0+)$/,``),`${r?`-`:``}${i||`0`}${a?`.${a}`:``}`}function L_(e,t=`wei`){return I_(e,P_[t])}function R_(e,t=`wei`){return I_(e,F_[t])}var z_=class extends q{constructor({address:e}){super(`State for account "${e}" is set multiple times.`,{name:`AccountStateConflictError`})}},B_=class extends q{constructor(){super(`state and stateDiff are set on the same account.`,{name:`StateAssignmentConflictError`})}};function V_(e){return e.reduce((e,{slot:t,value:n})=>`${e} ${t}: ${n}\n`,``)}function H_(e){return e.reduce((e,{address:t,...n})=>{let r=`${e} ${t}:\n`;return n.nonce&&(r+=` nonce: ${n.nonce}\n`),n.balance&&(r+=` balance: ${n.balance}\n`),n.code&&(r+=` code: ${n.code}\n`),n.state&&(r+=` state: +`,r+=V_(n.state)),n.stateDiff&&(r+=` stateDiff: +`,r+=V_(n.stateDiff)),r},` State Override: +`).slice(0,-1)}function U_(e){let t=Object.entries(e).map(([e,t])=>t===void 0||t===!1?null:[e,t]).filter(Boolean),n=t.reduce((e,[t])=>Math.max(e,t.length),0);return t.map(([e,t])=>` ${`${e}:`.padEnd(n+1)} ${t}`).join(` +`)}var W_=class extends q{constructor({transaction:e}){super(`Cannot infer a transaction type from provided transaction.`,{metaMessages:[`Provided Transaction:`,`{`,U_(e),`}`,``,`To infer the type, either provide:`,"- a `type` to the Transaction, or","- an EIP-1559 Transaction with `maxFeePerGas`, or","- an EIP-2930 Transaction with `gasPrice` & `accessList`, or","- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or","- an EIP-7702 Transaction with `authorizationList`, or","- a Legacy Transaction with `gasPrice`"],name:`InvalidSerializableTransactionError`})}},G_=class extends q{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d}){let f=U_({chain:r&&`${r?.name} (id: ${r?.id})`,from:t?.address,to:u,value:d!==void 0&&`${L_(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${R_(o)} gwei`,maxFeePerGas:s!==void 0&&`${R_(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${R_(c)} gwei`,nonce:l});super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Request Arguments:`,f].filter(Boolean),name:`TransactionExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},K_=class extends q{constructor({blockHash:e,blockNumber:t,blockTag:n,hash:r,index:i}){let a=`Transaction`;n&&i!==void 0&&(a=`Transaction at block time "${n}" at index "${i}"`),e&&i!==void 0&&(a=`Transaction at block hash "${e}" at index "${i}"`),t&&i!==void 0&&(a=`Transaction at block number "${t}" at index "${i}"`),r&&(a=`Transaction with hash "${r}"`),super(`${a} could not be found.`,{name:`TransactionNotFoundError`})}},q_=class extends q{constructor({hash:e}){super(`Transaction receipt with hash "${e}" could not be found. The Transaction may not be processed on a block yet.`,{name:`TransactionReceiptNotFoundError`})}},J_=class extends q{constructor({receipt:e}){super(`Transaction with hash "${e.transactionHash}" reverted.`,{metaMessages:[`The receipt marked the transaction as "reverted". This could mean that the function on the contract you are trying to call threw an error.`,` `,`You can attempt to extract the revert reason by:`,"- calling the `simulateContract` or `simulateCalls` Action with the `abi` and `functionName` of the contract","- using the `call` Action with raw `data`"],name:`TransactionReceiptRevertedError`}),Object.defineProperty(this,`receipt`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.receipt=e}},Y_=class extends q{constructor({hash:e}){super(`Timed out while waiting for transaction with hash "${e}" to be confirmed.`,{name:`WaitForTransactionReceiptTimeoutError`})}},X_=e=>e,Z_=e=>e,Q_=class extends q{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d,stateOverride:f}){let p=U_({from:(t?r_(t):void 0)?.address,to:u,value:d!==void 0&&`${L_(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${R_(o)} gwei`,maxFeePerGas:s!==void 0&&`${R_(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${R_(c)} gwei`,nonce:l});f&&(p+=`\n${H_(f)}`),super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Raw Call Arguments:`,p].filter(Boolean),name:`CallExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},$_=class extends q{constructor(e,{abi:t,args:n,contractAddress:r,docsPath:i,functionName:a,sender:o}){let s=Yg({abi:t,args:n,name:a}),c=s?N_({abiItem:s,args:n,includeFunctionName:!1,includeName:!1}):void 0,l=s?Rm(s,{includeName:!0}):void 0,u=U_({address:r&&X_(r),function:l,args:c&&c!==`()`&&`${[...Array(a?.length??0).keys()].map(()=>` `).join(``)}${c}`,sender:o});super(e.shortMessage||`An unknown error occurred while executing the contract function "${a}".`,{cause:e,docsPath:i,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],u&&`Contract Call:`,u].filter(Boolean),name:`ContractFunctionExecutionError`}),Object.defineProperty(this,`abi`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`args`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`contractAddress`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`formattedArgs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`functionName`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`sender`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abi=t,this.args=n,this.cause=e,this.contractAddress=r,this.functionName=a,this.sender=o}},ev=class extends q{constructor({abi:e,data:t,functionName:n,message:r,cause:i}){let a,o,s,c;if(t&&t!==`0x`)try{o=j_({abi:e,data:t,cause:i});let{abiItem:n,errorName:r,args:a}=o;if(r===`Error`)c=a[0];else if(r===`Panic`){let[e]=a;c=s_[e]}else{let e=n?Rm(n,{includeName:!0}):void 0,t=n&&a?N_({abiItem:n,args:a,includeFunctionName:!1,includeName:!1}):void 0;s=[e?`Error: ${e}`:``,t&&t!==`()`?` ${[...Array(r?.length??0).keys()].map(()=>` `).join(``)}${t}`:``]}}catch(e){a=e}else r&&(c=r);let l;a instanceof th&&(l=a.signature,s=[`Unable to decode signature "${l}" as it was not found on the provided ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`,`You can look up the decoded signature here: https://4byte.sourcify.dev/?q=${l}.`]),super(c&&c!==`execution reverted`||l?[`The contract function "${n}" reverted with the following ${l?`signature`:`reason`}:`,c||l].join(` +`):`The contract function "${n}" reverted.`,{cause:a??i,metaMessages:s,name:`ContractFunctionRevertedError`}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`raw`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`reason`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`signature`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=o,this.raw=t,this.reason=c,this.signature=l}},tv=class extends q{constructor({functionName:e,cause:t}){super(`The contract function "${e}" returned no data ("0x").`,{metaMessages:[`This could be due to any of the following:`,` - The contract does not have the function "${e}",`,` - The parameters passed to the contract function may be invalid, or`,` - The address is not a contract.`],name:`ContractFunctionZeroDataError`,cause:t})}},nv=class extends q{constructor({factory:e}){super(`Deployment for counterfactual contract call failed${e?` for factory "${e}".`:``}`,{metaMessages:[`Please ensure:`,"- The `factory` is a valid contract deployment factory (ie. Create2 Factory, ERC-4337 Factory, etc).","- The `factoryData` is a valid encoded function call for contract deployment function on the factory."],name:`CounterfactualDeploymentFailedError`})}},rv=class extends q{constructor({data:e,message:t}){super(t||``,{name:`RawContractError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=e}},iv=class extends q{constructor({body:e,cause:t,details:n,headers:r,status:i,url:a}){super(`HTTP request failed.`,{cause:t,details:n,metaMessages:[i&&`Status: ${i}`,`URL: ${Z_(a)}`,e&&`Request body: ${M_(e)}`].filter(Boolean),name:`HttpRequestError`}),Object.defineProperty(this,`body`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`headers`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`status`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.body=e,this.headers=r,this.status=i,this.url=a}},av=class extends q{constructor({body:e,error:t,url:n}){super(`RPC Request failed.`,{cause:t,details:t.message,metaMessages:[`URL: ${Z_(n)}`,`Request body: ${M_(e)}`],name:`RpcRequestError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.code=t.code,this.data=t.data,this.url=n}},ov=class extends q{constructor({body:e,url:t}){super(`The request took too long to respond.`,{details:`The request timed out.`,metaMessages:[`URL: ${Z_(t)}`,`Request body: ${M_(e)}`],name:`TimeoutError`}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.url=t}},sv=-1,cv=class extends q{constructor(e,{code:t,docsPath:n,metaMessages:r,name:i,shortMessage:a}){super(a,{cause:e,docsPath:n,metaMessages:r||e?.metaMessages,name:i||`RpcError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name=i||e.name,this.code=e instanceof av?e.code:t??sv}},lv=class extends cv{constructor(e,t){super(e,t),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=t.data}},uv=class e extends cv{constructor(t){super(t,{code:e.code,name:`ParseRpcError`,shortMessage:`Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.`})}};Object.defineProperty(uv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32700});var dv=class e extends cv{constructor(t){super(t,{code:e.code,name:`InvalidRequestRpcError`,shortMessage:`JSON is not a valid request object.`})}};Object.defineProperty(dv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32600});var fv=class e extends cv{constructor(t,{method:n}={}){super(t,{code:e.code,name:`MethodNotFoundRpcError`,shortMessage:`The method${n?` "${n}"`:``} does not exist / is not available.`})}};Object.defineProperty(fv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32601});var pv=class e extends cv{constructor(t){super(t,{code:e.code,name:`InvalidParamsRpcError`,shortMessage:[`Invalid parameters were provided to the RPC method.`,`Double check you have provided the correct parameters.`].join(` +`)})}};Object.defineProperty(pv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32602});var mv=class e extends cv{constructor(t){super(t,{code:e.code,name:`InternalRpcError`,shortMessage:`An internal error was received.`})}};Object.defineProperty(mv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32603});var hv=class e extends cv{constructor(t){super(t,{code:e.code,name:`InvalidInputRpcError`,shortMessage:[`Missing or invalid parameters.`,`Double check you have provided the correct parameters.`].join(` +`)})}};Object.defineProperty(hv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32e3});var gv=class e extends cv{constructor(t){super(t,{code:e.code,name:`ResourceNotFoundRpcError`,shortMessage:`Requested resource not found.`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`ResourceNotFoundRpcError`})}};Object.defineProperty(gv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32001});var _v=class e extends cv{constructor(t){super(t,{code:e.code,name:`ResourceUnavailableRpcError`,shortMessage:`Requested resource not available.`})}};Object.defineProperty(_v,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32002});var vv=class e extends cv{constructor(t){super(t,{code:e.code,name:`TransactionRejectedRpcError`,shortMessage:`Transaction creation failed.`})}};Object.defineProperty(vv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32003});var yv=class e extends cv{constructor(t,{method:n}={}){super(t,{code:e.code,name:`MethodNotSupportedRpcError`,shortMessage:`Method${n?` "${n}"`:``} is not supported.`})}};Object.defineProperty(yv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32004});var bv=class e extends cv{constructor(t){super(t,{code:e.code,name:`LimitExceededRpcError`,shortMessage:`Request exceeds defined limit.`})}};Object.defineProperty(bv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32005});var xv=class e extends cv{constructor(t){super(t,{code:e.code,name:`JsonRpcVersionUnsupportedError`,shortMessage:`Version of JSON-RPC protocol is not supported.`})}};Object.defineProperty(xv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32006});var Sv=class e extends lv{constructor(t){super(t,{code:e.code,name:`UserRejectedRequestError`,shortMessage:`User rejected the request.`})}};Object.defineProperty(Sv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4001});var Cv=class e extends lv{constructor(t){super(t,{code:e.code,name:`UnauthorizedProviderError`,shortMessage:`The requested method and/or account has not been authorized by the user.`})}};Object.defineProperty(Cv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4100});var wv=class e extends lv{constructor(t,{method:n}={}){super(t,{code:e.code,name:`UnsupportedProviderMethodError`,shortMessage:`The Provider does not support the requested method${n?` " ${n}"`:``}.`})}};Object.defineProperty(wv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4200});var Tv=class e extends lv{constructor(t){super(t,{code:e.code,name:`ProviderDisconnectedError`,shortMessage:`The Provider is disconnected from all chains.`})}};Object.defineProperty(Tv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4900});var Ev=class e extends lv{constructor(t){super(t,{code:e.code,name:`ChainDisconnectedError`,shortMessage:`The Provider is not connected to the requested chain.`})}};Object.defineProperty(Ev,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4901});var Dv=class e extends lv{constructor(t){super(t,{code:e.code,name:`SwitchChainError`,shortMessage:`An error occurred when attempting to switch chain.`})}};Object.defineProperty(Dv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4902});var Ov=class e extends lv{constructor(t){super(t,{code:e.code,name:`UnsupportedNonOptionalCapabilityError`,shortMessage:`This Wallet does not support a capability that was not marked as optional.`})}};Object.defineProperty(Ov,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5700});var kv=class e extends lv{constructor(t){super(t,{code:e.code,name:`UnsupportedChainIdError`,shortMessage:`This Wallet does not support the requested chain ID.`})}};Object.defineProperty(kv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5710});var Av=class e extends lv{constructor(t){super(t,{code:e.code,name:`DuplicateIdError`,shortMessage:`There is already a bundle submitted with this ID.`})}};Object.defineProperty(Av,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5720});var jv=class e extends lv{constructor(t){super(t,{code:e.code,name:`UnknownBundleIdError`,shortMessage:`This bundle id is unknown / has not been submitted`})}};Object.defineProperty(jv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5730});var Mv=class e extends lv{constructor(t){super(t,{code:e.code,name:`BundleTooLargeError`,shortMessage:`The call bundle is too large for the Wallet to process.`})}};Object.defineProperty(Mv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5740});var Nv=class e extends lv{constructor(t){super(t,{code:e.code,name:`AtomicReadyWalletRejectedUpgradeError`,shortMessage:`The Wallet can support atomicity after an upgrade, but the user rejected the upgrade.`})}};Object.defineProperty(Nv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5750});var Pv=class e extends lv{constructor(t){super(t,{code:e.code,name:`AtomicityNotSupportedError`,shortMessage:`The wallet does not support atomic execution but the request requires it.`})}};Object.defineProperty(Pv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5760});var Fv=class e extends lv{constructor(t){super(t,{code:e.code,name:`WalletConnectSessionSettlementError`,shortMessage:`WalletConnect session settlement failed.`})}};Object.defineProperty(Fv,`code`,{enumerable:!0,configurable:!0,writable:!0,value:7e3});var Iv=class extends cv{constructor(e){super(e,{name:`UnknownRpcError`,shortMessage:`An unknown RPC error occurred.`})}},Lv=3;function Rv(e,{abi:t,address:n,args:r,docsPath:i,functionName:a,sender:o}){let s=e instanceof rv?e:e instanceof q?e.walk(e=>`data`in e)||e.walk():{},{code:c,data:l,details:u,message:d,shortMessage:f}=s;return new $_(e instanceof Ym?new tv({functionName:a,cause:e}):[Lv,mv.code].includes(c)&&(l||u||d||f)||c===hv.code&&u===`execution reverted`&&l?new ev({abi:t,data:typeof l==`object`?l.data:l,functionName:a,message:s instanceof av?u:f??d,cause:e}):e,{abi:t,args:r,contractAddress:n,docsPath:i,functionName:a,sender:o})}function zv(e){return xg(`0x${dg(`0x${e.substring(4)}`).substring(26)}`)}var Bv=`modulepreload`,Vv=function(e){return`/`+e},Hv={},Uv=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}r=o(t.map(t=>{if(t=Vv(t,n),t in Hv)return;Hv[t]=!0;let r=t.endsWith(`.css`),i=r?`[rel="stylesheet"]`:``;if(n)for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}else if(document.querySelector(`link[href="${t}"]${i}`))return;let o=document.createElement(`link`);if(o.rel=r?`stylesheet`:Bv,r||(o.as=`script`),o.crossOrigin=``,o.href=t,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),r)return new Promise((e,n)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};async function Wv({hash:e,signature:t}){let n=Vm(e)?e:Nh(e),{secp256k1:r}=await Uv(async()=>{let{secp256k1:e}=await Promise.resolve().then(()=>qD);return{secp256k1:e}},void 0);return`0x${(()=>{if(typeof t==`object`&&`r`in t&&`s`in t){let{r:e,s:n,v:i,yParity:a}=t,o=Gv(Number(a??i));return new r.Signature(kh(e),kh(n)).addRecoveryBit(o)}let e=Vm(t)?t:Nh(t);if(Hm(e)!==65)throw Error(`invalid signature length`);let n=Gv(jh(`0x${e.slice(130)}`));return r.Signature.fromCompact(e.substring(2,130)).addRecoveryBit(n)})().recoverPublicKey(n.substring(2)).toHex(!1)}`}function Gv(e){if(e===0||e===1)return e;if(e===27)return 0;if(e===28)return 1;throw Error(`Invalid yParityOrV value`)}async function Kv({hash:e,signature:t}){return zv(await Wv({hash:e,signature:t}))}function qv(e,t=`hex`){let n=Jv(e),r=m_(new Uint8Array(n.length));return n.encode(r),t===`hex`?Fh(r.bytes):r.bytes}function Jv(e){return Array.isArray(e)?Yv(e.map(e=>Jv(e))):Xv(e)}function Yv(e){let t=e.reduce((e,t)=>e+t.length,0),n=Zv(t);return{length:t<=55?1+t:1+n+t,encode(r){t<=55?r.pushByte(192+t):(r.pushByte(247+n),n===1?r.pushUint8(t):n===2?r.pushUint16(t):n===3?r.pushUint24(t):r.pushUint32(t));for(let{encode:t}of e)t(r)}}}function Xv(e){let t=typeof e==`string`?Uh(e):e,n=Zv(t.length);return{length:t.length===1&&t[0]<128?1:t.length<=55?1+t.length:1+n+t.length,encode(e){t.length===1&&t[0]<128?e.pushBytes(t):t.length<=55?(e.pushByte(128+t.length),e.pushBytes(t)):(e.pushByte(183+n),n===1?e.pushUint8(t.length):n===2?e.pushUint16(t.length):n===3?e.pushUint24(t.length):e.pushUint32(t.length),e.pushBytes(t))}}}function Zv(e){if(e<2**8)return 1;if(e<2**16)return 2;if(e<2**24)return 3;if(e<2**32)return 4;throw new q(`Length is too large.`)}function Qv(e){let{chainId:t,nonce:n,to:r}=e,i=e.contractAddress??e.address,a=dg(Og([`0x05`,qv([t?J(t):`0x`,i,n?J(n):`0x`])]));return r===`bytes`?Uh(a):a}async function $v(e){let{authorization:t,signature:n}=e;return Kv({hash:Qv(t),signature:n??t})}var ey=class extends q{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d}){let f=U_({from:t?.address,to:u,value:d!==void 0&&`${L_(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${R_(o)} gwei`,maxFeePerGas:s!==void 0&&`${R_(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${R_(c)} gwei`,nonce:l});super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Estimate Gas Arguments:`,f].filter(Boolean),name:`EstimateGasExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},ty=class extends q{constructor({cause:e,message:t}={}){let n=t?.replace(`execution reverted: `,``)?.replace(`execution reverted`,``);super(`Execution reverted ${n?`with reason: ${n}`:`for an unknown reason`}.`,{cause:e,name:`ExecutionRevertedError`})}};Object.defineProperty(ty,`code`,{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(ty,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/execution reverted|gas required exceeds allowance/});var ny=class extends q{constructor({cause:e,maxFeePerGas:t}={}){super(`The fee cap (\`maxFeePerGas\`${t?` = ${R_(t)} gwei`:``}) cannot be higher than the maximum allowed value (2^256-1).`,{cause:e,name:`FeeCapTooHighError`})}};Object.defineProperty(ny,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/});var ry=class extends q{constructor({cause:e,maxFeePerGas:t}={}){super(`The fee cap (\`maxFeePerGas\`${t?` = ${R_(t)}`:``} gwei) cannot be lower than the block base fee.`,{cause:e,name:`FeeCapTooLowError`})}};Object.defineProperty(ry,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/});var iy=class extends q{constructor({cause:e,nonce:t}={}){super(`Nonce provided for the transaction ${t?`(${t}) `:``}is higher than the next one expected.`,{cause:e,name:`NonceTooHighError`})}};Object.defineProperty(iy,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce too high/});var ay=class extends q{constructor({cause:e,nonce:t}={}){super([`Nonce provided for the transaction ${t?`(${t}) `:``}is lower than the current nonce of the account.`,"Try increasing the nonce or find the latest nonce with `getTransactionCount`."].join(` +`),{cause:e,name:`NonceTooLowError`})}};Object.defineProperty(ay,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce too low|transaction already imported|already known/});var oy=class extends q{constructor({cause:e,nonce:t}={}){super(`Nonce provided for the transaction ${t?`(${t}) `:``}exceeds the maximum allowed nonce.`,{cause:e,name:`NonceMaxValueError`})}};Object.defineProperty(oy,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce has max value/});var sy=class extends q{constructor({cause:e}={}){super([`The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account.`].join(` +`),{cause:e,metaMessages:[`This error could arise when the account does not have enough funds to:`,` - pay for the total gas fee,`,` - pay for the value to send.`,` `,"The cost of the transaction is calculated as `gas * gas fee + value`, where:"," - `gas` is the amount of gas needed for transaction to execute,"," - `gas fee` is the gas fee,"," - `value` is the amount of ether to send to the recipient."],name:`InsufficientFundsError`})}};Object.defineProperty(sy,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/insufficient funds|exceeds transaction sender account balance/});var cy=class extends q{constructor({cause:e,gas:t}={}){super(`The amount of gas ${t?`(${t}) `:``}provided for the transaction exceeds the limit allowed for the block.`,{cause:e,name:`IntrinsicGasTooHighError`})}};Object.defineProperty(cy,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too high|gas limit reached/});var ly=class extends q{constructor({cause:e,gas:t}={}){super(`The amount of gas ${t?`(${t}) `:``}provided for the transaction is too low.`,{cause:e,name:`IntrinsicGasTooLowError`})}};Object.defineProperty(ly,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too low/});var uy=class extends q{constructor({cause:e}){super(`The transaction type is not supported for this chain.`,{cause:e,name:`TransactionTypeNotSupportedError`})}};Object.defineProperty(uy,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/transaction type not valid/});var dy=class extends q{constructor({cause:e,maxPriorityFeePerGas:t,maxFeePerGas:n}={}){super([`The provided tip (\`maxPriorityFeePerGas\`${t?` = ${R_(t)} gwei`:``}) cannot be higher than the fee cap (\`maxFeePerGas\`${n?` = ${R_(n)} gwei`:``}).`].join(` +`),{cause:e,name:`TipAboveFeeCapError`})}};Object.defineProperty(dy,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max priority fee per gas higher than max fee per gas|tip higher than fee cap/});var fy=class extends q{constructor({cause:e}){super(`An error occurred while executing: ${e?.shortMessage}`,{cause:e,name:`UnknownNodeError`})}};function py(e,t){let n=(e.details||``).toLowerCase(),r=e instanceof q?e.walk(e=>e?.code===ty.code):e;return r instanceof q?new ty({cause:e,message:r.details}):ty.nodeMessage.test(n)?new ty({cause:e,message:e.details}):ny.nodeMessage.test(n)?new ny({cause:e,maxFeePerGas:t?.maxFeePerGas}):ry.nodeMessage.test(n)?new ry({cause:e,maxFeePerGas:t?.maxFeePerGas}):iy.nodeMessage.test(n)?new iy({cause:e,nonce:t?.nonce}):ay.nodeMessage.test(n)?new ay({cause:e,nonce:t?.nonce}):oy.nodeMessage.test(n)?new oy({cause:e,nonce:t?.nonce}):sy.nodeMessage.test(n)?new sy({cause:e}):cy.nodeMessage.test(n)?new cy({cause:e,gas:t?.gas}):ly.nodeMessage.test(n)?new ly({cause:e,gas:t?.gas}):uy.nodeMessage.test(n)?new uy({cause:e}):dy.nodeMessage.test(n)?new dy({cause:e,maxFeePerGas:t?.maxFeePerGas,maxPriorityFeePerGas:t?.maxPriorityFeePerGas}):new fy({cause:e})}function my(e,{docsPath:t,...n}){return new ey((()=>{let t=py(e,n);return t instanceof fy?e:t})(),{docsPath:t,...n})}function hy(e,{format:t}){if(!t)return{};let n={};function r(t){let i=Object.keys(t);for(let a of i)a in e&&(n[a]=e[a]),t[a]&&typeof t[a]==`object`&&!Array.isArray(t[a])&&r(t[a])}return r(t(e||{})),n}var gy={legacy:`0x0`,eip2930:`0x1`,eip1559:`0x2`,eip4844:`0x3`,eip7702:`0x4`};function _y(e,t){let n={};return e.authorizationList!==void 0&&(n.authorizationList=vy(e.authorizationList)),e.accessList!==void 0&&(n.accessList=e.accessList),e.blobVersionedHashes!==void 0&&(n.blobVersionedHashes=e.blobVersionedHashes),e.blobs!==void 0&&(typeof e.blobs[0]==`string`?n.blobs=e.blobs:n.blobs=e.blobs.map(e=>Fh(e))),e.data!==void 0&&(n.data=e.data),e.account&&(n.from=e.account.address),e.from!==void 0&&(n.from=e.from),e.gas!==void 0&&(n.gas=J(e.gas)),e.gasPrice!==void 0&&(n.gasPrice=J(e.gasPrice)),e.maxFeePerBlobGas!==void 0&&(n.maxFeePerBlobGas=J(e.maxFeePerBlobGas)),e.maxFeePerGas!==void 0&&(n.maxFeePerGas=J(e.maxFeePerGas)),e.maxPriorityFeePerGas!==void 0&&(n.maxPriorityFeePerGas=J(e.maxPriorityFeePerGas)),e.nonce!==void 0&&(n.nonce=J(e.nonce)),e.to!==void 0&&(n.to=e.to),e.type!==void 0&&(n.type=gy[e.type]),e.value!==void 0&&(n.value=J(e.value)),n}function vy(e){return e.map(e=>({address:e.address,r:e.r?J(BigInt(e.r)):e.r,s:e.s?J(BigInt(e.s)):e.s,chainId:J(e.chainId),nonce:J(e.nonce),...e.yParity===void 0?{}:{yParity:J(e.yParity)},...e.v!==void 0&&e.yParity===void 0?{v:J(e.v)}:{}}))}function yy(e){if(!(!e||e.length===0))return e.reduce((e,{slot:t,value:n})=>{if(t.length!==66)throw new yh({size:t.length,targetSize:66,type:`hex`});if(n.length!==66)throw new yh({size:n.length,targetSize:66,type:`hex`});return e[t]=n,e},{})}function by(e){let{balance:t,nonce:n,state:r,stateDiff:i,code:a}=e,o={};if(a!==void 0&&(o.code=a),t!==void 0&&(o.balance=J(t)),n!==void 0&&(o.nonce=J(n)),r!==void 0&&(o.state=yy(r)),i!==void 0){if(o.state)throw new B_;o.stateDiff=yy(i)}return o}function xy(e){if(!e)return;let t={};for(let{address:n,...r}of e){if(!Tg(n,{strict:!1}))throw new vg({address:n});if(t[n])throw new z_({address:n});t[n]=by(r)}return t}2n**(8n-1n)-1n,2n**(16n-1n)-1n,2n**(24n-1n)-1n,2n**(32n-1n)-1n,2n**(40n-1n)-1n,2n**(48n-1n)-1n,2n**(56n-1n)-1n,2n**(64n-1n)-1n,2n**(72n-1n)-1n,2n**(80n-1n)-1n,2n**(88n-1n)-1n,2n**(96n-1n)-1n,2n**(104n-1n)-1n,2n**(112n-1n)-1n,2n**(120n-1n)-1n,2n**(128n-1n)-1n,2n**(136n-1n)-1n,2n**(144n-1n)-1n,2n**(152n-1n)-1n,2n**(160n-1n)-1n,2n**(168n-1n)-1n,2n**(176n-1n)-1n,2n**(184n-1n)-1n,2n**(192n-1n)-1n,2n**(200n-1n)-1n,2n**(208n-1n)-1n,2n**(216n-1n)-1n,2n**(224n-1n)-1n,2n**(232n-1n)-1n,2n**(240n-1n)-1n,2n**(248n-1n)-1n,2n**(256n-1n)-1n,-(2n**(8n-1n)),-(2n**(16n-1n)),-(2n**(24n-1n)),-(2n**(32n-1n)),-(2n**(40n-1n)),-(2n**(48n-1n)),-(2n**(56n-1n)),-(2n**(64n-1n)),-(2n**(72n-1n)),-(2n**(80n-1n)),-(2n**(88n-1n)),-(2n**(96n-1n)),-(2n**(104n-1n)),-(2n**(112n-1n)),-(2n**(120n-1n)),-(2n**(128n-1n)),-(2n**(136n-1n)),-(2n**(144n-1n)),-(2n**(152n-1n)),-(2n**(160n-1n)),-(2n**(168n-1n)),-(2n**(176n-1n)),-(2n**(184n-1n)),-(2n**(192n-1n)),-(2n**(200n-1n)),-(2n**(208n-1n)),-(2n**(216n-1n)),-(2n**(224n-1n)),-(2n**(232n-1n)),-(2n**(240n-1n)),-(2n**(248n-1n)),-(2n**(256n-1n));var Sy=2n**256n-1n;function Cy(e){let{account:t,maxFeePerGas:n,maxPriorityFeePerGas:r,to:i}=e,a=t?r_(t):void 0;if(a&&!Tg(a.address))throw new vg({address:a.address});if(i&&!Tg(i))throw new vg({address:i});if(n&&n>Sy)throw new ny({maxFeePerGas:n});if(r&&n&&r>n)throw new dy({maxFeePerGas:n,maxPriorityFeePerGas:r})}var wy=class extends q{constructor(){super("`baseFeeMultiplier` must be greater than 1.",{name:`BaseFeeScalarError`})}},Ty=class extends q{constructor(){super(`Chain does not support EIP-1559 fees.`,{name:`Eip1559FeesNotSupportedError`})}},Ey=class extends q{constructor({maxPriorityFeePerGas:e}){super(`\`maxFeePerGas\` cannot be less than the \`maxPriorityFeePerGas\` (${R_(e)} gwei).`,{name:`MaxFeePerGasTooLowError`})}},Dy=class extends q{constructor({blockHash:e,blockNumber:t}){let n=`Block`;e&&(n=`Block at hash "${e}"`),t&&(n=`Block at number "${t}"`),super(`${n} could not be found.`,{name:`BlockNotFoundError`})}},Oy={"0x0":`legacy`,"0x1":`eip2930`,"0x2":`eip1559`,"0x3":`eip4844`,"0x4":`eip7702`};function ky(e,t){let n={...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,chainId:e.chainId?jh(e.chainId):void 0,gas:e.gas?BigInt(e.gas):void 0,gasPrice:e.gasPrice?BigInt(e.gasPrice):void 0,maxFeePerBlobGas:e.maxFeePerBlobGas?BigInt(e.maxFeePerBlobGas):void 0,maxFeePerGas:e.maxFeePerGas?BigInt(e.maxFeePerGas):void 0,maxPriorityFeePerGas:e.maxPriorityFeePerGas?BigInt(e.maxPriorityFeePerGas):void 0,nonce:e.nonce?jh(e.nonce):void 0,to:e.to?e.to:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,type:e.type?Oy[e.type]:void 0,typeHex:e.type?e.type:void 0,value:e.value?BigInt(e.value):void 0,v:e.v?BigInt(e.v):void 0};return e.authorizationList&&(n.authorizationList=Ay(e.authorizationList)),n.yParity=(()=>{if(e.yParity)return Number(e.yParity);if(typeof n.v==`bigint`){if(n.v===0n||n.v===27n)return 0;if(n.v===1n||n.v===28n)return 1;if(n.v>=35n)return+(n.v%2n==0n)}})(),n.type===`legacy`&&(delete n.accessList,delete n.maxFeePerBlobGas,delete n.maxFeePerGas,delete n.maxPriorityFeePerGas,delete n.yParity),n.type===`eip2930`&&(delete n.maxFeePerBlobGas,delete n.maxFeePerGas,delete n.maxPriorityFeePerGas),n.type===`eip1559`&&delete n.maxFeePerBlobGas,n}function Ay(e){return e.map(e=>({address:e.address,chainId:Number(e.chainId),nonce:Number(e.nonce),r:e.r,s:e.s,yParity:Number(e.yParity)}))}function jy(e,t){let n=(e.transactions??[]).map(e=>typeof e==`string`?e:ky(e));return{...e,baseFeePerGas:e.baseFeePerGas?BigInt(e.baseFeePerGas):null,blobGasUsed:e.blobGasUsed?BigInt(e.blobGasUsed):void 0,difficulty:e.difficulty?BigInt(e.difficulty):void 0,excessBlobGas:e.excessBlobGas?BigInt(e.excessBlobGas):void 0,gasLimit:e.gasLimit?BigInt(e.gasLimit):void 0,gasUsed:e.gasUsed?BigInt(e.gasUsed):void 0,hash:e.hash?e.hash:null,logsBloom:e.logsBloom?e.logsBloom:null,nonce:e.nonce?e.nonce:null,number:e.number?BigInt(e.number):null,size:e.size?BigInt(e.size):void 0,timestamp:e.timestamp?BigInt(e.timestamp):void 0,transactions:n,totalDifficulty:e.totalDifficulty?BigInt(e.totalDifficulty):null}}async function My(e,{blockHash:t,blockNumber:n,blockTag:r=e.experimental_blockTag??`latest`,includeTransactions:i}={}){let a=i??!1,o=n===void 0?void 0:J(n),s=null;if(s=t?await e.request({method:`eth_getBlockByHash`,params:[t,a]},{dedupe:!0}):await e.request({method:`eth_getBlockByNumber`,params:[o||r,a]},{dedupe:!!o}),!s)throw new Dy({blockHash:t,blockNumber:n});return(e.chain?.formatters?.block?.format||jy)(s,`getBlock`)}async function Ny(e){let t=await e.request({method:`eth_gasPrice`});return BigInt(t)}async function Py(e,t){return Fy(e,t)}async function Fy(e,t){let{block:n,chain:r=e.chain,request:i}=t||{};try{let t=r?.fees?.maxPriorityFeePerGas??r?.fees?.defaultPriorityFee;if(typeof t==`function`){let r=await t({block:n||await K(e,My,`getBlock`)({}),client:e,request:i});if(r===null)throw Error();return r}return t===void 0?kh(await e.request({method:`eth_maxPriorityFeePerGas`})):t}catch{let[t,r]=await Promise.all([n?Promise.resolve(n):K(e,My,`getBlock`)({}),K(e,Ny,`getGasPrice`)({})]);if(typeof t.baseFeePerGas!=`bigint`)throw new Ty;let i=r-t.baseFeePerGas;return i<0n?0n:i}}async function Iy(e,t){return Ly(e,t)}async function Ly(e,t){let{block:n,chain:r=e.chain,request:i,type:a=`eip1559`}=t||{},o=await(async()=>typeof r?.fees?.baseFeeMultiplier==`function`?r.fees.baseFeeMultiplier({block:n,client:e,request:i}):r?.fees?.baseFeeMultiplier??1.2)();if(o<1)throw new wy;let s=10**(o.toString().split(`.`)[1]?.length??0),c=e=>e*BigInt(Math.ceil(o*s))/BigInt(s),l=n||await K(e,My,`getBlock`)({});if(typeof r?.fees?.estimateFeesPerGas==`function`){let t=await r.fees.estimateFeesPerGas({block:n,client:e,multiply:c,request:i,type:a});if(t!==null)return t}if(a===`eip1559`){if(typeof l.baseFeePerGas!=`bigint`)throw new Ty;let t=typeof i?.maxPriorityFeePerGas==`bigint`?i.maxPriorityFeePerGas:await Fy(e,{block:l,chain:r,request:i}),n=c(l.baseFeePerGas);return{maxFeePerGas:i?.maxFeePerGas??n+t,maxPriorityFeePerGas:t}}return{gasPrice:i?.gasPrice??c(await K(e,Ny,`getGasPrice`)({}))}}async function Ry(e,{address:t,blockTag:n=`latest`,blockNumber:r}){return jh(await e.request({method:`eth_getTransactionCount`,params:[t,typeof r==`bigint`?J(r):n]},{dedupe:!!r}))}function zy(e){let{kzg:t}=e,n=e.to??(typeof e.blobs[0]==`string`?`hex`:`bytes`),r=typeof e.blobs[0]==`string`?e.blobs.map(e=>Uh(e)):e.blobs,i=[];for(let e of r)i.push(Uint8Array.from(t.blobToKzgCommitment(e)));return n===`bytes`?i:i.map(e=>Fh(e))}function By(e){let{kzg:t}=e,n=e.to??(typeof e.blobs[0]==`string`?`hex`:`bytes`),r=typeof e.blobs[0]==`string`?e.blobs.map(e=>Uh(e)):e.blobs,i=typeof e.commitments[0]==`string`?e.commitments.map(e=>Uh(e)):e.commitments,a=[];for(let e=0;eFh(e))}function Vy(e,t,n,r){if(typeof e.setBigUint64==`function`)return e.setBigUint64(t,n,r);let i=BigInt(32),a=BigInt(4294967295),o=Number(n>>i&a),s=Number(n&a),c=r?4:0,l=r?0:4;e.setUint32(t+c,o,r),e.setUint32(t+l,s,r)}function Hy(e,t,n){return e&t^~e&n}function Uy(e,t,n){return e&t^e&n^t&n}var Wy=class extends ae{constructor(t,n,r,i){super(),this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.blockLen=t,this.outputLen=n,this.padOffset=r,this.isLE=i,this.buffer=new Uint8Array(t),this.view=e(this.buffer)}update(t){n(this),t=a(t),p(t);let{view:r,buffer:i,blockLen:o}=this,s=t.length;for(let n=0;ns-l&&(this.process(o,0),l=0);for(let e=l;ep.length)throw Error(`_sha2: outputLen bigger than state`);for(let e=0;e>>3;qy[e]=(l(n,17)^l(n,19)^n>>>10)+qy[e-7]+r+qy[e-16]|0}let{A:n,B:r,C:i,D:a,E:o,F:s,G:c,H:u}=this;for(let e=0;e<64;e++){let t=l(o,6)^l(o,11)^l(o,25),d=u+t+Hy(o,s,c)+Ky[e]+qy[e]|0,f=(l(n,2)^l(n,13)^l(n,22))+Uy(n,r,i)|0;u=c,c=s,s=o,o=a+d|0,a=i,i=r,r=n,n=d+f|0}n=n+this.A|0,r=r+this.B|0,i=i+this.C|0,a=a+this.D|0,o=o+this.E|0,s=s+this.F|0,c=c+this.G|0,u=u+this.H|0,this.set(n,r,i,a,o,s,c,u)}roundClean(){r(qy)}destroy(){this.set(0,0,0,0,0,0,0,0),r(this.buffer)}},Yy=h(`0x428a2f98d728ae22.0x7137449123ef65cd.0xb5c0fbcfec4d3b2f.0xe9b5dba58189dbbc.0x3956c25bf348b538.0x59f111f1b605d019.0x923f82a4af194f9b.0xab1c5ed5da6d8118.0xd807aa98a3030242.0x12835b0145706fbe.0x243185be4ee4b28c.0x550c7dc3d5ffb4e2.0x72be5d74f27b896f.0x80deb1fe3b1696b1.0x9bdc06a725c71235.0xc19bf174cf692694.0xe49b69c19ef14ad2.0xefbe4786384f25e3.0x0fc19dc68b8cd5b5.0x240ca1cc77ac9c65.0x2de92c6f592b0275.0x4a7484aa6ea6e483.0x5cb0a9dcbd41fbd4.0x76f988da831153b5.0x983e5152ee66dfab.0xa831c66d2db43210.0xb00327c898fb213f.0xbf597fc7beef0ee4.0xc6e00bf33da88fc2.0xd5a79147930aa725.0x06ca6351e003826f.0x142929670a0e6e70.0x27b70a8546d22ffc.0x2e1b21385c26c926.0x4d2c6dfc5ac42aed.0x53380d139d95b3df.0x650a73548baf63de.0x766a0abb3c77b2a8.0x81c2c92e47edaee6.0x92722c851482353b.0xa2bfe8a14cf10364.0xa81a664bbc423001.0xc24b8b70d0f89791.0xc76c51a30654be30.0xd192e819d6ef5218.0xd69906245565a910.0xf40e35855771202a.0x106aa07032bbd1b8.0x19a4c116b8d2d0c8.0x1e376c085141ab53.0x2748774cdf8eeb99.0x34b0bcb5e19b48a8.0x391c0cb3c5c95a63.0x4ed8aa4ae3418acb.0x5b9cca4f7763e373.0x682e6ff3d6b2b8a3.0x748f82ee5defb2fc.0x78a5636f43172f60.0x84c87814a1f0ab72.0x8cc702081a6439ec.0x90befffa23631e28.0xa4506cebde82bde9.0xbef9a3f7b2c67915.0xc67178f2e372532b.0xca273eceea26619c.0xd186b8c721c0c207.0xeada7dd6cde0eb1e.0xf57d4f7fee6ed178.0x06f067aa72176fba.0x0a637dc5a2c898a6.0x113f9804bef90dae.0x1b710b35131c471b.0x28db77f523047d84.0x32caab7b40c72493.0x3c9ebe0a15c9bebc.0x431d67c49c100d4c.0x4cc5d4becb3e42b6.0x597f299cfc657e2a.0x5fcb6fab3ad6faec.0x6c44198c4a475817`.split(`.`).map(e=>BigInt(e)));Yy[0],Yy[1];var Xy=E(()=>new Jy),Zy=Xy;function Qy(e,t){let n=t||`hex`,r=Zy(Vm(e,{strict:!1})?zh(e):e);return n===`bytes`?r:Nh(r)}function $y(e){let{commitment:t,version:n=1}=e,r=e.to??(typeof t==`string`?`hex`:`bytes`),i=Qy(t,`bytes`);return i.set([n],0),r===`bytes`?i:Fh(i)}function eb(e){let{commitments:t,version:n}=e,r=e.to??(typeof t[0]==`string`?`hex`:`bytes`),i=[];for(let e of t)i.push($y({commitment:e,to:r,version:n}));return i}var tb=6,nb=4096,rb=32*nb,ib=rb*tb-1-1*nb*tb,ab=class extends q{constructor({maxSize:e,size:t}){super(`Blob size is too large.`,{metaMessages:[`Max: ${e} bytes`,`Given: ${t} bytes`],name:`BlobSizeTooLargeError`})}},ob=class extends q{constructor(){super(`Blob data must not be empty.`,{name:`EmptyBlobError`})}};function sb(e){let t=e.to??(typeof e.data==`string`?`hex`:`bytes`),n=typeof e.data==`string`?Uh(e.data):e.data,r=Hm(n);if(!r)throw new ob;if(r>761855)throw new ab({maxSize:ib,size:r});let i=[],a=!0,o=0;for(;a;){let e=m_(new Uint8Array(rb)),t=0;for(;te.bytes):i.map(e=>Fh(e.bytes))}function cb(e){let{data:t,kzg:n,to:r}=e,i=e.blobs??sb({data:t,to:r}),a=e.commitments??zy({blobs:i,kzg:n,to:r}),o=e.proofs??By({blobs:i,commitments:a,kzg:n,to:r}),s=[];for(let e=0;e{let t=py(e,n);return t instanceof fy?e:t})(),{docsPath:t,...n})}async function db(e){return jh(await e.request({method:`eth_chainId`},{dedupe:!0}))}async function fb(e,t){let{account:n=e.account,accessList:r,authorizationList:i,chain:a=e.chain,blobVersionedHashes:o,blobs:s,data:c,gas:l,gasPrice:u,maxFeePerBlobGas:d,maxFeePerGas:f,maxPriorityFeePerGas:p,nonce:m,nonceManager:h,to:g,type:_,value:v,...y}=t,b=await(async()=>{if(!n||!h||m!==void 0)return m;let t=r_(n),r=a?a.id:await K(e,db,`getChainId`)({});return await h.consume({address:t.address,chainId:r,client:e})})();Cy(t);let x=a?.formatters?.transactionRequest?.format,S=(x||_y)({...hy(y,{format:x}),account:n?r_(n):void 0,accessList:r,authorizationList:i,blobs:s,blobVersionedHashes:o,data:c,gas:l,gasPrice:u,maxFeePerBlobGas:d,maxFeePerGas:f,maxPriorityFeePerGas:p,nonce:b,to:g,type:_,value:v},`fillTransaction`);try{let n=await e.request({method:`eth_fillTransaction`,params:[S]}),r=(a?.formatters?.transaction?.format||ky)(n.tx);delete r.blockHash,delete r.blockNumber,delete r.r,delete r.s,delete r.transactionIndex,delete r.v,delete r.yParity,r.data=r.input,r.gas&&=t.gas??r.gas,r.gasPrice&&=t.gasPrice??r.gasPrice,r.maxFeePerBlobGas&&=t.maxFeePerBlobGas??r.maxFeePerBlobGas,r.maxFeePerGas&&=t.maxFeePerGas??r.maxFeePerGas,r.maxPriorityFeePerGas&&=t.maxPriorityFeePerGas??r.maxPriorityFeePerGas,r.nonce!==void 0&&(r.nonce=t.nonce??r.nonce);let i=await(async()=>{if(typeof a?.fees?.baseFeeMultiplier==`function`){let n=await K(e,My,`getBlock`)({});return a.fees.baseFeeMultiplier({block:n,client:e,request:t})}return a?.fees?.baseFeeMultiplier??1.2})();if(i<1)throw new wy;let o=10**(i.toString().split(`.`)[1]?.length??0),s=e=>e*BigInt(Math.ceil(i*o))/BigInt(o);return r.feePayerSignature||(r.maxFeePerGas&&!t.maxFeePerGas&&(r.maxFeePerGas=s(r.maxFeePerGas)),r.gasPrice&&!t.gasPrice&&(r.gasPrice=s(r.gasPrice))),{raw:n.raw,transaction:{from:S.from,...r},...n.capabilities?{capabilities:n.capabilities}:{}}}catch(n){throw ub(n,{...t,chain:e.chain})}}var pb=[`blobVersionedHashes`,`chainId`,`fees`,`gas`,`nonce`,`type`],mb=new Map,hb=new yg(128);async function gb(e,t){let n=t;n.account??=e.account,n.parameters??=pb;let{account:r,chain:i=e.chain,nonceManager:a,parameters:o}=n,s=(()=>{if(typeof i?.prepareTransactionRequest==`function`)return{fn:i.prepareTransactionRequest,runAt:[`beforeFillTransaction`]};if(Array.isArray(i?.prepareTransactionRequest))return{fn:i.prepareTransactionRequest[0],runAt:i.prepareTransactionRequest[1].runAt}})(),c;async function l(){return c||(n.chainId===void 0?i?i.id:(c=await K(e,db,`getChainId`)({}),c):n.chainId)}let u=r&&r_(r),d=n.nonce;if(o.includes(`nonce`)&&d===void 0&&u&&a){let t=await l();d=await a.consume({address:u.address,chainId:t,client:e})}s?.fn&&s.runAt?.includes(`beforeFillTransaction`)&&(n=await s.fn({...n,chain:i},{phase:`beforeFillTransaction`}),d??=n.nonce);let f=!((o.includes(`blobVersionedHashes`)||o.includes(`sidecars`))&&n.kzg&&n.blobs||hb.get(e.uid)===!1||![`fees`,`gas`].some(e=>o.includes(e)))&&(o.includes(`chainId`)&&typeof n.chainId!=`number`||o.includes(`nonce`)&&typeof d!=`number`||o.includes(`fees`)&&typeof n.gasPrice!=`bigint`&&(typeof n.maxFeePerGas!=`bigint`||typeof n.maxPriorityFeePerGas!=`bigint`)||o.includes(`gas`)&&typeof n.gas!=`bigint`)?await K(e,fb,`fillTransaction`)({...n,nonce:d}).then(t=>{let{chainId:r,from:i,gas:a,gasPrice:o,nonce:s,maxFeePerBlobGas:c,maxFeePerGas:l,maxPriorityFeePerGas:u,type:d,...f}=t.transaction;return hb.set(e.uid,!0),{...n,...i?{from:i}:{},...d&&!n.type?{type:d}:{},...r===void 0?{}:{chainId:r},...a===void 0?{}:{gas:a},...o===void 0?{}:{gasPrice:o},...s===void 0?{}:{nonce:s},...c!==void 0&&n.type!==`legacy`&&n.type!==`eip2930`?{maxFeePerBlobGas:c}:{},...l!==void 0&&n.type!==`legacy`&&n.type!==`eip2930`?{maxFeePerGas:l}:{},...u!==void 0&&n.type!==`legacy`&&n.type!==`eip2930`?{maxPriorityFeePerGas:u}:{},...`nonceKey`in f&&f.nonceKey!==void 0?{nonceKey:f.nonceKey}:{},...`keyAuthorization`in f&&f.keyAuthorization!==void 0&&f.keyAuthorization!==null&&!(`keyAuthorization`in n)?{keyAuthorization:f.keyAuthorization}:{},...`feePayerSignature`in f&&f.feePayerSignature!==void 0&&f.feePayerSignature!==null?{feePayerSignature:f.feePayerSignature}:{},...`feeToken`in f&&f.feeToken!==void 0&&f.feeToken!==null&&!(`feeToken`in n)?{feeToken:f.feeToken}:{},...t.capabilities?{_capabilities:t.capabilities}:{}}}).catch(t=>{let r=t;if(r.name!==`TransactionExecutionError`)return n;if(r.walk?.(e=>e.name===`ExecutionRevertedError`))throw t;return r.walk?.(e=>{let t=e;return t.name===`MethodNotFoundRpcError`||t.name===`MethodNotSupportedRpcError`||t.message?.includes(`eth_fillTransaction is not available`)})&&hb.set(e.uid,!1),n}):n;d??=f.nonce,n={...f,...u?{from:u?.address}:{},...d===void 0?{}:{nonce:d}};let{blobs:p,gas:m,kzg:h,type:g}=n;s?.fn&&s.runAt?.includes(`beforeFillParameters`)&&(n=await s.fn({...n,chain:i},{phase:`beforeFillParameters`}));let _;async function v(){return _||(_=await K(e,My,`getBlock`)({blockTag:`latest`}),_)}if(o.includes(`nonce`)&&d===void 0&&u&&!a&&(n.nonce=await K(e,Ry,`getTransactionCount`)({address:u.address,blockTag:`pending`})),(o.includes(`blobVersionedHashes`)||o.includes(`sidecars`))&&p&&h){let e=zy({blobs:p,kzg:h});if(o.includes(`blobVersionedHashes`)){let t=eb({commitments:e,to:`hex`});n.blobVersionedHashes=t}if(o.includes(`sidecars`)){let t=cb({blobs:p,commitments:e,proofs:By({blobs:p,commitments:e,kzg:h}),to:`hex`});n.sidecars=t}}if(o.includes(`chainId`)&&(n.chainId=await l()),(o.includes(`fees`)||o.includes(`type`))&&g===void 0)try{n.type=lb(n)}catch{let t=mb.get(e.uid);t===void 0&&(t=typeof(await v())?.baseFeePerGas==`bigint`,mb.set(e.uid,t)),n.type=t?`eip1559`:`legacy`}if(o.includes(`fees`))if(n.type!==`legacy`&&n.type!==`eip2930`){if(n.maxFeePerGas===void 0||n.maxPriorityFeePerGas===void 0){let{maxFeePerGas:t,maxPriorityFeePerGas:r}=await Ly(e,{block:await v(),chain:i,request:n});if(n.maxPriorityFeePerGas===void 0&&n.maxFeePerGas&&n.maxFeePerGas{if(Array.isArray(r))return r;if(i?.type!==`local`)return[`blobVersionedHashes`]})();try{let n=await(async()=>{if(t.to)return t.to;if(t.authorizationList&&t.authorizationList.length>0)return await $v({authorization:t.authorizationList[0]}).catch(()=>{throw new q("`to` is required. Could not infer from `authorizationList`")})})(),{accessList:o,authorizationList:s,blobs:c,blobVersionedHashes:l,blockNumber:u,blockTag:d,data:f,gas:p,gasPrice:m,maxFeePerBlobGas:h,maxFeePerGas:g,maxPriorityFeePerGas:_,nonce:v,value:y,stateOverride:b,...x}=r?await gb(e,{...t,parameters:a,to:n}):t;if(p&&t.gas!==p)return p;let S=(typeof u==`bigint`?J(u):void 0)||d,C=xy(b);Cy(t);let w=e.chain?.formatters?.transactionRequest?.format,T=(w||_y)({...hy(x,{format:w}),account:i,accessList:o,authorizationList:s,blobs:c,blobVersionedHashes:l,data:f,gasPrice:m,maxFeePerBlobGas:h,maxFeePerGas:g,maxPriorityFeePerGas:_,nonce:v,to:n,value:y},`estimateGas`);return BigInt(await e.request({method:`eth_estimateGas`,params:C?[T,S??e.experimental_blockTag??`latest`,C]:S?[T,S]:[T]}))}catch(n){throw my(n,{...t,account:i,chain:e.chain})}}async function vb(e,t){let{abi:n,address:r,args:i,functionName:a,dataSuffix:o=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,...s}=t,c=o_({abi:n,args:i,functionName:a});try{return await K(e,_b,`estimateGas`)({data:`${c}${o?o.replace(`0x`,``):``}`,to:r,...s})}catch(e){throw Rv(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/estimateContractGas`,functionName:a,sender:(s.account?r_(s.account):void 0)?.address})}}function yb(e,t){if(!Tg(e,{strict:!1}))throw new vg({address:e});if(!Tg(t,{strict:!1}))throw new vg({address:t});return e.toLowerCase()===t.toLowerCase()}function bb(e,{args:t,eventName:n}={}){return{...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,blockTimestamp:e.blockTimestamp?BigInt(e.blockTimestamp):e.blockTimestamp===null?null:void 0,logIndex:e.logIndex?Number(e.logIndex):null,transactionHash:e.transactionHash?e.transactionHash:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,...n?{args:t,eventName:n}:{}}}var xb=`/docs/contract/decodeEventLog`;function Sb(e){let{abi:t,data:n,strict:r,topics:i}=e,a=r??!0,[o,...s]=i;if(!o)throw new nh({docsPath:xb});let c=t.find(e=>e.type===`event`&&o===_g(Rm(e)));if(!(c&&`name`in c)||c.type!==`event`)throw new rh(o,{docsPath:xb});let{name:l,inputs:u}=c,d=u?.some(e=>!(`name`in e&&e.name)),f=d?[]:{},p=u.map((e,t)=>[e,t]).filter(([e])=>`indexed`in e&&e.indexed),m=[];for(let e=0;e!(`indexed`in e&&e.indexed)),g=a?h:[...m.map(([e])=>e),...h];if(g.length>0){if(n&&n!==`0x`)try{let e=y_(g,n);if(e){let t=0;if(!a)for(let[n,r]of m)f[d?r:n.name||r]=e[t++];if(d)for(let n=0;n0?f:void 0}}function Cb({param:e,value:t}){return e.type===`string`||e.type===`bytes`||e.type===`tuple`||e.type.match(/^(.*)\[(\d+)?\]$/)?t:(y_([e],t)||[])[0]}function wb(e){let{abi:t,args:n,logs:r,strict:i=!0}=e,a=(()=>{if(e.eventName)return Array.isArray(e.eventName)?e.eventName:[e.eventName]})(),o=t.filter(e=>e.type===`event`).map(e=>({abi:e,selector:_g(e)}));return r.map(e=>{let t=typeof e.blockNumber==`string`?bb(e):e,r=o.filter(e=>t.topics[0]===e.selector);if(r.length===0)return null;let s,c;for(let e of r)try{s=Sb({...t,abi:[e.abi],strict:!0}),c=e;break}catch{}if(!s&&!i){c=r[0];try{s=Sb({data:t.data,topics:t.topics,abi:[c.abi],strict:!1})}catch{let e=c.abi.inputs?.some(e=>!(`name`in e&&e.name));return{...t,args:e?[]:{},eventName:c.abi.name}}}return!s||!c||a&&!a.includes(s.eventName)||!Tb({args:s.args,inputs:c.abi.inputs,matchArgs:n})?null:{...s,...t}}).filter(Boolean)}function Tb(e){let{args:t,inputs:n,matchArgs:r}=e;if(!r)return!0;if(!t)return!1;function i(e,t,n){try{return e.type===`address`?yb(t,n):e.type===`string`||e.type===`bytes`?dg(zh(t))===n:t===n}catch{return!1}}return Array.isArray(t)&&Array.isArray(r)?r.every((e,r)=>{if(e==null)return!0;let a=n[r];return a?(Array.isArray(e)?e:[e]).some(e=>i(a,e,t[r])):!1}):typeof t==`object`&&!Array.isArray(t)&&typeof r==`object`&&!Array.isArray(r)?Object.entries(r).every(([e,r])=>{if(r==null)return!0;let a=n.find(t=>t.name===e);return a?(Array.isArray(r)?r:[r]).some(n=>i(a,n,t[e])):!1}):!1}async function Eb(e,{address:t,blockHash:n,fromBlock:r,toBlock:i,event:a,events:o,args:s,strict:c}={}){let l=c??!1,u=o??(a?[a]:void 0),d=[];u&&(d=[u.flatMap(e=>$g({abi:[e],eventName:e.name,args:o?void 0:s}))],a&&(d=d[0]));let f;f=n?await e.request({method:`eth_getLogs`,params:[{address:t,topics:d,blockHash:n}]}):await e.request({method:`eth_getLogs`,params:[{address:t,topics:d,fromBlock:typeof r==`bigint`?J(r):r,toBlock:typeof i==`bigint`?J(i):i}]});let p=f.map(e=>bb(e));return u?wb({abi:u,args:s,logs:p,strict:l}):p}async function Db(e,t){let{abi:n,address:r,args:i,blockHash:a,eventName:o,fromBlock:s,toBlock:c,strict:l}=t,u=o?Yg({abi:n,name:o}):void 0,d=u?void 0:n.filter(e=>e.type===`event`);return K(e,Eb,`getLogs`)({address:r,args:i,blockHash:a,event:u,events:d,fromBlock:s,toBlock:c,strict:l})}var Ob=`/docs/contract/decodeFunctionResult`;function kb(e){let{abi:t,args:n,functionName:r,data:i}=e,a=t[0];if(r){let e=Yg({abi:t,args:n,name:r});if(!e)throw new ah(r,{docsPath:Ob});a=e}if(a.type!==`function`)throw new ah(void 0,{docsPath:Ob});if(!a.outputs)throw new oh(a.name,{docsPath:Ob});let o=y_(a.outputs,i);if(o&&o.length>1)return o;if(o&&o.length===1)return o[0]}var Ab=`0.1.1`;function jb(){return Ab}var Y=class e extends Error{static setStaticOptions(t){e.prototype.docsOrigin=t.docsOrigin,e.prototype.showVersion=t.showVersion,e.prototype.version=t.version}constructor(t,n={}){let r=(()=>{if(n.cause instanceof e){if(n.cause.details)return n.cause.details;if(n.cause.shortMessage)return n.cause.shortMessage}return n.cause&&`details`in n.cause&&typeof n.cause.details==`string`?n.cause.details:n.cause?.message?n.cause.message:n.details})(),i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=n.docsOrigin??e.prototype.docsOrigin,o=`${a}${i??``}`,s=!!(n.version??e.prototype.showVersion),c=n.version??e.prototype.version,l=[t||`An error occurred.`,...n.metaMessages?[``,...n.metaMessages]:[],...r||i||s?[``,r?`Details: ${r}`:void 0,i?`See: ${o}`:void 0,s?`Version: ${c}`:void 0]:[]].filter(e=>typeof e==`string`).join(` +`);super(l,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsOrigin`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`showVersion`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.cause=n.cause,this.details=r,this.docs=o,this.docsOrigin=a,this.docsPath=i,this.shortMessage=t,this.showVersion=s,this.version=c}walk(e){return Mb(this,e)}};Object.defineProperty(Y,`defaultStaticOptions`,{enumerable:!0,configurable:!0,writable:!0,value:{docsOrigin:`https://oxlib.sh`,showVersion:!1,version:`ox@${jb()}`}}),Y.setStaticOptions(Y.defaultStaticOptions);function Mb(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause?Mb(e.cause,t):t?null:e}function Nb(e,t){if($b(e)>t)throw new cx({givenSize:$b(e),maxSize:t})}function Pb(e,t){if(typeof t==`number`&&t>0&&t>$b(e)-1)throw new lx({offset:t,position:`start`,size:$b(e)})}function Fb(e,t,n){if(typeof t==`number`&&typeof n==`number`&&$b(e)!==n-t)throw new lx({offset:n,position:`end`,size:$b(e)})}var Ib={zero:48,nine:57,A:65,F:70,a:97,f:102};function Lb(e){if(e>=Ib.zero&&e<=Ib.nine)return e-Ib.zero;if(e>=Ib.A&&e<=Ib.F)return e-(Ib.A-10);if(e>=Ib.a&&e<=Ib.f)return e-(Ib.a-10)}function Rb(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;if(e.length>r)throw new ux({size:e.length,targetSize:r,type:`Bytes`});let i=new Uint8Array(r);for(let t=0;tt)throw new Ax({givenSize:Cx(e),maxSize:t})}function Vb(e,t){if(typeof t==`number`&&t>0&&t>Cx(e)-1)throw new jx({offset:t,position:`start`,size:Cx(e)})}function Hb(e,t,n){if(typeof t==`number`&&typeof n==`number`&&Cx(e)!==n-t)throw new jx({offset:n,position:`end`,size:Cx(e)})}function Ub(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;let i=e.replace(`0x`,``);if(i.length>r*2)throw new Mx({size:Math.ceil(i.length/2),targetSize:r,type:`Hex`});return`0x${i[n===`right`?`padEnd`:`padStart`](r*2,`0`)}`}var Wb=`#__bigint`;function Gb(e,t,n){return JSON.stringify(e,(e,n)=>typeof t==`function`?t(e,n):typeof n==`bigint`?n.toString()+Wb:n,n)}var Kb=new TextDecoder,qb=new TextEncoder;function Jb(e){return e instanceof Uint8Array?e:typeof e==`string`?Xb(e):Yb(e)}function Yb(e){return e instanceof Uint8Array?e:new Uint8Array(e)}function Xb(e,t={}){let{size:n}=t,r=e;n&&(Bb(e,n),r=xx(e,n));let i=r.slice(2);i.length%2&&(i=`0${i}`);let a=i.length/2,o=new Uint8Array(a);for(let e=0,t=0;e1||r[0]>1)throw new sx(r);return!!r[0]}function rx(e,t={}){let{size:n}=t;return n!==void 0&&Nb(e,n),Tx(_x(e,t),t)}function ix(e,t={}){let{size:n}=t,r=e;return n!==void 0&&(Nb(r,n),r=ox(r)),Kb.decode(r)}function ax(e){return zb(e,{dir:`left`})}function ox(e){return zb(e,{dir:`right`})}var sx=class extends Y{constructor(e){super(`Bytes value \`${e}\` is not a valid boolean.`,{metaMessages:["The bytes array must contain a single byte of either a `0` or `1` value."]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.InvalidBytesBooleanError`})}},cx=class extends Y{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \`${t}\` bytes. Given size: \`${e}\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeOverflowError`})}},lx=class extends Y{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \`${e}\` is out-of-bounds (size: \`${n}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SliceOffsetOutOfBoundsError`})}},ux=class extends Y{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\`${e}\`) exceeds padding size (\`${t}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeExceedsPaddingSizeError`})}},dx=new TextEncoder,fx=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`));function px(e,t={}){let{strict:n=!1}=t;if(!e||typeof e!=`string`)throw new Ox(e);if(n&&!/^0x[0-9a-fA-F]*$/.test(e)||!e.startsWith(`0x`))throw new kx(e)}function mx(...e){return`0x${e.reduce((e,t)=>e+t.replace(`0x`,``),``)}`}function hx(e){return e instanceof Uint8Array?_x(e):Array.isArray(e)?_x(new Uint8Array(e)):e}function gx(e,t={}){let n=`0x${Number(e)}`;return typeof t.size==`number`?(Bb(n,t.size),bx(n,t.size)):n}function _x(e,t={}){let n=``;for(let t=0;ta||i>1n?r:r-a-1n}function Tx(e,t={}){let{signed:n,size:r}=t;return Number(!n&&!r?e:wx(e,t))}function Ex(e,t={}){let{strict:n=!1}=t;try{return px(e,{strict:n}),!0}catch{return!1}}var Dx=class extends Y{constructor({max:e,min:t,signed:n,size:r,value:i}){super(`Number \`${i}\` is not in safe${r?` ${r*8}-bit`:``}${n?` signed`:` unsigned`} integer range ${e?`(\`${t}\` to \`${e}\`)`:`(above \`${t}\`)`}`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.IntegerOutOfRangeError`})}},Ox=class extends Y{constructor(e){super(`Value \`${typeof e==`object`?Gb(e):e}\` of type \`${typeof e}\` is an invalid hex type.`,{metaMessages:['Hex types must be represented as `"0x${string}"`.']}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.InvalidHexTypeError`})}},kx=class extends Y{constructor(e){super(`Value \`${e}\` is an invalid hex value.`,{metaMessages:['Hex values must start with `"0x"` and contain only hexadecimal characters (0-9, a-f, A-F).']}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.InvalidHexValueError`})}},Ax=class extends Y{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \`${t}\` bytes. Given size: \`${e}\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SizeOverflowError`})}},jx=class extends Y{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \`${e}\` is out-of-bounds (size: \`${n}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SliceOffsetOutOfBoundsError`})}},Mx=class extends Y{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\`${e}\`) exceeds padding size (\`${t}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SizeExceedsPaddingSizeError`})}};function Nx(e){return{address:e.address,amount:vx(e.amount),index:vx(e.index),validatorIndex:vx(e.validatorIndex)}}function Px(e){return{...typeof e.baseFeePerGas==`bigint`&&{baseFeePerGas:vx(e.baseFeePerGas)},...typeof e.blobBaseFee==`bigint`&&{blobBaseFee:vx(e.blobBaseFee)},...typeof e.feeRecipient==`string`&&{feeRecipient:e.feeRecipient},...typeof e.gasLimit==`bigint`&&{gasLimit:vx(e.gasLimit)},...typeof e.number==`bigint`&&{number:vx(e.number)},...typeof e.prevRandao==`bigint`&&{prevRandao:vx(e.prevRandao)},...typeof e.time==`bigint`&&{time:vx(e.time)},...e.withdrawals&&{withdrawals:e.withdrawals.map(Nx)}}}var Fx=[{inputs:[{components:[{name:`target`,type:`address`},{name:`allowFailure`,type:`bool`},{name:`callData`,type:`bytes`}],name:`calls`,type:`tuple[]`}],name:`aggregate3`,outputs:[{components:[{name:`success`,type:`bool`},{name:`returnData`,type:`bytes`}],name:`returnData`,type:`tuple[]`}],stateMutability:`view`,type:`function`},{inputs:[{name:`addr`,type:`address`}],name:`getEthBalance`,outputs:[{name:`balance`,type:`uint256`}],stateMutability:`view`,type:`function`},{inputs:[],name:`getCurrentBlockTimestamp`,outputs:[{internalType:`uint256`,name:`timestamp`,type:`uint256`}],stateMutability:`view`,type:`function`}],Ix=[{name:`query`,type:`function`,stateMutability:`view`,inputs:[{type:`tuple[]`,name:`queries`,components:[{type:`address`,name:`sender`},{type:`string[]`,name:`urls`},{type:`bytes`,name:`data`}]}],outputs:[{type:`bool[]`,name:`failures`},{type:`bytes[]`,name:`responses`}]},{name:`HttpError`,type:`error`,inputs:[{type:`uint16`,name:`status`},{type:`string`,name:`message`}]}],Lx=[{inputs:[{name:`dns`,type:`bytes`}],name:`DNSDecodingFailed`,type:`error`},{inputs:[{name:`ens`,type:`string`}],name:`DNSEncodingFailed`,type:`error`},{inputs:[],name:`EmptyAddress`,type:`error`},{inputs:[{name:`status`,type:`uint16`},{name:`message`,type:`string`}],name:`HttpError`,type:`error`},{inputs:[],name:`InvalidBatchGatewayResponse`,type:`error`},{inputs:[{name:`errorData`,type:`bytes`}],name:`ResolverError`,type:`error`},{inputs:[{name:`name`,type:`bytes`},{name:`resolver`,type:`address`}],name:`ResolverNotContract`,type:`error`},{inputs:[{name:`name`,type:`bytes`}],name:`ResolverNotFound`,type:`error`},{inputs:[{name:`primary`,type:`string`},{name:`primaryAddress`,type:`bytes`}],name:`ReverseAddressMismatch`,type:`error`},{inputs:[{internalType:`bytes4`,name:`selector`,type:`bytes4`}],name:`UnsupportedResolverProfile`,type:`error`}],Rx=[...Lx,{name:`resolveWithGateways`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes`},{name:`data`,type:`bytes`},{name:`gateways`,type:`string[]`}],outputs:[{name:``,type:`bytes`},{name:`address`,type:`address`}]}],zx=[...Lx,{name:`reverseWithGateways`,type:`function`,stateMutability:`view`,inputs:[{type:`bytes`,name:`reverseName`},{type:`uint256`,name:`coinType`},{type:`string[]`,name:`gateways`}],outputs:[{type:`string`,name:`resolvedName`},{type:`address`,name:`resolver`},{type:`address`,name:`reverseResolver`}]}],Bx=[{name:`text`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes32`},{name:`key`,type:`string`}],outputs:[{name:``,type:`string`}]}],Vx=[{name:`addr`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes32`}],outputs:[{name:``,type:`address`}]},{name:`addr`,type:`function`,stateMutability:`view`,inputs:[{name:`name`,type:`bytes32`},{name:`coinType`,type:`uint256`}],outputs:[{name:``,type:`bytes`}]}],Hx=[{name:`isValidSignature`,type:`function`,stateMutability:`view`,inputs:[{name:`hash`,type:`bytes32`},{name:`signature`,type:`bytes`}],outputs:[{name:``,type:`bytes4`}]}],Ux=[{inputs:[{name:`_signer`,type:`address`},{name:`_hash`,type:`bytes32`},{name:`_signature`,type:`bytes`}],stateMutability:`nonpayable`,type:`constructor`},{inputs:[{name:`_signer`,type:`address`},{name:`_hash`,type:`bytes32`},{name:`_signature`,type:`bytes`}],outputs:[{type:`bool`}],stateMutability:`nonpayable`,type:`function`,name:`isValidSig`}],Wx=`0x608060405234801561001057600080fd5b5060405161018e38038061018e83398101604081905261002f91610124565b6000808351602085016000f59050803b61004857600080fd5b6000808351602085016000855af16040513d6000823e81610067573d81fd5b3d81f35b634e487b7160e01b600052604160045260246000fd5b600082601f83011261009257600080fd5b81516001600160401b038111156100ab576100ab61006b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156100d9576100d961006b565b6040528181528382016020018510156100f157600080fd5b60005b82811015610110576020818601810151838301820152016100f4565b506000918101602001919091529392505050565b6000806040838503121561013757600080fd5b82516001600160401b0381111561014d57600080fd5b61015985828601610081565b602085015190935090506001600160401b0381111561017757600080fd5b61018385828601610081565b915050925092905056fe`,Gx=`0x608060405234801561001057600080fd5b506040516102c03803806102c083398101604081905261002f916101e6565b836001600160a01b03163b6000036100e457600080836001600160a01b03168360405161005c9190610270565b6000604051808303816000865af19150503d8060008114610099576040519150601f19603f3d011682016040523d82523d6000602084013e61009e565b606091505b50915091508115806100b857506001600160a01b0386163b155b156100e1578060405163101bb98d60e01b81526004016100d8919061028c565b60405180910390fd5b50505b6000808451602086016000885af16040513d6000823e81610103573d81fd5b3d81f35b80516001600160a01b038116811461011e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015457818101518382015260200161013c565b50506000910152565b600082601f83011261016e57600080fd5b81516001600160401b0381111561018757610187610123565b604051601f8201601f19908116603f011681016001600160401b03811182821017156101b5576101b5610123565b6040528181528382016020018510156101cd57600080fd5b6101de826020830160208701610139565b949350505050565b600080600080608085870312156101fc57600080fd5b61020585610107565b60208601519094506001600160401b0381111561022157600080fd5b61022d8782880161015d565b93505061023c60408601610107565b60608601519092506001600160401b0381111561025857600080fd5b6102648782880161015d565b91505092959194509250565b60008251610282818460208701610139565b9190910192915050565b60208152600082518060208401526102ab816040850160208701610139565b601f01601f1916919091016040019291505056fe`,Kx=`0x608060405234801561001057600080fd5b5060405161069438038061069483398101604081905261002f9161051e565b600061003c848484610048565b9050806000526001601ff35b60007f64926492649264926492649264926492649264926492649264926492649264926100748361040c565b036101e7576000606080848060200190518101906100929190610577565b60405192955090935091506000906001600160a01b038516906100b69085906105dd565b6000604051808303816000865af19150503d80600081146100f3576040519150601f19603f3d011682016040523d82523d6000602084013e6100f8565b606091505b50509050876001600160a01b03163b60000361016057806101605760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90610190908b9087906004016105f9565b602060405180830381865afa1580156101ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d19190610633565b6001600160e01b03191614945050505050610405565b6001600160a01b0384163b1561027a57604051630b135d3f60e11b808252906001600160a01b03861690631626ba7e9061022790879087906004016105f9565b602060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102689190610633565b6001600160e01b031916149050610405565b81516041146102df5760405162461bcd60e51b815260206004820152603a602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e6774680000000000006064820152608401610157565b6102e7610425565b5060208201516040808401518451859392600091859190811061030c5761030c61065d565b016020015160f81c9050601b811480159061032b57508060ff16601c14155b1561038c5760405162461bcd60e51b815260206004820152603b602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c756500000000006064820152608401610157565b60408051600081526020810180835289905260ff83169181019190915260608101849052608081018390526001600160a01b0389169060019060a0016020604051602081039080840390855afa1580156103ea573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149450505050505b9392505050565b600060208251101561041d57600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b038116811461045857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561048c578181015183820152602001610474565b50506000910152565b600082601f8301126104a657600080fd5b81516001600160401b038111156104bf576104bf61045b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104ed576104ed61045b565b60405281815283820160200185101561050557600080fd5b610516826020830160208701610471565b949350505050565b60008060006060848603121561053357600080fd5b835161053e81610443565b6020850151604086015191945092506001600160401b0381111561056157600080fd5b61056d86828701610495565b9150509250925092565b60008060006060848603121561058c57600080fd5b835161059781610443565b60208501519093506001600160401b038111156105b357600080fd5b6105bf86828701610495565b604086015190935090506001600160401b0381111561056157600080fd5b600082516105ef818460208701610471565b9190910192915050565b828152604060208201526000825180604084015261061e816060850160208701610471565b601f01601f1916919091016060019392505050565b60006020828403121561064557600080fd5b81516001600160e01b03198116811461040557600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572`,qx=`0x608060405234801561001057600080fd5b506115b9806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e14610325578063bce38bd714610350578063c3077fa914610380578063ee82ac5e146103b2576100f3565b80634d2301cc1461026257806372425d9d1461029f57806382ad56cb146102ca57806386d516e8146102fa576100f3565b80633408e470116100c65780633408e470146101af578063399542e9146101da5780633e64a6961461020c57806342cbb15c14610237576100f3565b80630f28c97d146100f8578063174dea7114610123578063252dba421461015357806327e86d6e14610184575b600080fd5b34801561010457600080fd5b5061010d6103ef565b60405161011a9190610c0a565b60405180910390f35b61013d60048036038101906101389190610c94565b6103f7565b60405161014a9190610e94565b60405180910390f35b61016d60048036038101906101689190610f0c565b610615565b60405161017b92919061101b565b60405180910390f35b34801561019057600080fd5b506101996107ab565b6040516101a69190611064565b60405180910390f35b3480156101bb57600080fd5b506101c46107b7565b6040516101d19190610c0a565b60405180910390f35b6101f460048036038101906101ef91906110ab565b6107bf565b6040516102039392919061110b565b60405180910390f35b34801561021857600080fd5b506102216107e1565b60405161022e9190610c0a565b60405180910390f35b34801561024357600080fd5b5061024c6107e9565b6040516102599190610c0a565b60405180910390f35b34801561026e57600080fd5b50610289600480360381019061028491906111a7565b6107f1565b6040516102969190610c0a565b60405180910390f35b3480156102ab57600080fd5b506102b4610812565b6040516102c19190610c0a565b60405180910390f35b6102e460048036038101906102df919061122a565b61081a565b6040516102f19190610e94565b60405180910390f35b34801561030657600080fd5b5061030f6109e4565b60405161031c9190610c0a565b60405180910390f35b34801561033157600080fd5b5061033a6109ec565b6040516103479190611286565b60405180910390f35b61036a600480360381019061036591906110ab565b6109f4565b6040516103779190610e94565b60405180910390f35b61039a60048036038101906103959190610f0c565b610ba6565b6040516103a99392919061110b565b60405180910390f35b3480156103be57600080fd5b506103d960048036038101906103d491906112cd565b610bca565b6040516103e69190611064565b60405180910390f35b600042905090565b60606000808484905090508067ffffffffffffffff81111561041c5761041b6112fa565b5b60405190808252806020026020018201604052801561045557816020015b610442610bd5565b81526020019060019003908161043a5790505b5092503660005b828110156105c957600085828151811061047957610478611329565b5b6020026020010151905087878381811061049657610495611329565b5b90506020028101906104a89190611367565b925060008360400135905080860195508360000160208101906104cb91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16818580606001906104f2919061138f565b604051610500929190611431565b60006040518083038185875af1925050503d806000811461053d576040519150601f19603f3d011682016040523d82523d6000602084013e610542565b606091505b5083600001846020018290528215151515815250505081516020850135176105bc577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b826001019250505061045c565b5082341461060c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610603906114a7565b60405180910390fd5b50505092915050565b6000606043915060008484905090508067ffffffffffffffff81111561063e5761063d6112fa565b5b60405190808252806020026020018201604052801561067157816020015b606081526020019060019003908161065c5790505b5091503660005b828110156107a157600087878381811061069557610694611329565b5b90506020028101906106a791906114c7565b92508260000160208101906106bc91906111a7565b73ffffffffffffffffffffffffffffffffffffffff168380602001906106e2919061138f565b6040516106f0929190611431565b6000604051808303816000865af19150503d806000811461072d576040519150601f19603f3d011682016040523d82523d6000602084013e610732565b606091505b5086848151811061074657610745611329565b5b60200260200101819052819250505080610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078c9061153b565b60405180910390fd5b81600101915050610678565b5050509250929050565b60006001430340905090565b600046905090565b6000806060439250434091506107d68686866109f4565b905093509350939050565b600048905090565b600043905090565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b600044905090565b606060008383905090508067ffffffffffffffff81111561083e5761083d6112fa565b5b60405190808252806020026020018201604052801561087757816020015b610864610bd5565b81526020019060019003908161085c5790505b5091503660005b828110156109db57600084828151811061089b5761089a611329565b5b602002602001015190508686838181106108b8576108b7611329565b5b90506020028101906108ca919061155b565b92508260000160208101906108df91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060400190610905919061138f565b604051610913929190611431565b6000604051808303816000865af19150503d8060008114610950576040519150601f19603f3d011682016040523d82523d6000602084013e610955565b606091505b5082600001836020018290528215151515815250505080516020840135176109cf577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b8160010191505061087e565b50505092915050565b600045905090565b600041905090565b606060008383905090508067ffffffffffffffff811115610a1857610a176112fa565b5b604051908082528060200260200182016040528015610a5157816020015b610a3e610bd5565b815260200190600190039081610a365790505b5091503660005b82811015610b9c576000848281518110610a7557610a74611329565b5b60200260200101519050868683818110610a9257610a91611329565b5b9050602002810190610aa491906114c7565b9250826000016020810190610ab991906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060200190610adf919061138f565b604051610aed929190611431565b6000604051808303816000865af19150503d8060008114610b2a576040519150601f19603f3d011682016040523d82523d6000602084013e610b2f565b606091505b508260000183602001829052821515151581525050508715610b90578060000151610b8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b869061153b565b60405180910390fd5b5b81600101915050610a58565b5050509392505050565b6000806060610bb7600186866107bf565b8093508194508295505050509250925092565b600081409050919050565b6040518060400160405280600015158152602001606081525090565b6000819050919050565b610c0481610bf1565b82525050565b6000602082019050610c1f6000830184610bfb565b92915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610c5457610c53610c2f565b5b8235905067ffffffffffffffff811115610c7157610c70610c34565b5b602083019150836020820283011115610c8d57610c8c610c39565b5b9250929050565b60008060208385031215610cab57610caa610c25565b5b600083013567ffffffffffffffff811115610cc957610cc8610c2a565b5b610cd585828601610c3e565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60008115159050919050565b610d2281610d0d565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610d62578082015181840152602081019050610d47565b83811115610d71576000848401525b50505050565b6000601f19601f8301169050919050565b6000610d9382610d28565b610d9d8185610d33565b9350610dad818560208601610d44565b610db681610d77565b840191505092915050565b6000604083016000830151610dd96000860182610d19565b5060208301518482036020860152610df18282610d88565b9150508091505092915050565b6000610e0a8383610dc1565b905092915050565b6000602082019050919050565b6000610e2a82610ce1565b610e348185610cec565b935083602082028501610e4685610cfd565b8060005b85811015610e825784840389528151610e638582610dfe565b9450610e6e83610e12565b925060208a01995050600181019050610e4a565b50829750879550505050505092915050565b60006020820190508181036000830152610eae8184610e1f565b905092915050565b60008083601f840112610ecc57610ecb610c2f565b5b8235905067ffffffffffffffff811115610ee957610ee8610c34565b5b602083019150836020820283011115610f0557610f04610c39565b5b9250929050565b60008060208385031215610f2357610f22610c25565b5b600083013567ffffffffffffffff811115610f4157610f40610c2a565b5b610f4d85828601610eb6565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000610f918383610d88565b905092915050565b6000602082019050919050565b6000610fb182610f59565b610fbb8185610f64565b935083602082028501610fcd85610f75565b8060005b858110156110095784840389528151610fea8582610f85565b9450610ff583610f99565b925060208a01995050600181019050610fd1565b50829750879550505050505092915050565b60006040820190506110306000830185610bfb565b81810360208301526110428184610fa6565b90509392505050565b6000819050919050565b61105e8161104b565b82525050565b60006020820190506110796000830184611055565b92915050565b61108881610d0d565b811461109357600080fd5b50565b6000813590506110a58161107f565b92915050565b6000806000604084860312156110c4576110c3610c25565b5b60006110d286828701611096565b935050602084013567ffffffffffffffff8111156110f3576110f2610c2a565b5b6110ff86828701610eb6565b92509250509250925092565b60006060820190506111206000830186610bfb565b61112d6020830185611055565b818103604083015261113f8184610e1f565b9050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061117482611149565b9050919050565b61118481611169565b811461118f57600080fd5b50565b6000813590506111a18161117b565b92915050565b6000602082840312156111bd576111bc610c25565b5b60006111cb84828501611192565b91505092915050565b60008083601f8401126111ea576111e9610c2f565b5b8235905067ffffffffffffffff81111561120757611206610c34565b5b60208301915083602082028301111561122357611222610c39565b5b9250929050565b6000806020838503121561124157611240610c25565b5b600083013567ffffffffffffffff81111561125f5761125e610c2a565b5b61126b858286016111d4565b92509250509250929050565b61128081611169565b82525050565b600060208201905061129b6000830184611277565b92915050565b6112aa81610bf1565b81146112b557600080fd5b50565b6000813590506112c7816112a1565b92915050565b6000602082840312156112e3576112e2610c25565b5b60006112f1848285016112b8565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160800383360303811261138357611382611358565b5b80830191505092915050565b600080833560016020038436030381126113ac576113ab611358565b5b80840192508235915067ffffffffffffffff8211156113ce576113cd61135d565b5b6020830192506001820236038313156113ea576113e9611362565b5b509250929050565b600081905092915050565b82818337600083830152505050565b600061141883856113f2565b93506114258385846113fd565b82840190509392505050565b600061143e82848661140c565b91508190509392505050565b600082825260208201905092915050565b7f4d756c746963616c6c333a2076616c7565206d69736d61746368000000000000600082015250565b6000611491601a8361144a565b915061149c8261145b565b602082019050919050565b600060208201905081810360008301526114c081611484565b9050919050565b6000823560016040038336030381126114e3576114e2611358565b5b80830191505092915050565b7f4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000600082015250565b600061152560178361144a565b9150611530826114ef565b602082019050919050565b6000602082019050818103600083015261155481611518565b9050919050565b60008235600160600383360303811261157757611576611358565b5b8083019150509291505056fea264697066735822122020c1bc9aacf8e4a6507193432a895a8e77094f45a1395583f07b24e860ef06cd64736f6c634300080c0033`,Jx=class extends q{constructor({blockNumber:e,chain:t,contract:n}){super(`Chain "${t.name}" does not support contract "${n.name}".`,{metaMessages:[`This could be due to any of the following:`,...e&&n.blockCreated&&n.blockCreated>e?[`- The contract "${n.name}" was not deployed until block ${n.blockCreated} (current block ${e}).`]:[`- The chain does not have the contract "${n.name}" configured.`]],name:`ChainDoesNotSupportContract`})}},Yx=class extends q{constructor({chain:e,currentChainId:t}){super(`The current chain of the wallet (id: ${t}) does not match the target chain for the transaction (id: ${e.id} – ${e.name}).`,{metaMessages:[`Current Chain ID: ${t}`,`Expected Chain ID: ${e.id} – ${e.name}`],name:`ChainMismatchError`})}},Xx=class extends q{constructor(){super([`No chain was provided to the request.`,"Please provide a chain with the `chain` argument on the Action, or by supplying a `chain` to WalletClient."].join(` +`),{name:`ChainNotFoundError`})}},Zx=class extends q{constructor(){super(`No chain was provided to the Client.`,{name:`ClientChainNotConfiguredError`})}},Qx=`/docs/contract/encodeDeployData`;function $x(e){let{abi:t,args:n,bytecode:r}=e;if(!n||n.length===0)return r;let i=t.find(e=>`type`in e&&e.type===`constructor`);if(!i)throw new Km({docsPath:Qx});if(!(`inputs`in i)||!i.inputs||i.inputs.length===0)throw new qm({docsPath:Qx});return Og([r,Ig(i.inputs,n)])}function eS({blockNumber:e,chain:t,contract:n}){let r=t?.contracts?.[n];if(!r)throw new Jx({chain:t,contract:{name:n}});if(e&&r.blockCreated&&r.blockCreated>e)throw new Jx({blockNumber:e,chain:t,contract:{name:n,blockCreated:r.blockCreated}});return r.address}function tS(e,{docsPath:t,...n}){return new Q_((()=>{let t=py(e,n);return t instanceof fy?e:t})(),{docsPath:t,...n})}function nS(){let e=()=>void 0,t=()=>void 0;return{promise:new Promise((n,r)=>{e=n,t=r}),resolve:e,reject:t}}var rS=new Map;function iS({fn:e,id:t,shouldSplitBatch:n,wait:r=0,sort:i}){let a=async()=>{let t=c();o();let n=t.map(({args:e})=>e);n.length!==0&&e(n).then(e=>{i&&Array.isArray(e)&&e.sort(i);for(let n=0;n{for(let n=0;nrS.delete(t),s=()=>c().map(({args:e})=>e),c=()=>rS.get(t)||[],l=e=>rS.set(t,[...c(),e]);return{flush:o,async schedule(e){let{promise:t,resolve:i,reject:o}=nS();return n?.([...s(),e])&&a(),c().length>0?(l({args:e,resolve:i,reject:o}),t):(l({args:e,resolve:i,reject:o}),setTimeout(a,r),t)}}}async function aS(e,t){let{account:n=e.account,authorizationList:r,batch:i=!!e.batch?.multicall,blockNumber:a,blockTag:o=e.experimental_blockTag??`latest`,accessList:s,blobs:c,blockOverrides:l,code:u,data:d,factory:f,factoryData:p,gas:m,gasPrice:h,maxFeePerBlobGas:g,maxFeePerGas:_,maxPriorityFeePerGas:v,nonce:y,to:b,value:x,stateOverride:S,...C}=t,w=n?r_(n):void 0;if(u&&(f||p))throw new q("Cannot provide both `code` & `factory`/`factoryData` as parameters.");if(u&&b)throw new q("Cannot provide both `code` & `to` as parameters.");let T=u&&d,E=f&&p&&b&&d,D=T||E,ee=T?cS({code:u,data:d}):E?lS({data:d,factory:f,factoryData:p,to:b}):d;try{Cy(t);let n=(typeof a==`bigint`?J(a):void 0)||o,u=l?Px(l):void 0,d=xy(S),f=e.chain?.formatters?.transactionRequest?.format,p=(f||_y)({...hy(C,{format:f}),accessList:s,account:w,authorizationList:r,blobs:c,data:ee,gas:m,gasPrice:h,maxFeePerBlobGas:g,maxFeePerGas:_,maxPriorityFeePerGas:v,nonce:y,to:D?void 0:b,value:x},`call`);if(i&&oS({request:p})&&!d&&!u)try{return await sS(e,{...p,blockNumber:a,blockTag:o})}catch(e){if(!(e instanceof Zx)&&!(e instanceof Jx))throw e}let T=(()=>{let e=[p,n];return d&&u?[...e,d,u]:d?[...e,d]:u?[...e,{},u]:e})(),E=await e.request({method:`eth_call`,params:T});return E===`0x`?{data:void 0}:{data:E}}catch(n){let r=uS(n),{offchainLookup:i,offchainLookupSignature:a}=await Uv(async()=>{let{offchainLookup:e,offchainLookupSignature:t}=await import(`./ccip-Ch1826Mz.js`);return{offchainLookup:e,offchainLookupSignature:t}},[]);if(e.ccipRead!==!1&&r?.slice(0,10)===a&&b)return{data:await i(e,{data:r,to:b})};throw D&&r?.slice(0,10)===`0x101bb98d`?new nv({factory:f}):tS(n,{...t,account:w,chain:e.chain})}}function oS({request:e}){let{data:t,to:n,...r}=e;return!(!t||t.startsWith(`0x82ad56cb`)||!n||Object.values(r).filter(e=>e!==void 0).length>0)}async function sS(e,t){let{batchSize:n=1024,deployless:r=!1,wait:i=0}=typeof e.batch?.multicall==`object`?e.batch.multicall:{},{blockNumber:a,blockTag:o=e.experimental_blockTag??`latest`,data:s,to:c}=t,l=(()=>{if(r)return null;if(t.multicallAddress)return t.multicallAddress;if(e.chain)return eS({blockNumber:a,chain:e.chain,contract:`multicall3`});throw new Zx})(),u=(typeof a==`bigint`?J(a):void 0)||o,{schedule:d}=iS({id:`${e.uid}.${u}`,wait:i,shouldSplitBatch(e){return e.reduce((e,{data:t})=>e+(t.length-2),0)>n*2},fn:async t=>{let n=t.map(e=>({allowFailure:!0,callData:e.data,target:e.to})),r=o_({abi:Fx,args:[n],functionName:`aggregate3`}),i=await e.request({method:`eth_call`,params:[{...l===null?{data:cS({code:qx,data:r})}:{to:l,data:r}},u]});return kb({abi:Fx,args:[n],functionName:`aggregate3`,data:i||`0x`})}}),[{returnData:f,success:p}]=await d({data:s,to:c});if(!p)throw new rv({data:f});return f===`0x`?{data:void 0}:{data:f}}function cS(e){let{code:t,data:n}=e;return $x({abi:Lm([`constructor(bytes, bytes)`]),bytecode:Wx,args:[t,n]})}function lS(e){let{data:t,factory:n,factoryData:r,to:i}=e;return $x({abi:Lm([`constructor(address, bytes, address, bytes)`]),bytecode:Gx,args:[i,t,n,r]})}function uS(e){if(!(e instanceof q))return;let t=e.walk();return typeof t?.data==`object`?t.data?.data:t.data}async function dS(e,t){let{abi:n,address:r,args:i,functionName:a,...o}=t,s=o_({abi:n,args:i,functionName:a});try{let{data:t}=await K(e,aS,`call`)({...o,data:s,to:r});return kb({abi:n,args:i,functionName:a,data:t||`0x`})}catch(e){throw Rv(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/readContract`,functionName:a})}}async function fS(e,t){let{abi:n,address:r,args:i,functionName:a,dataSuffix:o=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,...s}=t,c=s.account?r_(s.account):e.account,l=o_({abi:n,args:i,functionName:a});try{let{data:u}=await K(e,aS,`call`)({batch:!1,data:`${l}${o?o.replace(`0x`,``):``}`,to:r,...s,account:c});return{result:kb({abi:n,args:i,functionName:a,data:u||`0x`}),request:{abi:n.filter(e=>`name`in e&&e.name===t.functionName),address:r,args:i,dataSuffix:o,functionName:a,...s,account:c}}}catch(e){throw Rv(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/simulateContract`,functionName:a,sender:c?.address})}}var pS=new Map,mS=new Map,hS=0;function gS(e,t,n){let r=++hS,i=()=>pS.get(e)||[],a=()=>{let t=i();pS.set(e,t.filter(e=>e.id!==r))},o=()=>{let t=i();if(!t.some(e=>e.id===r))return;let n=mS.get(e);if(t.length===1&&n){let e=n();e instanceof Promise&&e.catch(()=>{})}a()},s=i();if(pS.set(e,[...s,{id:r,fns:t}]),s&&s.length>0)return o;let c={};for(let e in t)c[e]=((...t)=>{let n=i();if(n.length!==0)for(let r of n)r.fns[e]?.(...t)});let l=n(c);return typeof l==`function`&&mS.set(e,l),o}async function _S(e){return new Promise(t=>setTimeout(t,e))}function vS(e,{emitOnBegin:t,initialWaitTime:n,interval:r}){let i=!0,a=()=>i=!1;return(async()=>{let o;t&&(o=await e({unpoll:a})),await _S(await n?.(o)??r);let s=async()=>{i&&(await e({unpoll:a}),await _S(r),s())};s()})(),a}var yS=new Map,bS=new Map;function xS(e){let t=(e,t)=>({clear:()=>t.delete(e),get:()=>t.get(e),set:n=>t.set(e,n)}),n=t(e,yS),r=t(e,bS);return{clear:()=>{n.clear(),r.clear()},promise:n,response:r}}async function SS(e,{cacheKey:t,cacheTime:n=1/0}){let r=xS(t),i=r.response.get();if(i&&n>0&&Date.now()-i.created.getTime()`blockNumber.${e}`;async function wS(e,{cacheTime:t=e.cacheTime}={}){let n=await SS(()=>e.request({method:`eth_blockNumber`}),{cacheKey:CS(e.uid),cacheTime:t});return BigInt(n)}async function TS(e,{filter:t}){let n=`strict`in t&&t.strict,r=await t.request({method:`eth_getFilterChanges`,params:[t.id]});if(typeof r[0]==`string`)return r;let i=r.map(e=>bb(e));return!(`abi`in t)||!t.abi?i:wb({abi:t.abi,logs:i,strict:n})}async function ES(e,{filter:t}){return t.request({method:`eth_uninstallFilter`,params:[t.id]})}function DS(e,t){let{abi:n,address:r,args:i,batch:a=!0,eventName:o,fromBlock:s,onError:c,onLogs:l,poll:u,pollingInterval:d=e.pollingInterval,strict:f}=t;return(u===void 0?typeof s==`bigint`||!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):u)?(()=>{let t=f??!1;return gS(M_([`watchContractEvent`,r,i,a,e.uid,o,d,t,s]),{onLogs:l,onError:c},c=>{let l;s!==void 0&&(l=s-1n);let u,f=!1,p=vS(async()=>{if(!f){try{u=await K(e,n_,`createContractEventFilter`)({abi:n,address:r,args:i,eventName:o,strict:t,fromBlock:s})}catch{}f=!0;return}try{let s;if(u)s=await K(e,TS,`getFilterChanges`)({filter:u});else{let a=await K(e,wS,`getBlockNumber`)({});s=l&&l{u&&await K(e,ES,`uninstallFilter`)({filter:u}),p()}})})():(()=>{let t=f??!1,s=M_([`watchContractEvent`,r,i,a,e.uid,o,d,t]),u=!0,p=()=>u=!1;return gS(s,{onLogs:l,onError:c},t=>((async()=>{try{let a=(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})(),s=o?$g({abi:n,eventName:o,args:i}):[],{unsubscribe:c}=await a.subscribe({params:[`logs`,{address:r,topics:s}],onData(e){if(!u)return;let r=e.result;try{let{eventName:e,args:i}=Sb({abi:n,data:r.data,topics:r.topics,strict:f}),a=bb(r,{args:i,eventName:e});t.onLogs([a])}catch(e){let n,i;if(e instanceof uh||e instanceof dh){if(f)return;n=e.abiItem.name,i=e.abiItem.inputs?.some(e=>!(`name`in e&&e.name))}let a=bb(r,{args:i?[]:{},eventName:n});t.onLogs([a])}},onError(e){t.onError?.(e)}});p=c,u||p()}catch(e){c?.(e)}})(),()=>p()))})()}var OS=class extends q{constructor({docsPath:e}={}){super([`Could not find an Account to execute with this Action.`,"Please provide an Account with the `account` argument on the Action, or by supplying an `account` to the Client."].join(` +`),{docsPath:e,docsSlug:`account`,name:`AccountNotFoundError`})}},kS=class extends q{constructor({docsPath:e,metaMessages:t,type:n}){super(`Account type "${n}" is not supported.`,{docsPath:e,metaMessages:t,name:`AccountTypeNotSupportedError`})}};function AS({chain:e,currentChainId:t}){if(!e)throw new Xx;if(t!==e.id)throw new Yx({chain:e,currentChainId:t})}async function jS(e,{serializedTransaction:t}){return e.request({method:`eth_sendRawTransaction`,params:[t]},{retryCount:0})}var MS=new yg(128);async function NS(e,t){let{account:n=e.account,assertChainId:r=!0,chain:i=e.chain,accessList:a,authorizationList:o,blobs:s,data:c,dataSuffix:l=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,type:g,value:_,...v}=t;if(n===void 0)throw new OS({docsPath:`/docs/actions/wallet/sendTransaction`});let y=n?r_(n):null;try{Cy(t);let n=await(async()=>{if(t.to)return t.to;if(t.to!==null&&o&&o.length>0)return await $v({authorization:o[0]}).catch(()=>{throw new q("`to` is required. Could not infer from `authorizationList`.")})})();if(y?.type===`json-rpc`||y===null){let t;i!==null&&(t=await K(e,db,`getChainId`)({}),r&&AS({currentChainId:t,chain:i}));let b=e.chain?.formatters?.transactionRequest?.format,x=(b||_y)({...hy(v,{format:b}),accessList:a,account:y,authorizationList:o,blobs:s,chainId:t,data:l?Eg([c??`0x`,l]):c,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,to:n,type:g,value:_},`sendTransaction`),S=MS.get(e.uid),C=S?`wallet_sendTransaction`:`eth_sendTransaction`;try{return await e.request({method:C,params:[x]},{retryCount:0})}catch(t){if(S===!1)throw t;let n=t;if(n.name===`InvalidInputRpcError`||n.name===`InvalidParamsRpcError`||n.name===`MethodNotFoundRpcError`||n.name===`MethodNotSupportedRpcError`)return await e.request({method:`wallet_sendTransaction`,params:[x]},{retryCount:0}).then(t=>(MS.set(e.uid,!0),t)).catch(t=>{let r=t;throw r.name===`MethodNotFoundRpcError`||r.name===`MethodNotSupportedRpcError`?(MS.set(e.uid,!1),n):r});throw n}}if(y?.type===`local`){let t=await K(e,gb,`prepareTransactionRequest`)({account:y,accessList:a,authorizationList:o,blobs:s,chain:i,data:l?Eg([c??`0x`,l]):c,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,nonceManager:y.nonceManager,parameters:[...pb,`sidecars`],type:g,value:_,...v,to:n}),r=i?.serializers?.transaction,b=await y.signTransaction(t,{serializer:r});return await K(e,jS,`sendRawTransaction`)({serializedTransaction:b})}throw y?.type===`smart`?new kS({metaMessages:["Consider using the `sendUserOperation` Action instead."],docsPath:`/docs/actions/bundler/sendUserOperation`,type:`smart`}):new kS({docsPath:`/docs/actions/wallet/sendTransaction`,type:y?.type})}catch(e){throw e instanceof kS?e:ub(e,{...t,account:y,chain:t.chain||void 0})}}async function PS(e,t){return PS.internal(e,NS,`sendTransaction`,t)}(function(e){async function t(e,t,n,r){let{abi:i,account:a=e.account,address:o,args:s,functionName:c,...l}=r;if(a===void 0)throw new OS({docsPath:`/docs/contract/writeContract`});let u=a?r_(a):null,d=o_({abi:i,args:s,functionName:c});try{return await K(e,t,n)({data:d,to:o,account:u,...l})}catch(e){throw Rv(e,{abi:i,address:o,args:s,docsPath:`/docs/contract/writeContract`,functionName:c,sender:u?.address})}}e.internal=t})(PS||={});var FS=class extends q{constructor(e){super(`Call bundle failed with status: ${e.statusCode}`,{name:`BundleFailedError`}),Object.defineProperty(this,`result`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.result=e}};function IS(e,{delay:t=100,retryCount:n=2,shouldRetry:r=()=>!0}={}){return new Promise((i,a)=>{let o=async({count:s=0}={})=>{let c=async({error:e})=>{let n=typeof t==`function`?t({count:s,error:e}):t;n&&await _S(n),o({count:s+1})};try{i(await e())}catch(e){if(sbb(e)):null,to:e.to?e.to:null,transactionIndex:e.transactionIndex?jh(e.transactionIndex):null,status:e.status?LS[e.status]:null,type:e.type?Oy[e.type]||e.type:null};return e.blobGasPrice&&(n.blobGasPrice=BigInt(e.blobGasPrice)),e.blobGasUsed&&(n.blobGasUsed=BigInt(e.blobGasUsed)),n}var zS=`0x5792579257925792579257925792579257925792579257925792579257925792`,BS=J(0,{size:32});async function VS(e,t){let{account:n=e.account,chain:r=e.chain,experimental_fallback:i,experimental_fallbackDelay:a=32,forceAtomic:o=!1,id:s,version:c=`2.0.0`}=t,l=n?r_(n):null,u=t.capabilities;e.dataSuffix&&!t.capabilities?.dataSuffix&&(u=typeof e.dataSuffix==`string`?{...t.capabilities,dataSuffix:{value:e.dataSuffix,optional:!0}}:{...t.capabilities,dataSuffix:{value:e.dataSuffix.value,...e.dataSuffix.required?{}:{optional:!0}}});let d=t.calls.map(e=>{let t=e,n=t.abi?o_({abi:t.abi,functionName:t.functionName,args:t.args}):t.data;return{data:t.dataSuffix&&n?Eg([n,t.dataSuffix]):n,to:t.to,value:t.value?J(t.value):void 0}});try{let t=await e.request({method:`wallet_sendCalls`,params:[{atomicRequired:o,calls:d,capabilities:u,chainId:J(r.id),from:l?.address,id:s,version:c}]},{retryCount:0});return typeof t==`string`?{id:t}:t}catch(n){let s=n;if(i&&(s.name===`MethodNotFoundRpcError`||s.name===`MethodNotSupportedRpcError`||s.name===`UnknownRpcError`||s.details.toLowerCase().includes(`does not exist / is not available`)||s.details.toLowerCase().includes(`missing or invalid. request()`)||s.details.toLowerCase().includes(`did not match any variant of untagged enum`)||s.details.toLowerCase().includes(`account upgraded to unsupported contract`)||s.details.toLowerCase().includes(`eip-7702 not supported`)||s.details.toLowerCase().includes(`unsupported wc_ method`)||s.details.toLowerCase().includes(`feature toggled misconfigured`)||s.details.toLowerCase().includes(`jsonrpcengine: response has no error or result for request`))){if(u&&Object.values(u).some(e=>!e.optional)){let e="non-optional `capabilities` are not supported on fallback to `eth_sendTransaction`.";throw new Ov(new q(e,{details:e}))}if(o&&d.length>1){let e="`forceAtomic` is not supported on fallback to `eth_sendTransaction`.";throw new Pv(new q(e,{details:e}))}let t=[];for(let n of d){let i=NS(e,{account:l,chain:r,data:n.data,to:n.to,value:n.value?kh(n.value):void 0});t.push(i),a>0&&await new Promise(e=>setTimeout(e,a))}let n=await Promise.allSettled(t);if(n.every(e=>e.status===`rejected`))throw n[0].reason;return{id:Eg([...n.map(e=>e.status===`fulfilled`?e.value:BS),J(r.id,{size:32}),zS])}}throw ub(n,{...t,account:l,chain:t.chain})}}async function HS(e,t){async function n(t){if(t.endsWith(`5792579257925792579257925792579257925792579257925792579257925792`)){let n=Dh(Ng(t,-64,-32)),r=Ng(t,0,-64).slice(2).match(/.{1,64}/g),i=await Promise.all(r.map(t=>BS.slice(2)===t?void 0:e.request({method:`eth_getTransactionReceipt`,params:[`0x${t}`]},{dedupe:!0}))),a=i.some(e=>e===null)?100:i.every(e=>e?.status===`0x1`)?200:i.every(e=>e?.status===`0x0`)?500:600;return{atomic:!1,chainId:jh(n),receipts:i.filter(Boolean),status:a,version:`2.0.0`}}return e.request({method:`wallet_getCallsStatus`,params:[t]})}let{atomic:r=!1,chainId:i,receipts:a,version:o=`2.0.0`,...s}=await n(t.id),[c,l]=(()=>{let e=s.status;return e>=100&&e<200?[`pending`,e]:e>=200&&e<300?[`success`,e]:e>=300&&e<700?[`failure`,e]:e===`CONFIRMED`?[`success`,200]:e===`PENDING`?[`pending`,100]:[void 0,e]})();return{...s,atomic:r,chainId:i?jh(i):void 0,receipts:a?.map(e=>({...e,blockNumber:kh(e.blockNumber),gasUsed:kh(e.gasUsed),status:LS[e.status]}))??[],statusCode:l,status:c,version:o}}async function US(e,t){let{id:n,pollingInterval:r=e.pollingInterval,status:i=({statusCode:e})=>e===200||e>=300,retryCount:a=4,retryDelay:o=({count:e})=>~~(1<{let s=vS(async()=>{let r=e=>{clearTimeout(p),s(),e(),m()};try{let s=await IS(async()=>{let t=await K(e,HS,`getCallsStatus`)({id:n});if(c&&t.status===`failure`)throw new FS(t);return t},{retryCount:a,delay:o});if(!i(s))return;r(()=>t.resolve(s))}catch(e){r(()=>t.reject(e))}},{interval:r,emitOnBegin:!0});return s});return p=s?setTimeout(()=>{m(),clearTimeout(p),f(new WS({id:n}))},s):void 0,await u}var WS=class extends q{constructor({id:e}){super(`Timed out while waiting for call bundle with id "${e}" to be confirmed.`,{name:`WaitForCallsStatusTimeoutError`})}},GS=256,KS=GS,qS;function JS(e=11){if(!qS||KS+e>GS*2){qS=``,KS=0;for(let e=0;e{let n=t(e);for(let e in _)delete n[e];let r={...e,...n};return Object.assign(r,{extend:v(r)})}}return Object.assign(_,{extend:v(_)})}function XS(e){if(!(e instanceof q))return!1;let t=e.walk(e=>e instanceof ev);return t instanceof ev?t.data?.errorName===`HttpError`||t.data?.errorName===`ResolverError`||t.data?.errorName===`ResolverNotContract`||t.data?.errorName===`ResolverNotFound`||t.data?.errorName===`ReverseAddressMismatch`||t.data?.errorName===`UnsupportedResolverProfile`:!1}function ZS(e){let{abi:t,data:n}=e,r=kg(n,0,4),i=t.find(e=>e.type===`function`&&r===Jg(Rm(e)));if(!i)throw new sh(r,{docsPath:`/docs/contract/decodeFunctionData`});return{functionName:i.name,args:`inputs`in i&&i.inputs&&i.inputs.length>0?y_(i.inputs,kg(n,4)):void 0}}var QS=`/docs/contract/encodeErrorResult`;function $S(e){let{abi:t,errorName:n,args:r}=e,i=t[0];if(n){let e=Yg({abi:t,args:r,name:n});if(!e)throw new eh(n,{docsPath:QS});i=e}if(i.type!==`error`)throw new eh(void 0,{docsPath:QS});let a=Jg(Rm(i)),o=`0x`;if(r&&r.length>0){if(!i.inputs)throw new $m(i.name,{docsPath:QS});o=Ig(i.inputs,r)}return Og([a,o])}var eC=`/docs/contract/encodeFunctionResult`;function tC(e){let{abi:t,functionName:n,result:r}=e,i=t[0];if(n){let e=Yg({abi:t,name:n});if(!e)throw new ah(n,{docsPath:eC});i=e}if(i.type!==`function`)throw new ah(void 0,{docsPath:eC});if(!i.outputs)throw new oh(i.name,{docsPath:eC});let a=(()=>{if(i.outputs.length===0)return[];if(i.outputs.length===1)return[r];if(Array.isArray(r))return r;throw new mh(r)})();return Ig(i.outputs,a)}var nC=`x-batch-gateway:true`;async function rC(e){let{data:t,ccipRequest:n}=e,{args:[r]}=ZS({abi:Ix,data:t}),i=[],a=[];return await Promise.all(r.map(async(e,t)=>{try{a[t]=e.urls.includes(`x-batch-gateway:true`)?await rC({data:e.data,ccipRequest:n}):await n(e),i[t]=!1}catch(e){i[t]=!0,a[t]=iC(e)}})),tC({abi:Ix,functionName:`query`,result:[i,a]})}function iC(e){return e.name===`HttpRequestError`&&e.status?$S({abi:Ix,errorName:`HttpError`,args:[e.status,e.shortMessage]}):$S({abi:[c_],errorName:`Error`,args:[`shortMessage`in e?e.shortMessage:e.message]})}function aC(e){if(e.length!==66||e.indexOf(`[`)!==0||e.indexOf(`]`)!==65)return null;let t=`0x${e.slice(1,65)}`;return Vm(t)?t:null}function oC(e){let t=new Uint8Array(32).fill(0);if(!e)return Fh(t);let n=e.split(`.`);for(let e=n.length-1;e>=0;--e){let r=aC(n[e]),i=r?zh(r):dg(Gh(n[e]),`bytes`);t=dg(Eg([t,i]),`bytes`)}return Fh(t)}function sC(e){return`[${e.slice(2)}]`}function cC(e){let t=new Uint8Array(32).fill(0);return e?aC(e)||dg(Gh(e)):Fh(t)}function lC(e){let t=e.replace(/^\.|\.$/gm,``);if(t.length===0)return new Uint8Array(1);let n=new Uint8Array(Gh(t).byteLength+2),r=0,i=t.split(`.`);for(let e=0;e255&&(t=Gh(sC(cC(i[e])))),n[r]=t.length,n.set(t,r+1),r+=t.length+1}return n.byteLength===r+1?n:n.slice(0,r+1)}async function uC(e,t){let{blockNumber:n,blockTag:r,coinType:i,name:a,gatewayUrls:o,strict:s}=t,{chain:c}=e,l=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw Error(`client chain not configured. universalResolverAddress is required.`);return eS({blockNumber:n,chain:c,contract:`ensUniversalResolver`})})(),u=c?.ensTlds;if(u&&!u.some(e=>a.endsWith(e)))return null;let d=i==null?[oC(a)]:[oC(a),BigInt(i)];try{let t=o_({abi:Vx,functionName:`addr`,args:d}),i={address:l,abi:Rx,functionName:`resolveWithGateways`,args:[Nh(lC(a)),t,o??[`x-batch-gateway:true`]],blockNumber:n,blockTag:r},s=await K(e,dS,`readContract`)(i);if(s[0]===`0x`)return null;let c=kb({abi:Vx,args:d,functionName:`addr`,data:s[0]});return c===`0x`||Dh(c)===`0x00`?null:c}catch(e){if(s)throw e;if(XS(e))return null;throw e}}var dC=class extends q{constructor({data:e}){super(`Unable to extract image from metadata. The metadata may be malformed or invalid.`,{metaMessages:["- Metadata must be a JSON object with at least an `image`, `image_url` or `image_data` property.",``,`Provided data: ${JSON.stringify(e)}`],name:`EnsAvatarInvalidMetadataError`})}},fC=class extends q{constructor({reason:e}){super(`ENS NFT avatar URI is invalid. ${e}`,{name:`EnsAvatarInvalidNftUriError`})}},pC=class extends q{constructor({uri:e}){super(`Unable to resolve ENS avatar URI "${e}". The URI may be malformed, invalid, or does not respond with a valid image.`,{name:`EnsAvatarUriResolutionError`})}},mC=class extends q{constructor({namespace:e}){super(`ENS NFT avatar namespace "${e}" is not supported. Must be "erc721" or "erc1155".`,{name:`EnsAvatarUnsupportedNamespaceError`})}},hC=/(?https?:\/\/[^/]*|ipfs:\/|ipns:\/|ar:\/)?(?\/)?(?ipfs\/|ipns\/)?(?[\w\-.]+)(?\/.*)?/,gC=/^(Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,})(\/(?[\w\-.]+))?(?\/.*)?$/,_C=/^data:([a-zA-Z\-/+]*);base64,([^"].*)/,vC=/^data:([a-zA-Z\-/+]*)?(;[a-zA-Z0-9].*?)?(,)/;async function yC(e){try{let t=await fetch(e,{method:`HEAD`});return t.status===200?t.headers.get(`content-type`)?.startsWith(`image/`):!1}catch(t){return typeof t==`object`&&t.response!==void 0||!Object.hasOwn(globalThis,`Image`)?!1:new Promise(t=>{let n=new Image;n.onload=()=>{t(!0)},n.onerror=()=>{t(!1)},n.src=e})}}function bC(e,t){return e?e.endsWith(`/`)?e.slice(0,-1):e:t}function xC({uri:e,gatewayUrls:t}){let n=_C.test(e);if(n)return{uri:e,isOnChain:!0,isEncoded:n};let r=bC(t?.ipfs,`https://ipfs.io`),i=bC(t?.arweave,`https://arweave.net`),{protocol:a,subpath:o,target:s,subtarget:c=``}=e.match(hC)?.groups||{},l=a===`ipns:/`||o===`ipns/`,u=a===`ipfs:/`||o===`ipfs/`||gC.test(e);if(e.startsWith(`http`)&&!l&&!u){let n=e;return t?.arweave&&(n=e.replace(/https:\/\/arweave.net/g,t?.arweave)),{uri:n,isOnChain:!1,isEncoded:!1}}if((l||u)&&s)return{uri:`${r}/${l?`ipns`:`ipfs`}/${s}${c}`,isOnChain:!1,isEncoded:!1};if(a===`ar:/`&&s)return{uri:`${i}/${s}${c||``}`,isOnChain:!1,isEncoded:!1};let d=e.replace(vC,``);if(d.startsWith(`e.json()))})}catch{throw new pC({uri:t})}}async function wC({gatewayUrls:e,uri:t}){let{uri:n,isOnChain:r}=xC({uri:t,gatewayUrls:e});if(r||await yC(n))return n;throw new pC({uri:t})}function TC(e){let t=e;t.startsWith(`did:nft:`)&&(t=t.replace(`did:nft:`,``).replace(/_/g,`/`));let[n,r,i]=t.split(`/`),[a,o]=n.split(`:`),[s,c]=r.split(`:`);if(!a||a.toLowerCase()!==`eip155`)throw new fC({reason:`Only EIP-155 supported`});if(!o)throw new fC({reason:`Chain ID not found`});if(!c)throw new fC({reason:`Contract address not found`});if(!i)throw new fC({reason:`Token ID not found`});if(!s)throw new fC({reason:`ERC namespace not found`});return{chainID:Number.parseInt(o,10),namespace:s.toLowerCase(),contractAddress:c,tokenID:i}}async function EC(e,{nft:t}){if(t.namespace===`erc721`)return dS(e,{address:t.contractAddress,abi:[{name:`tokenURI`,type:`function`,stateMutability:`view`,inputs:[{name:`tokenId`,type:`uint256`}],outputs:[{name:``,type:`string`}]}],functionName:`tokenURI`,args:[BigInt(t.tokenID)]});if(t.namespace===`erc1155`)return dS(e,{address:t.contractAddress,abi:[{name:`uri`,type:`function`,stateMutability:`view`,inputs:[{name:`_id`,type:`uint256`}],outputs:[{name:``,type:`string`}]}],functionName:`uri`,args:[BigInt(t.tokenID)]});throw new mC({namespace:t.namespace})}async function DC(e,{gatewayUrls:t,record:n}){return/eip155:/i.test(n)?OC(e,{gatewayUrls:t,record:n}):wC({uri:n,gatewayUrls:t})}async function OC(e,{gatewayUrls:t,record:n}){let r=TC(n),{uri:i,isOnChain:a,isEncoded:o}=xC({uri:await EC(e,{nft:r}),gatewayUrls:t});if(a&&(i.includes(`data:application/json;base64,`)||i.startsWith(`{`))){let e=o?atob(i.replace(`data:application/json;base64,`,``)):i;return wC({uri:SC(JSON.parse(e)),gatewayUrls:t})}let s=r.tokenID;return r.namespace===`erc1155`&&(s=s.replace(`0x`,``).padStart(64,`0`)),CC({gatewayUrls:t,uri:i.replace(/(?:0x)?{id}/,s)})}async function kC(e,t){let{blockNumber:n,blockTag:r,key:i,name:a,gatewayUrls:o,strict:s}=t,{chain:c}=e,l=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw Error(`client chain not configured. universalResolverAddress is required.`);return eS({blockNumber:n,chain:c,contract:`ensUniversalResolver`})})(),u=c?.ensTlds;if(u&&!u.some(e=>a.endsWith(e)))return null;try{let t={address:l,abi:Rx,args:[Nh(lC(a)),o_({abi:Bx,functionName:`text`,args:[oC(a),i]}),o??[`x-batch-gateway:true`]],functionName:`resolveWithGateways`,blockNumber:n,blockTag:r},s=await K(e,dS,`readContract`)(t);if(s[0]===`0x`)return null;let c=kb({abi:Bx,functionName:`text`,data:s[0]});return c===``?null:c}catch(e){if(s)throw e;if(XS(e))return null;throw e}}async function AC(e,{blockNumber:t,blockTag:n,assetGatewayUrls:r,name:i,gatewayUrls:a,strict:o,universalResolverAddress:s}){let c=await K(e,kC,`getEnsText`)({blockNumber:t,blockTag:n,key:`avatar`,name:i,universalResolverAddress:s,gatewayUrls:a,strict:o});if(!c)return null;try{return await DC(e,{record:c,gatewayUrls:r})}catch{return null}}async function jC(e,t){let{address:n,blockNumber:r,blockTag:i,coinType:a=60n,gatewayUrls:o,strict:s}=t,{chain:c}=e,l=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!c)throw Error(`client chain not configured. universalResolverAddress is required.`);return eS({blockNumber:r,chain:c,contract:`ensUniversalResolver`})})();try{let t={address:l,abi:zx,args:[n,a,o??[`x-batch-gateway:true`]],functionName:`reverseWithGateways`,blockNumber:r,blockTag:i},[s]=await K(e,dS,`readContract`)(t);return s||null}catch(e){if(s)throw e;if(XS(e))return null;throw e}}async function MC(e,t){let{blockNumber:n,blockTag:r,name:i}=t,{chain:a}=e,o=(()=>{if(t.universalResolverAddress)return t.universalResolverAddress;if(!a)throw Error(`client chain not configured. universalResolverAddress is required.`);return eS({blockNumber:n,chain:a,contract:`ensUniversalResolver`})})(),s=a?.ensTlds;if(s&&!s.some(e=>i.endsWith(e)))throw Error(`${i} is not a valid ENS TLD (${s?.join(`, `)}) for chain "${a.name}" (id: ${a.id}).`);let[c]=await K(e,dS,`readContract`)({address:o,abi:[{inputs:[{type:`bytes`}],name:`findResolver`,outputs:[{type:`address`},{type:`bytes32`},{type:`uint256`}],stateMutability:`view`,type:`function`}],functionName:`findResolver`,args:[Nh(lC(i))],blockNumber:n,blockTag:r});return c}async function NC(e,t){let{account:n=e.account,blockNumber:r,blockTag:i=`latest`,blobs:a,data:o,gas:s,gasPrice:c,maxFeePerBlobGas:l,maxFeePerGas:u,maxPriorityFeePerGas:d,to:f,value:p,...m}=t,h=n?r_(n):void 0;try{Cy(t);let n=(typeof r==`bigint`?J(r):void 0)||i,g=e.chain?.formatters?.transactionRequest?.format,_=(g||_y)({...hy(m,{format:g}),account:h,blobs:a,data:o,gas:s,gasPrice:c,maxFeePerBlobGas:l,maxFeePerGas:u,maxPriorityFeePerGas:d,to:f,value:p},`createAccessList`),v=await e.request({method:`eth_createAccessList`,params:[_,n]});return{accessList:v.accessList,gasUsed:BigInt(v.gasUsed)}}catch(n){throw tS(n,{...t,account:h,chain:e.chain})}}async function PC(e){let t=t_(e,{method:`eth_newBlockFilter`}),n=await e.request({method:`eth_newBlockFilter`});return{id:n,request:t(n),type:`block`}}async function FC(e,{address:t,args:n,event:r,events:i,fromBlock:a,strict:o,toBlock:s}={}){let c=i??(r?[r]:void 0),l=t_(e,{method:`eth_newFilter`}),u=[];c&&(u=[c.flatMap(e=>$g({abi:[e],eventName:e.name,args:n}))],r&&(u=u[0]));let d=await e.request({method:`eth_newFilter`,params:[{address:t,fromBlock:typeof a==`bigint`?J(a):a,toBlock:typeof s==`bigint`?J(s):s,...u.length?{topics:u}:{}}]});return{abi:c,args:n,eventName:r?r.name:void 0,fromBlock:a,id:d,request:l(d),strict:!!o,toBlock:s,type:`event`}}async function IC(e){let t=t_(e,{method:`eth_newPendingTransactionFilter`}),n=await e.request({method:`eth_newPendingTransactionFilter`});return{id:n,request:t(n),type:`transaction`}}async function LC(e,{address:t,blockNumber:n,blockTag:r=e.experimental_blockTag??`latest`}){if(e.batch?.multicall&&e.chain?.contracts?.multicall3){let i=e.chain.contracts.multicall3.address,a=o_({abi:Fx,functionName:`getEthBalance`,args:[t]}),{data:o}=await K(e,aS,`call`)({to:i,data:a,blockNumber:n,blockTag:r});return kb({abi:Fx,functionName:`getEthBalance`,args:[t],data:o||`0x`})}let i=typeof n==`bigint`?J(n):void 0,a=await e.request({method:`eth_getBalance`,params:[t,i||r]});return BigInt(a)}async function RC(e){let t=await e.request({method:`eth_blobBaseFee`});return BigInt(t)}async function zC(e,{blockHash:t,blockNumber:n,blockTag:r=`latest`}={}){let i=n===void 0?void 0:J(n),a;return a=t?await e.request({method:`eth_getBlockTransactionCountByHash`,params:[t]},{dedupe:!0}):await e.request({method:`eth_getBlockTransactionCountByNumber`,params:[i||r]},{dedupe:!!i}),jh(a)}async function BC(e,{address:t,blockNumber:n,blockTag:r=`latest`}){let i=n===void 0?void 0:J(n),a=await e.request({method:`eth_getCode`,params:[t,i||r]},{dedupe:!!i});if(a!==`0x`)return a}async function VC(e,{address:t,blockNumber:n,blockTag:r=`latest`}){let i=await BC(e,{address:t,...n===void 0?{blockTag:r}:{blockNumber:n}});if(i&&Hm(i)===23&&i.startsWith(`0xef0100`))return Sg(kg(i,3,23))}var HC=class extends q{constructor({address:e}){super(`No EIP-712 domain found on contract "${e}".`,{metaMessages:[`Ensure that:`,`- The contract is deployed at the address "${e}".`,"- `eip712Domain()` function exists on the contract.","- `eip712Domain()` function matches signature to ERC-5267 specification."],name:`Eip712DomainNotFoundError`})}};async function UC(e,t){let{address:n,factory:r,factoryData:i}=t;try{let[t,a,o,s,c,l,u]=await K(e,dS,`readContract`)({abi:WC,address:n,functionName:`eip712Domain`,factory:r,factoryData:i});return{domain:{name:a,version:o,chainId:Number(s),verifyingContract:c,salt:l},extensions:u,fields:t}}catch(e){let t=e;throw t.name===`ContractFunctionExecutionError`&&t.cause.name===`ContractFunctionZeroDataError`?new HC({address:n}):t}}var WC=[{inputs:[],name:`eip712Domain`,outputs:[{name:`fields`,type:`bytes1`},{name:`name`,type:`string`},{name:`version`,type:`string`},{name:`chainId`,type:`uint256`},{name:`verifyingContract`,type:`address`},{name:`salt`,type:`bytes32`},{name:`extensions`,type:`uint256[]`}],stateMutability:`view`,type:`function`}];function GC(e){return{baseFeePerGas:e.baseFeePerGas.map(e=>BigInt(e)),gasUsedRatio:e.gasUsedRatio,oldestBlock:BigInt(e.oldestBlock),reward:e.reward?.map(e=>e.map(e=>BigInt(e)))}}async function KC(e,{blockCount:t,blockNumber:n,blockTag:r=`latest`,rewardPercentiles:i}){let a=typeof n==`bigint`?J(n):void 0;return GC(await e.request({method:`eth_feeHistory`,params:[J(t),a||r,i]},{dedupe:!!a}))}async function qC(e,{filter:t}){let n=t.strict??!1,r=(await t.request({method:`eth_getFilterLogs`,params:[t.id]})).map(e=>bb(e));return t.abi?wb({abi:t.abi,logs:r,strict:n}):r}async function JC({address:e,authorization:t,signature:n}){return yb(Sg(e),await $v({authorization:t,signature:n}))}var YC=new yg(8192);function XC(e,{enabled:t=!0,id:n}){if(!t||!n)return e();if(YC.get(n))return YC.get(n);let r=e().finally(()=>YC.delete(n));return YC.set(n,r),r}function ZC(e,t={}){return async(n,r={})=>{let{dedupe:i=!1,methods:a,retryDelay:o=150,retryCount:s=3,uid:c}={...t,...r},{method:l}=n;if(a?.exclude?.includes(l)||a?.include&&!a.include.includes(l))throw new yv(Error(`method not supported`),{method:l});return XC(()=>IS(async()=>{try{return await e(n)}catch(e){let t=e;switch(t.code){case uv.code:throw new uv(t);case dv.code:throw new dv(t);case fv.code:throw new fv(t,{method:n.method});case pv.code:throw new pv(t);case mv.code:throw new mv(t);case hv.code:throw new hv(t);case gv.code:throw new gv(t);case _v.code:throw new _v(t);case vv.code:throw new vv(t);case yv.code:throw new yv(t,{method:n.method});case bv.code:throw new bv(t);case xv.code:throw new xv(t);case Sv.code:throw new Sv(t);case Cv.code:throw new Cv(t);case wv.code:throw new wv(t);case Tv.code:throw new Tv(t);case Ev.code:throw new Ev(t);case Dv.code:throw new Dv(t);case Ov.code:throw new Ov(t);case kv.code:throw new kv(t);case Av.code:throw new Av(t);case jv.code:throw new jv(t);case Mv.code:throw new Mv(t);case Nv.code:throw new Nv(t);case Pv.code:throw new Pv(t);case 5e3:throw new Sv(t);case Fv.code:throw new Fv(t);default:throw e instanceof q?e:new Iv(t)}}},{delay:({count:e,error:t})=>{if(t&&t instanceof iv){let e=t?.headers?.get(`Retry-After`);if(e?.match(/\d/))return Number.parseInt(e,10)*1e3}return~~(1<QC(e)}),{enabled:i,id:i?$C(`${c}.${M_(n)}`):void 0})}}function QC(e){return`code`in e&&typeof e.code==`number`?e.code===-1||e.code===bv.code||e.code===mv.code||e.code===429:e instanceof iv&&e.status?e.status===403||e.status===408||e.status===413||e.status===429||e.status===500||e.status===502||e.status===503||e.status===504:!0}function $C(e,t=0){let n=3735928559^t,r=1103547991^t;for(let t=0;t>>16,2246822507),n^=Math.imul(r^r>>>16,3266489909),r=Math.imul(r^r>>>16,2246822507),r^=Math.imul(n^n>>>16,3266489909),(4294967296*(2097151&r)+(n>>>0)).toString(36)}function ew(e){let t={formatters:void 0,fees:void 0,serializers:void 0,...e};function n(e){return t=>{let r=typeof t==`function`?t(e):t,i={...e,...r};return Object.assign(i,{extend:n(i)})}}return Object.assign(t,{extend:n(t)})}function tw(e,{errorInstance:t=Error(`timed out`),timeout:n,signal:r}){return new Promise((i,a)=>{(async()=>{let o;try{let s=new AbortController;n>0&&(o=setTimeout(()=>{r?s.abort():a(t)},n)),i(await e({signal:s?.signal||null}))}catch(e){e?.name===`AbortError`&&a(t),a(e)}finally{clearTimeout(o)}})()})}function nw(){return{current:0,take(){return this.current++},reset(){this.current=0}}}var rw=nw();function iw(e,t={}){let{url:n,headers:r}=aw(e);return{async request(e){let{body:i,fetchFn:a=t.fetchFn??fetch,onRequest:o=t.onRequest,onResponse:s=t.onResponse,timeout:c=t.timeout??1e4}=e,l={...t.fetchOptions??{},...e.fetchOptions??{}},{headers:u,method:d,signal:f}=l;try{let e=await tw(async({signal:e})=>{let t={...l,body:M_(Array.isArray(i)?i.map(e=>({jsonrpc:`2.0`,id:e.id??rw.take(),...e})):{jsonrpc:`2.0`,id:i.id??rw.take(),...i}),headers:{...r,"Content-Type":`application/json`,...u},method:d||`POST`,signal:f||(c>0?e:null)},s=new Request(n,t),p=await o?.(s,t)??{...t,url:n};return await a(p.url??n,p)},{errorInstance:new ov({body:i,url:n}),timeout:c,signal:!0});s&&await s(e);let t;if(e.headers.get(`Content-Type`)?.startsWith(`application/json`))t=await e.json();else{t=await e.text();try{t=JSON.parse(t||`{}`)}catch(n){if(e.ok)throw n;t={error:t}}}if(!e.ok){if(typeof t.error?.code==`number`&&typeof t.error?.message==`string`)return t;throw new iv({body:i,details:M_(t.error)||e.statusText,headers:e.headers,status:e.status,url:n})}return t}catch(e){throw e instanceof iv||e instanceof ov?e:new iv({body:i,cause:e,url:n})}}}}function aw(e){try{let t=new URL(e),n=(()=>{if(t.username){let e=`${decodeURIComponent(t.username)}:${decodeURIComponent(t.password)}`;return t.username=``,t.password=``,{url:t.toString(),headers:{Authorization:`Basic ${btoa(e)}`}}}})();return{url:t.toString(),...n}}catch{return{url:e}}}var ow=`Ethereum Signed Message: +`;function sw(e){let t=typeof e==`string`?Lh(e):typeof e.raw==`string`?e.raw:Fh(e.raw);return Eg([Lh(`${ow}${Hm(t)}`),t])}function cw(e,t){return dg(sw(e),t)}var lw=class extends q{constructor({domain:e}){super(`Invalid domain "${M_(e)}".`,{metaMessages:[`Must be a valid EIP-712 domain.`]})}},uw=class extends q{constructor({primaryType:e,types:t}){super(`Invalid primary type \`${e}\` must be one of \`${JSON.stringify(Object.keys(t))}\`.`,{docsPath:`/api/glossary/Errors#typeddatainvalidprimarytypeerror`,metaMessages:["Check that the primary type is a key in `types`."]})}},dw=class extends q{constructor({type:e}){super(`Struct type "${e}" is invalid.`,{metaMessages:[`Struct type must not be a Solidity type.`],name:`InvalidStructTypeError`})}};function fw(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{let n={...t};for(let t of e){let{name:e,type:r}=t;r===`address`&&(n[e]=n[e].toLowerCase())}return n};return M_({domain:!i.EIP712Domain||!t?{}:a(i.EIP712Domain,t),message:(()=>{if(r!==`EIP712Domain`)return a(i[r],n)})(),primaryType:r,types:i})}function pw(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{for(let n of e){let{name:e,type:r}=n,o=t[e],s=r.match(Fg);if(s&&(typeof o==`number`||typeof o==`bigint`)){let[e,t,n]=s;J(o,{signed:t===`int`,size:Number.parseInt(n,10)/8})}if(r===`address`&&typeof o==`string`&&!Tg(o))throw new vg({address:o});let c=r.match(Pg);if(c){let[e,t]=c;if(t&&Hm(o)!==Number.parseInt(t,10))throw new lh({expectedSize:Number.parseInt(t,10),givenSize:Hm(o)})}let l=i[r];l&&(hw(r),a(l,o))}};if(i.EIP712Domain&&t){if(typeof t!=`object`)throw new lw({domain:t});a(i.EIP712Domain,t)}if(r!==`EIP712Domain`)if(i[r])a(i[r],n);else throw new uw({primaryType:r,types:i})}function mw({domain:e}){return[typeof e?.name==`string`&&{name:`name`,type:`string`},e?.version&&{name:`version`,type:`string`},(typeof e?.chainId==`number`||typeof e?.chainId==`bigint`)&&{name:`chainId`,type:`uint256`},e?.verifyingContract&&{name:`verifyingContract`,type:`address`},e?.salt&&{name:`salt`,type:`bytes32`}].filter(Boolean)}function hw(e){if(e===`address`||e===`bool`||e===`string`||e.startsWith(`bytes`)||e.startsWith(`uint`)||e.startsWith(`int`))throw new dw({type:e})}function gw(e){let{domain:t={},message:n,primaryType:r}=e,i={EIP712Domain:mw({domain:t}),...e.types};pw({domain:t,message:n,primaryType:r,types:i});let a=[`0x1901`];return t&&a.push(_w({domain:t,types:i})),r!==`EIP712Domain`&&a.push(vw({data:n,primaryType:r,types:i})),dg(Eg(a))}function _w({domain:e,types:t}){return vw({data:e,primaryType:`EIP712Domain`,types:t})}function vw({data:e,primaryType:t,types:n}){return dg(yw({data:e,primaryType:t,types:n}))}function yw({data:e,primaryType:t,types:n}){let r=[{type:`bytes32`}],i=[bw({primaryType:t,types:n})];for(let a of n[t]){let[t,o]=Cw({types:n,name:a.name,type:a.type,value:e[a.name]});r.push(t),i.push(o)}return Ig(r,i)}function bw({primaryType:e,types:t}){return dg(Nh(xw({primaryType:e,types:t})))}function xw({primaryType:e,types:t}){let n=``,r=Sw({primaryType:e,types:t});r.delete(e);let i=[e,...Array.from(r).sort()];for(let e of i)n+=`${e}(${t[e].map(({name:e,type:t})=>`${t} ${e}`).join(`,`)})`;return n}function Sw({primaryType:e,types:t},n=new Set){let r=e.match(/^\w*/u)?.[0];if(n.has(r)||t[r]===void 0)return n;n.add(r);for(let e of t[r])Sw({primaryType:e.type,types:t},n);return n}function Cw({types:e,name:t,type:n,value:r}){if(e[n]!==void 0)return[{type:`bytes32`},dg(yw({data:r,primaryType:n,types:e}))];if(n===`bytes`)return[{type:`bytes32`},dg(r)];if(n===`string`)return[{type:`bytes32`},dg(Nh(r))];if(n.lastIndexOf(`]`)===n.length-1){let i=n.slice(0,n.lastIndexOf(`[`)),a=r.map(n=>Cw({name:t,type:i,types:e,value:n}));return[{type:`bytes32`},dg(Ig(a.map(([e])=>e),a.map(([,e])=>e)))]}return[{type:n},r]}var ww=`1.2.4`,Tw=class e extends Error{constructor(t,n={}){let r=n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details,i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...i?[`Docs: https://abitype.dev${i}`]:[],...r?[`Details: ${r}`]:[],`Version: abitype@${ww}`].join(` +`);super(a),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiTypeError`}),n.cause&&(this.cause=n.cause),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.shortMessage=t}};function Ew(e,t){return e.exec(t)?.groups}var Dw=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,Ow=/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/,kw=/^\(.+?\).*?$/,Aw=/^tuple(?(\[(\d*)\])*)$/;function jw(e){let t=e.type;if(Aw.test(e.type)&&`components`in e){t=`(`;let n=e.components.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function Fw(e){return Pw.test(e)}function Iw(e){return Ew(Pw,e)}var Lw=/^event (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)$/;function Rw(e){return Lw.test(e)}function zw(e){return Ew(Lw,e)}var Bw=/^function (?[a-zA-Z$_][a-zA-Z0-9$_]*)\((?.*?)\)(?: (?external|public{1}))?(?: (?pure|view|nonpayable|payable{1}))?(?: returns\s?\((?.*?)\))?$/;function Vw(e){return Bw.test(e)}function Hw(e){return Ew(Bw,e)}var Uw=/^struct (?[a-zA-Z$_][a-zA-Z0-9$_]*) \{(?.*?)\}$/;function Ww(e){return Uw.test(e)}function Gw(e){return Ew(Uw,e)}var Kw=/^constructor\((?.*?)\)(?:\s(?payable{1}))?$/;function qw(e){return Kw.test(e)}function Jw(e){return Ew(Kw,e)}var Yw=/^fallback\(\) external(?:\s(?payable{1}))?$/;function Xw(e){return Yw.test(e)}function Zw(e){return Ew(Yw,e)}var Qw=/^receive\(\) external payable$/;function $w(e){return Qw.test(e)}var eT=new Set([`memory`,`indexed`,`storage`,`calldata`]),tT=new Set([`indexed`]),nT=new Set([`calldata`,`memory`,`storage`]),rT=class extends Tw{constructor({signature:e}){super(`Failed to parse ABI item.`,{details:`parseAbiItem(${JSON.stringify(e,null,2)})`,docsPath:`/api/human#parseabiitem-1`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiItemError`})}},iT=class extends Tw{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownTypeError`})}},aT=class extends Tw{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type "${e}" is not a valid ABI type.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSolidityTypeError`})}},oT=class extends Tw{constructor({params:e}){super(`Failed to parse ABI parameters.`,{details:`parseAbiParameters(${JSON.stringify(e,null,2)})`,docsPath:`/api/human#parseabiparameters-1`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiParametersError`})}},sT=class extends Tw{constructor({param:e}){super(`Invalid ABI parameter.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParameterError`})}},cT=class extends Tw{constructor({param:e,name:t}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`"${t}" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SolidityProtectedKeywordError`})}},lT=class extends Tw{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidModifierError`})}},uT=class extends Tw{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier "${n}" not allowed${t?` in "${t}" type`:``}.`,`Data location can only be specified for array, struct, or mapping types, but "${n}" was given.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidFunctionModifierError`})}},dT=class extends Tw{constructor({abiParameter:e}){super(`Invalid ABI parameter.`,{details:JSON.stringify(e,null,2),metaMessages:[`ABI parameter type is invalid.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiTypeParameterError`})}},fT=class extends Tw{constructor({signature:e,type:t}){super(`Invalid ${t} signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidSignatureError`})}},pT=class extends Tw{constructor({signature:e}){super(`Unknown signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSignatureError`})}},mT=class extends Tw{constructor({signature:e}){super(`Invalid struct signature.`,{details:e,metaMessages:[`No properties exist.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidStructSignatureError`})}},hT=class extends Tw{constructor({type:e}){super(`Circular reference detected.`,{metaMessages:[`Struct "${e}" is a circular reference.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`CircularReferenceError`})}},gT=class extends Tw{constructor({current:e,depth:t}){super(`Unbalanced parentheses.`,{metaMessages:[`"${e.trim()}" has too many ${t>0?`opening`:`closing`} parentheses.`],details:`Depth "${t}"`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParenthesisError`})}};function _T(e,t,n){let r=``;if(n)for(let e of Object.entries(n)){if(!e)continue;let t=``;for(let n of e[1])t+=`[${n.type}${n.name?`:${n.name}`:``}]`;r+=`(${e[0]}{${t}})`}return t?`${t}:${e}${r}`:`${e}${r}`}var vT=new Map([[`address`,{type:`address`}],[`bool`,{type:`bool`}],[`bytes`,{type:`bytes`}],[`bytes32`,{type:`bytes32`}],[`int`,{type:`int256`}],[`int256`,{type:`int256`}],[`string`,{type:`string`}],[`uint`,{type:`uint256`}],[`uint8`,{type:`uint8`}],[`uint16`,{type:`uint16`}],[`uint24`,{type:`uint24`}],[`uint32`,{type:`uint32`}],[`uint64`,{type:`uint64`}],[`uint96`,{type:`uint96`}],[`uint112`,{type:`uint112`}],[`uint160`,{type:`uint160`}],[`uint192`,{type:`uint192`}],[`uint256`,{type:`uint256`}],[`address owner`,{type:`address`,name:`owner`}],[`address to`,{type:`address`,name:`to`}],[`bool approved`,{type:`bool`,name:`approved`}],[`bytes _data`,{type:`bytes`,name:`_data`}],[`bytes data`,{type:`bytes`,name:`data`}],[`bytes signature`,{type:`bytes`,name:`signature`}],[`bytes32 hash`,{type:`bytes32`,name:`hash`}],[`bytes32 r`,{type:`bytes32`,name:`r`}],[`bytes32 root`,{type:`bytes32`,name:`root`}],[`bytes32 s`,{type:`bytes32`,name:`s`}],[`string name`,{type:`string`,name:`name`}],[`string symbol`,{type:`string`,name:`symbol`}],[`string tokenURI`,{type:`string`,name:`tokenURI`}],[`uint tokenId`,{type:`uint256`,name:`tokenId`}],[`uint8 v`,{type:`uint8`,name:`v`}],[`uint256 balance`,{type:`uint256`,name:`balance`}],[`uint256 tokenId`,{type:`uint256`,name:`tokenId`}],[`uint256 value`,{type:`uint256`,name:`value`}],[`event:address indexed from`,{type:`address`,name:`from`,indexed:!0}],[`event:address indexed to`,{type:`address`,name:`to`,indexed:!0}],[`event:uint indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}],[`event:uint256 indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}]]);function yT(e,t={}){if(Vw(e))return bT(e,t);if(Rw(e))return xT(e,t);if(Fw(e))return ST(e,t);if(qw(e))return CT(e,t);if(Xw(e))return wT(e);if($w(e))return{type:`receive`,stateMutability:`payable`};throw new pT({signature:e})}function bT(e,t={}){let n=Hw(e);if(!n)throw new fT({signature:e,type:`function`});let r=kT(n.parameters),i=[],a=r.length;for(let e=0;e[a-zA-Z$_][a-zA-Z0-9$_]*(?:\spayable)?)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,ET=/^\((?.+?)\)(?(?:\[\d*?\])+?)?(?:\s(?calldata|indexed|memory|storage{1}))?(?:\s(?[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,DT=/^u?int$/;function OT(e,t){let n=_T(e,t?.type,t?.structs);if(vT.has(n))return vT.get(n);let r=kw.test(e),i=Ew(r?ET:TT,e);if(!i)throw new sT({param:e});if(i.name&&MT(i.name))throw new cT({param:e,name:i.name});let a=i.name?{name:i.name}:{},o=i.modifier===`indexed`?{indexed:!0}:{},s=t?.structs??{},c,l={};if(r){c=`tuple`;let e=kT(i.type),t=[],n=e.length;for(let r=0;r[a-zA-Z$_][a-zA-Z0-9$_]*)(?(?:\[\d*?\])+?)?$/;function IT(e=[],t={},n=new Set){let r=[],i=e.length;for(let a=0;athis.maxSize){let e=this.keys().next().value;e&&this.delete(e)}return this}}(8192)}.checksum,BT=class extends ae{constructor(e,t){super(),this.finished=!1,this.destroyed=!1,ie(e);let n=a(t);if(this.iHash=e.create(),typeof this.iHash.update!=`function`)throw Error(`Expected instance of class which extends utils.Hash`);this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let i=this.blockLen,o=new Uint8Array(i);o.set(n.length>i?e.create().update(n).digest():n);for(let e=0;enew BT(e,t).update(n).digest();VT.create=(e,t)=>new BT(e,t);function HT(e,t={}){let{as:n=typeof e==`string`?`Hex`:`Bytes`}=t,r=lg(Jb(e));return n===`Bytes`?r:_x(r)}var UT=/^0x[a-fA-F0-9]{40}$/;function WT(e,t={}){let{strict:n=!0}=t;if(!UT.test(e))throw new qT({address:e,cause:new JT});if(n){if(e.toLowerCase()===e)return;if(GT(e)!==e)throw new qT({address:e,cause:new YT})}}function GT(e){if(zT.has(e))return zT.get(e);WT(e,{strict:!1});let t=e.substring(2).toLowerCase(),n=HT(Zb(t),{as:`Bytes`}),r=t.split(``);for(let e=0;e<40;e+=2)n[e>>1]>>4>=8&&r[e]&&(r[e]=r[e].toUpperCase()),(n[e>>1]&15)>=8&&r[e+1]&&(r[e+1]=r[e+1].toUpperCase());let i=`0x${r.join(``)}`;return zT.set(e,i),i}function KT(e,t={}){let{strict:n=!0}=t??{};try{return WT(e,{strict:n}),!0}catch{return!1}}var qT=class extends Y{constructor({address:e,cause:t}){super(`Address "${e}" is invalid.`,{cause:t}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidAddressError`})}},JT=class extends Y{constructor(){super(`Address is not a 20 byte (40 hexadecimal character) value.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidInputError`})}},YT=class extends Y{constructor(){super(`Address does not match its checksum counterpart.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidChecksumError`})}},XT=/^(.*)\[([0-9]*)\]$/,ZT=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,QT=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;2n**(8n-1n)-1n,2n**(16n-1n)-1n,2n**(24n-1n)-1n,2n**(32n-1n)-1n,2n**(40n-1n)-1n,2n**(48n-1n)-1n,2n**(56n-1n)-1n,2n**(64n-1n)-1n,2n**(72n-1n)-1n,2n**(80n-1n)-1n,2n**(88n-1n)-1n,2n**(96n-1n)-1n,2n**(104n-1n)-1n,2n**(112n-1n)-1n,2n**(120n-1n)-1n,2n**(128n-1n)-1n,2n**(136n-1n)-1n,2n**(144n-1n)-1n,2n**(152n-1n)-1n,2n**(160n-1n)-1n,2n**(168n-1n)-1n,2n**(176n-1n)-1n,2n**(184n-1n)-1n,2n**(192n-1n)-1n,2n**(200n-1n)-1n,2n**(208n-1n)-1n,2n**(216n-1n)-1n,2n**(224n-1n)-1n,2n**(232n-1n)-1n,2n**(240n-1n)-1n,2n**(248n-1n)-1n,2n**(256n-1n)-1n,-(2n**(8n-1n)),-(2n**(16n-1n)),-(2n**(24n-1n)),-(2n**(32n-1n)),-(2n**(40n-1n)),-(2n**(48n-1n)),-(2n**(56n-1n)),-(2n**(64n-1n)),-(2n**(72n-1n)),-(2n**(80n-1n)),-(2n**(88n-1n)),-(2n**(96n-1n)),-(2n**(104n-1n)),-(2n**(112n-1n)),-(2n**(120n-1n)),-(2n**(128n-1n)),-(2n**(136n-1n)),-(2n**(144n-1n)),-(2n**(152n-1n)),-(2n**(160n-1n)),-(2n**(168n-1n)),-(2n**(176n-1n)),-(2n**(184n-1n)),-(2n**(192n-1n)),-(2n**(200n-1n)),-(2n**(208n-1n)),-(2n**(216n-1n)),-(2n**(224n-1n)),-(2n**(232n-1n)),-(2n**(240n-1n)),-(2n**(248n-1n)),-(2n**(256n-1n));var $T=2n**256n-1n;function eE(e,t,n){let{checksumAddress:r,staticPosition:i}=n,a=bE(t.type);if(a){let[n,o]=a;return iE(e,{...t,type:o},{checksumAddress:r,length:n,staticPosition:i})}if(t.type===`tuple`)return cE(e,t,{checksumAddress:r,staticPosition:i});if(t.type===`address`)return rE(e,{checksum:r});if(t.type===`bool`)return aE(e);if(t.type.startsWith(`bytes`))return oE(e,t,{staticPosition:i});if(t.type.startsWith(`uint`)||t.type.startsWith(`int`))return sE(e,t);if(t.type===`string`)return lE(e,{staticPosition:i});throw new LE(t.type)}var tE=32,nE=32;function rE(e,t={}){let{checksum:n=!1}=t;return[(e=>n?GT(e):e)(_x(ex(e.readBytes(32),-20))),32]}function iE(e,t,n){let{checksumAddress:r,length:i,staticPosition:a}=n;if(!i){let n=a+rx(e.readBytes(nE)),i=n+tE;e.setPosition(n);let o=rx(e.readBytes(tE)),s=xE(t),c=0,l=[];for(let n=0;n48?tx(i,{signed:n}):rx(i,{signed:n}),32]}function cE(e,t,n){let{checksumAddress:r,staticPosition:i}=n,a=t.components.length===0||t.components.some(({name:e})=>!e),o=a?[]:{},s=0;if(xE(t)){let n=i+rx(e.readBytes(nE));for(let i=0;i0?mx(t,e):t}}if(o)return{dynamic:!0,encoded:e}}return{dynamic:!1,encoded:mx(...s.map(({encoded:e})=>e))}}function hE(e,{type:t}){let[,n]=t.split(`bytes`),r=Cx(e);if(!n){let t=e;return r%32!=0&&(t=xx(t,Math.ceil((e.length-2)/2/32)*32)),{dynamic:!0,encoded:mx(bx(vx(r,{size:32})),t)}}if(r!==Number.parseInt(n,10))throw new PE({expectedSize:Number.parseInt(n,10),value:e});return{dynamic:!1,encoded:xx(e)}}function gE(e){if(typeof e!=`boolean`)throw new Y(`Invalid boolean value: "${e}" (type: ${typeof e}). Expected: \`true\` or \`false\`.`);return{dynamic:!1,encoded:bx(gx(e))}}function _E(e,{signed:t,size:n}){if(typeof n==`number`){let r=2n**(BigInt(n)-(t?1n:0n))-1n,i=t?-r-1n:0n;if(e>r||ee))}}function bE(e){let t=e.match(/^(.*)\[(\d+)?\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}function xE(e){let{type:t}=e;if(t===`string`||t===`bytes`||t.endsWith(`[]`))return!0;if(t===`tuple`)return e.components?.some(xE);let n=bE(e.type);return!!(n&&xE({...e,type:n[1]}))}var SE={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:1/0,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new EE({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new TE({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new wE({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new wE({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let n=t??this.position;return this.assertPosition(n+e-1),this.bytes.subarray(n,n+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let n=this.inspectBytes(e);return this.position+=t??e,n},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===1/0)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}};function CE(e,{recursiveReadLimit:t=8192}={}){let n=Object.create(SE);return n.bytes=e,n.dataView=new DataView(e.buffer,e.byteOffset,e.byteLength),n.positionReadCount=new Map,n.recursiveReadLimit=t,n}var wE=class extends Y{constructor({offset:e}){super(`Offset \`${e}\` cannot be negative.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.NegativeOffsetError`})}},TE=class extends Y{constructor({length:e,position:t}){super(`Position \`${t}\` is out of bounds (\`0 < position < ${e}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.PositionOutOfBoundsError`})}},EE=class extends Y{constructor({count:e,limit:t}){super(`Recursive read limit of \`${t}\` exceeded (recursive read count: \`${e}\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.RecursiveReadLimitExceededError`})}};function DE(e,t,n={}){let{as:r=`Array`,checksumAddress:i=!1}=n,a=typeof t==`string`?Xb(t):t,o=CE(a);if($b(a)===0&&e.length>0)throw new ME;if($b(a)&&$b(a)<32)throw new jE({data:typeof t==`string`?t:_x(t),parameters:e,size:$b(a)});let s=0,c=r===`Array`?[]:{};for(let t=0;t=RE?n:t+n}function KE(e,t,n){let r=e;for(;t-- >RE;)r*=r,r%=n;return r}function qE(e,t){if(e===RE)throw Error(`invert: expected non-zero number`);if(t<=RE)throw Error(`invert: expected positive modulus, got `+t);let n=GE(e,t),r=t,i=RE,a=zE,o=zE,s=RE;for(;n!==RE;){let e=r/n,t=r%n,c=i-o*e,l=a-s*e;r=n,n=t,i=o,a=s,o=c,s=l}if(r!==zE)throw Error(`invert: does not exist`);return GE(i,t)}function JE(e,t){let n=(e.ORDER+zE)/HE,r=e.pow(t,n);if(!e.eql(e.sqr(r),t))throw Error(`Cannot find square root`);return r}function YE(e,t){let n=(e.ORDER-UE)/WE,r=e.mul(t,BE),i=e.pow(r,n),a=e.mul(t,i),o=e.mul(e.mul(a,BE),i),s=e.mul(a,e.sub(o,e.ONE));if(!e.eql(e.sqr(s),t))throw Error(`Cannot find square root`);return s}function XE(e){if(e1e3)throw Error(`Cannot find square root: probably non-prime P`);if(n===1)return JE;let a=i.pow(r,t),o=(t+zE)/BE;return function(e,r){if(e.is0(r))return r;if(nD(e,r)!==1)throw Error(`Cannot find square root`);let i=n,s=e.mul(e.ONE,a),c=e.pow(r,t),l=e.pow(r,o);for(;!e.eql(c,e.ONE);){if(e.is0(c))return e.ZERO;let t=1,n=e.sqr(c);for(;!e.eql(n,e.ONE);)if(t++,n=e.sqr(n),t===i)throw Error(`Cannot find square root`);let r=zE<(e[t]=`function`,e),{ORDER:`bigint`,MASK:`bigint`,BYTES:`isSafeInteger`,BITS:`isSafeInteger`}))}function eD(e,t,n){if(nRE;)n&zE&&(r=e.mul(r,i)),i=e.sqr(i),n>>=zE;return r}function tD(e,t,n=!1){let r=Array(t.length).fill(n?e.ZERO:void 0),i=t.reduce((t,n,i)=>e.is0(n)?t:(r[i]=t,e.mul(t,n)),e.ONE),a=e.inv(i);return t.reduceRight((t,n,i)=>e.is0(n)?t:(r[i]=e.mul(t,r[i]),e.mul(t,n)),a),r}function nD(e,t){let n=(e.ORDER-zE)/BE,r=e.pow(t,n),i=e.eql(r,e.ONE),a=e.eql(r,e.ZERO),o=e.eql(r,e.neg(e.ONE));if(!i&&!a&&!o)throw Error(`invalid Legendre symbol result`);return i?1:a?0:-1}function rD(e,t){t!==void 0&&m(t);let n=t===void 0?e.toString(2).length:t;return{nBitLength:n,nByteLength:Math.ceil(n/8)}}function iD(e,t,n=!1,r={}){if(e<=RE)throw Error(`invalid field: expected ORDER > 0, got `+e);let{nBitLength:i,nByteLength:a}=rD(e,t);if(a>2048)throw Error(`invalid field: expected ORDER of <= 2048 bytes`);let o,s=Object.freeze({ORDER:e,isLE:n,BITS:i,BYTES:a,MASK:_(i),ZERO:RE,ONE:zE,create:t=>GE(t,e),isValid:t=>{if(typeof t!=`bigint`)throw Error(`invalid field element: expected bigint, got `+typeof t);return RE<=t&&te===RE,isOdd:e=>(e&zE)===zE,neg:t=>GE(-t,e),eql:(e,t)=>e===t,sqr:t=>GE(t*t,e),add:(t,n)=>GE(t+n,e),sub:(t,n)=>GE(t-n,e),mul:(t,n)=>GE(t*n,e),pow:(e,t)=>eD(s,e,t),div:(t,n)=>GE(t*qE(n,e),e),sqrN:e=>e*e,addN:(e,t)=>e+t,subN:(e,t)=>e-t,mulN:(e,t)=>e*t,inv:t=>qE(t,e),sqrt:r.sqrt||(t=>(o||=ZE(e),o(s,t))),toBytes:e=>n?g(e,a):S(e,a),fromBytes:e=>{if(e.length!==a)throw Error(`Field.fromBytes: expected `+a+` bytes, got `+e.length);return n?y(e):A(e)},invertBatch:e=>tD(s,e),cmov:(e,t,n)=>n?t:e});return Object.freeze(s)}function aD(e){if(typeof e!=`bigint`)throw Error(`field order must be bigint`);let t=e.toString(2).length;return Math.ceil(t/8)}function oD(e){let t=aD(e);return t+Math.ceil(t/2)}function sD(e,t,n=!1){let r=e.length,i=aD(t),a=oD(t);if(r<16||r1024)throw Error(`expected `+a+`-1024 bytes of input, got `+r);let o=GE(n?y(e):A(e),t-zE)+zE;return n?g(o,i):S(o,i)}var cD=BigInt(0),lD=BigInt(1);function uD(e,t){let n=t.negate();return e?n:t}function dD(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw Error(`invalid window size, expected [1..`+t+`], got W=`+e)}function fD(e,t){dD(e,t);let n=Math.ceil(t/e)+1,r=2**(e-1),i=2**e;return{windows:n,windowSize:r,mask:_(e),maxNumber:i,shiftBy:BigInt(e)}}function pD(e,t,n){let{windowSize:r,mask:i,maxNumber:a,shiftBy:o}=n,s=Number(e&i),c=e>>o;s>r&&(s-=a,c+=lD);let l=t*r,u=l+Math.abs(s)-1,d=s===0,f=s<0,p=t%2!=0;return{nextN:c,offset:u,isZero:d,isNeg:f,isNegF:p,offsetF:l}}function mD(e,t){if(!Array.isArray(e))throw Error(`array expected`);e.forEach((e,n)=>{if(!(e instanceof t))throw Error(`invalid point at index `+n)})}function hD(e,t){if(!Array.isArray(e))throw Error(`array of scalars expected`);e.forEach((e,n)=>{if(!t.isValid(e))throw Error(`invalid scalar at index `+n)})}var gD=new WeakMap,_D=new WeakMap;function vD(e){return _D.get(e)||1}function yD(e,t){return{constTimeNegate:uD,hasPrecomputes(e){return vD(e)!==1},unsafeLadder(t,n,r=e.ZERO){let i=t;for(;n>cD;)n&lD&&(r=r.add(i)),i=i.double(),n>>=lD;return r},precomputeWindow(e,n){let{windows:r,windowSize:i}=fD(n,t),a=[],o=e,s=o;for(let e=0;e12?c=s-3:s>4?c=s-2:s>0&&(c=2);let l=_(c),u=Array(Number(l)+1).fill(o),d=Math.floor((t.BITS-1)/c)*c,f=o;for(let e=d;e>=0;e-=c){u.fill(o);for(let t=0;t>BigInt(e)&l);u[a]=u[a].add(n[t])}let t=o;for(let e=u.length-1,n=o;e>0;e--)n=n.add(u[e]),t=t.add(n);if(f=f.add(t),e!==0)for(let e=0;e{let{Err:n}=wD;if(e<0||e>256)throw new n(`tlv.encode: wrong tag`);if(t.length&1)throw new n(`tlv.encode: unpadded data`);let r=t.length/2,i=M(r);if(i.length/2&128)throw new n(`tlv.encode: long form length too big`);let a=r>127?M(i.length/2|128):``;return M(e)+a+i+t},decode(e,t){let{Err:n}=wD,r=0;if(e<0||e>256)throw new n(`tlv.encode: wrong tag`);if(t.length<2||t[r++]!==e)throw new n(`tlv.decode: wrong tlv`);let i=t[r++],a=!!(i&128),o=0;if(!a)o=i;else{let e=i&127;if(!e)throw new n(`tlv.decode(long): indefinite length not supported`);if(e>4)throw new n(`tlv.decode(long): byte length is too big`);let a=t.subarray(r,r+e);if(a.length!==e)throw new n(`tlv.decode: length bytes not complete`);if(a[0]===0)throw new n(`tlv.decode(long): zero leftmost byte`);for(let e of a)o=o<<8|e;if(r+=e,o<128)throw new n(`tlv.decode(long): not minimal encoding`)}let s=t.subarray(r,r+o);if(s.length!==o)throw new n(`tlv.decode: wrong value length`);return{v:s,l:t.subarray(r+o)}}},_int:{encode(e){let{Err:t}=wD;if(e{let i=t.toAffine();return D(Uint8Array.from([4]),n.toBytes(i.x),n.toBytes(i.y))}),a=t.fromBytes||(e=>{let t=e.subarray(1);return{x:n.fromBytes(t.subarray(0,n.BYTES)),y:n.fromBytes(t.subarray(n.BYTES,2*n.BYTES))}});function o(e){let{a:r,b:i}=t,a=n.sqr(e),o=n.mul(a,e);return n.add(n.add(o,n.mul(e,r)),i)}function s(e,t){let r=n.sqr(t),i=o(e);return n.eql(r,i)}if(!s(t.Gx,t.Gy))throw Error(`bad curve params: generator point`);let c=n.mul(n.pow(t.a,kD),AD),l=n.mul(n.sqr(t.b),BigInt(27));if(n.is0(n.add(c,l)))throw Error(`bad curve params: a or b`);function u(e){return O(e,DD,t.n)}function d(e){let{allowedPrivateKeyLengths:n,nByteLength:r,wrapPrivateKey:i,n:a}=t;if(n&&typeof e!=`bigint`){if(ee(e)&&(e=ne(e)),typeof e!=`string`||!n.includes(e.length))throw Error(`invalid private key`);e=e.padStart(r*2,`0`)}let o;try{o=typeof e==`bigint`?e:A(b(`private key`,e,r))}catch{throw Error(`invalid private key, expected hex or `+r+` bytes, got `+typeof e)}return i&&(o=GE(o,a)),j(`private key`,o,DD,a),o}function f(e){if(!(e instanceof h))throw Error(`ProjectivePoint expected`)}let p=C((e,t)=>{let{px:r,py:i,pz:a}=e;if(n.eql(a,n.ONE))return{x:r,y:i};let o=e.is0();t??=o?n.ONE:n.inv(a);let s=n.mul(r,t),c=n.mul(i,t),l=n.mul(a,t);if(o)return{x:n.ZERO,y:n.ZERO};if(!n.eql(l,n.ONE))throw Error(`invZ was invalid`);return{x:s,y:c}}),m=C(e=>{if(e.is0()){if(t.allowInfinityPoint&&!n.is0(e.py))return;throw Error(`bad point: ZERO`)}let{x:r,y:i}=e.toAffine();if(!n.isValid(r)||!n.isValid(i))throw Error(`bad point: x or y not FE`);if(!s(r,i))throw Error(`bad point: equation left != right`);if(!e.isTorsionFree())throw Error(`bad point: not in prime-order subgroup`);return!0});class h{constructor(e,t,r){if(e==null||!n.isValid(e))throw Error(`x required`);if(t==null||!n.isValid(t)||n.is0(t))throw Error(`y required`);if(r==null||!n.isValid(r))throw Error(`z required`);this.px=e,this.py=t,this.pz=r,Object.freeze(this)}static fromAffine(e){let{x:t,y:r}=e||{};if(!e||!n.isValid(t)||!n.isValid(r))throw Error(`invalid affine point`);if(e instanceof h)throw Error(`projective point not allowed`);let i=e=>n.eql(e,n.ZERO);return i(t)&&i(r)?h.ZERO:new h(t,r,n.ONE)}get x(){return this.toAffine().x}get y(){return this.toAffine().y}static normalizeZ(e){let t=tD(n,e.map(e=>e.pz));return e.map((e,n)=>e.toAffine(t[n])).map(h.fromAffine)}static fromHex(e){let t=h.fromAffine(a(b(`pointHex`,e)));return t.assertValidity(),t}static fromPrivateKey(e){return h.BASE.multiply(d(e))}static msm(e,t){return bD(h,r,e,t)}_setWindowSize(e){v.setWindowSize(this,e)}assertValidity(){m(this)}hasEvenY(){let{y:e}=this.toAffine();if(n.isOdd)return!n.isOdd(e);throw Error(`Field doesn't support isOdd`)}equals(e){f(e);let{px:t,py:r,pz:i}=this,{px:a,py:o,pz:s}=e,c=n.eql(n.mul(t,s),n.mul(a,i)),l=n.eql(n.mul(r,s),n.mul(o,i));return c&&l}negate(){return new h(this.px,n.neg(this.py),this.pz)}double(){let{a:e,b:r}=t,i=n.mul(r,kD),{px:a,py:o,pz:s}=this,c=n.ZERO,l=n.ZERO,u=n.ZERO,d=n.mul(a,a),f=n.mul(o,o),p=n.mul(s,s),m=n.mul(a,o);return m=n.add(m,m),u=n.mul(a,s),u=n.add(u,u),c=n.mul(e,u),l=n.mul(i,p),l=n.add(c,l),c=n.sub(f,l),l=n.add(f,l),l=n.mul(c,l),c=n.mul(m,c),u=n.mul(i,u),p=n.mul(e,p),m=n.sub(d,p),m=n.mul(e,m),m=n.add(m,u),u=n.add(d,d),d=n.add(u,d),d=n.add(d,p),d=n.mul(d,m),l=n.add(l,d),p=n.mul(o,s),p=n.add(p,p),d=n.mul(p,m),c=n.sub(c,d),u=n.mul(p,f),u=n.add(u,u),u=n.add(u,u),new h(c,l,u)}add(e){f(e);let{px:r,py:i,pz:a}=this,{px:o,py:s,pz:c}=e,l=n.ZERO,u=n.ZERO,d=n.ZERO,p=t.a,m=n.mul(t.b,kD),g=n.mul(r,o),_=n.mul(i,s),v=n.mul(a,c),y=n.add(r,i),b=n.add(o,s);y=n.mul(y,b),b=n.add(g,_),y=n.sub(y,b),b=n.add(r,a);let x=n.add(o,c);return b=n.mul(b,x),x=n.add(g,v),b=n.sub(b,x),x=n.add(i,a),l=n.add(s,c),x=n.mul(x,l),l=n.add(_,v),x=n.sub(x,l),d=n.mul(p,b),l=n.mul(m,v),d=n.add(l,d),l=n.sub(_,d),d=n.add(_,d),u=n.mul(l,d),_=n.add(g,g),_=n.add(_,g),v=n.mul(p,v),b=n.mul(m,b),_=n.add(_,v),v=n.sub(g,v),v=n.mul(p,v),b=n.add(b,v),g=n.mul(_,b),u=n.add(u,g),g=n.mul(x,b),l=n.mul(y,l),l=n.sub(l,g),g=n.mul(y,_),d=n.mul(x,d),d=n.add(d,g),new h(l,u,d)}subtract(e){return this.add(e.negate())}is0(){return this.equals(h.ZERO)}wNAF(e){return v.wNAFCached(this,e,h.normalizeZ)}multiplyUnsafe(e){let{endo:r,n:i}=t;j(`scalar`,e,ED,i);let a=h.ZERO;if(e===ED)return a;if(this.is0()||e===DD)return this;if(!r||v.hasPrecomputes(this))return v.wNAFCachedUnsafe(this,e,h.normalizeZ);let{k1neg:o,k1:s,k2neg:c,k2:l}=r.splitScalar(e),u=a,d=a,f=this;for(;s>ED||l>ED;)s&DD&&(u=u.add(f)),l&DD&&(d=d.add(f)),f=f.double(),s>>=DD,l>>=DD;return o&&(u=u.negate()),c&&(d=d.negate()),d=new h(n.mul(d.px,r.beta),d.py,d.pz),u.add(d)}multiply(e){let{endo:r,n:i}=t;j(`scalar`,e,DD,i);let a,o;if(r){let{k1neg:t,k1:i,k2neg:s,k2:c}=r.splitScalar(e),{p:l,f:u}=this.wNAF(i),{p:d,f}=this.wNAF(c);l=v.constTimeNegate(t,l),d=v.constTimeNegate(s,d),d=new h(n.mul(d.px,r.beta),d.py,d.pz),a=l.add(d),o=u.add(f)}else{let{p:t,f:n}=this.wNAF(e);a=t,o=n}return h.normalizeZ([a,o])[0]}multiplyAndAddUnsafe(e,t,n){let r=h.BASE,i=(e,t)=>t===ED||t===DD||!e.equals(r)?e.multiplyUnsafe(t):e.multiply(t),a=i(this,t).add(i(e,n));return a.is0()?void 0:a}toAffine(e){return p(this,e)}isTorsionFree(){let{h:e,isTorsionFree:n}=t;if(e===DD)return!0;if(n)return n(h,this);throw Error(`isTorsionFree() has not been declared for the elliptic curve`)}clearCofactor(){let{h:e,clearCofactor:n}=t;return e===DD?this:n?n(h,this):this.multiplyUnsafe(t.h)}toRawBytes(e=!0){return te(`isCompressed`,e),this.assertValidity(),i(h,this,e)}toHex(e=!0){return te(`isCompressed`,e),ne(this.toRawBytes(e))}}h.BASE=new h(t.Gx,t.Gy,n.ONE),h.ZERO=new h(n.ZERO,n.ONE,n.ZERO);let{endo:g,nBitLength:_}=t,v=yD(h,g?Math.ceil(_/2):_);return{CURVE:t,ProjectivePoint:h,normPrivateKeyToScalar:d,weierstrassEquation:o,isWithinCurveOrder:u}}function MD(e){let t=xD(e);return v(t,{hash:`hash`,hmac:`function`,randomBytes:`function`},{bits2int:`function`,bits2int_modN:`function`,lowS:`boolean`}),Object.freeze({lowS:!0,...t})}function ND(e){let t=MD(e),{Fp:n,n:r,nByteLength:i,nBitLength:a}=t,o=n.BYTES+1,s=2*n.BYTES+1;function c(e){return GE(e,r)}function l(e){return qE(e,r)}let{ProjectivePoint:u,normPrivateKeyToScalar:d,weierstrassEquation:f,isWithinCurveOrder:p}=jD({...t,toBytes(e,t,r){let i=t.toAffine(),a=n.toBytes(i.x),o=D;return te(`isCompressed`,r),r?o(Uint8Array.from([t.hasEvenY()?2:3]),a):o(Uint8Array.from([4]),a,n.toBytes(i.y))},fromBytes(e){let t=e.length,r=e[0],i=e.subarray(1);if(t===o&&(r===2||r===3)){let e=A(i);if(!O(e,DD,n.ORDER))throw Error(`Point is not on curve`);let t=f(e),a;try{a=n.sqrt(t)}catch(e){let t=e instanceof Error?`: `+e.message:``;throw Error(`Point is not on curve`+t)}let o=(a&DD)===DD;return(r&1)==1!==o&&(a=n.neg(a)),{x:e,y:a}}else if(t===s&&r===4)return{x:n.fromBytes(i.subarray(0,n.BYTES)),y:n.fromBytes(i.subarray(n.BYTES,2*n.BYTES))};else{let e=o,n=s;throw Error(`invalid Point, expected length of `+e+`, or uncompressed `+n+`, got `+t)}}});function m(e){return e>r>>DD}function h(e){return m(e)?c(-e):e}let g=(e,t,n)=>A(e.slice(t,n));class v{constructor(e,t,n){j(`r`,e,DD,r),j(`s`,t,DD,r),this.r=e,this.s=t,n!=null&&(this.recovery=n),Object.freeze(this)}static fromCompact(e){let t=i;return e=b(`compactSignature`,e,t*2),new v(g(e,0,t),g(e,t,2*t))}static fromDER(e){let{r:t,s:n}=wD.toSig(b(`DER`,e));return new v(t,n)}assertValidity(){}addRecoveryBit(e){return new v(this.r,this.s,e)}recoverPublicKey(e){let{r,s:i,recovery:a}=this,o=ne(b(`msgHash`,e));if(a==null||![0,1,2,3].includes(a))throw Error(`recovery id invalid`);let s=a===2||a===3?r+t.n:r;if(s>=n.ORDER)throw Error(`recovery id 2 or 3 invalid`);let d=a&1?`03`:`02`,f=u.fromHex(d+TD(s,n.BYTES)),p=l(s),m=c(-o*p),h=c(i*p),g=u.BASE.multiplyAndAddUnsafe(f,m,h);if(!g)throw Error(`point at infinify`);return g.assertValidity(),g}hasHighS(){return m(this.s)}normalizeS(){return this.hasHighS()?new v(this.r,c(-this.s),this.recovery):this}toDERRawBytes(){return x(this.toDERHex())}toDERHex(){return wD.hexFromSig(this)}toCompactRawBytes(){return x(this.toCompactHex())}toCompactHex(){let e=i;return TD(this.r,e)+TD(this.s,e)}}let y={isValidPrivateKey(e){try{return d(e),!0}catch{return!1}},normPrivateKeyToScalar:d,randomPrivateKey:()=>{let e=oD(t.n);return sD(t.randomBytes(e),t.n)},precompute(e=8,t=u.BASE){return t._setWindowSize(e),t.multiply(BigInt(3)),t}};function C(e,t=!0){return u.fromPrivateKey(e).toRawBytes(t)}function w(e){if(typeof e==`bigint`)return!1;if(e instanceof u)return!0;let r=b(`key`,e).length,a=n.BYTES,o=a+1,s=2*a+1;if(!(t.allowedPrivateKeyLengths||i===o))return r===o||r===s}function T(e,t,n=!0){if(w(e)===!0)throw Error(`first arg must be private key`);if(w(t)===!1)throw Error(`second arg must be public key`);return u.fromHex(t).multiply(d(e)).toRawBytes(n)}let E=t.bits2int||function(e){if(e.length>8192)throw Error(`input is too large`);let t=A(e),n=e.length*8-a;return n>0?t>>BigInt(n):t},ne=t.bits2int_modN||function(e){return c(E(e))},k=_(a);function M(e){return j(`num < 2^`+a,e,ED,k),S(e,i)}function ie(e,r,i=ae){if([`recovered`,`canonical`].some(e=>e in i))throw Error(`sign() legacy options not supported`);let{hash:a,randomBytes:o}=t,{lowS:s,prehash:f,extraEntropy:g}=i;s??=!0,e=b(`msgHash`,e),SD(i),f&&(e=b(`prehashed msgHash`,a(e)));let _=ne(e),y=d(r),x=[M(y),M(_)];if(g!=null&&g!==!1){let e=g===!0?o(n.BYTES):g;x.push(b(`extraEntropy`,e))}let S=D(...x),C=_;function w(e){let t=E(e);if(!p(t))return;let n=l(t),r=u.BASE.multiply(t).toAffine(),i=c(r.x);if(i===ED)return;let a=c(n*c(C+i*y));if(a===ED)return;let o=(r.x===i?0:2)|Number(r.y&DD),d=a;return s&&m(a)&&(d=h(a),o^=1),new v(i,d,o)}return{seed:S,k2sig:w}}let ae={lowS:t.lowS,prehash:!1},oe={lowS:t.lowS,prehash:!1};function se(e,n,r=ae){let{seed:i,k2sig:a}=ie(e,n,r),o=t;return re(o.hash.outputLen,o.nByteLength,o.hmac)(i,a)}u.BASE._setWindowSize(8);function ce(e,n,r,i=oe){let a=e;n=b(`msgHash`,n),r=b(`publicKey`,r);let{lowS:o,prehash:s,format:d}=i;if(SD(i),`strict`in i)throw Error(`options.strict was renamed to lowS`);if(d!==void 0&&d!==`compact`&&d!==`der`)throw Error(`format must be compact or der`);let f=typeof a==`string`||ee(a),p=!f&&!d&&typeof a==`object`&&!!a&&typeof a.r==`bigint`&&typeof a.s==`bigint`;if(!f&&!p)throw Error(`invalid signature, expected Uint8Array, hex string or Signature instance`);let m,h;try{if(p&&(m=new v(a.r,a.s)),f){try{d!==`compact`&&(m=v.fromDER(a))}catch(e){if(!(e instanceof wD.Err))throw e}!m&&d!==`der`&&(m=v.fromCompact(a))}h=u.fromHex(r)}catch{return!1}if(!m||o&&m.hasHighS())return!1;s&&(n=t.hash(n));let{r:g,s:_}=m,y=ne(n),x=l(_),S=c(y*x),C=c(g*x),w=u.BASE.multiplyAndAddUnsafe(h,S,C)?.toAffine();return w?c(w.x)===g:!1}return{CURVE:t,getPublicKey:C,getSharedSecret:T,sign:se,verify:ce,ProjectivePoint:u,Signature:v,utils:y}}function PD(e,t){let n=e.ORDER,r=ED;for(let e=n-DD;e%OD===ED;e/=OD)r+=DD;let i=r,a=OD<{let r=d,a=e.pow(n,l),o=e.sqr(a);o=e.mul(o,n);let s=e.mul(t,o);s=e.pow(s,c),s=e.mul(s,a),a=e.mul(s,n),o=e.mul(s,t);let p=e.mul(o,a);s=e.pow(p,u);let m=e.eql(s,e.ONE);a=e.mul(o,f),s=e.mul(p,r),o=e.cmov(a,o,m),p=e.cmov(s,p,m);for(let t=i;t>DD;t--){let n=t-OD;n=OD<{let a=e.sqr(i),o=e.mul(t,i);a=e.mul(a,o);let s=e.pow(a,n);s=e.mul(s,o);let c=e.mul(s,r),l=e.mul(e.sqr(s),i),u=e.eql(l,t);return{isValid:u,value:e.cmov(c,s,u)}}}return p}function FD(e,t){if($E(e),!e.isValid(t.A)||!e.isValid(t.B)||!e.isValid(t.Z))throw Error(`mapToCurveSimpleSWU: invalid opts`);let n=PD(e,t.Z);if(!e.isOdd)throw Error(`Fp.isOdd is not implemented!`);return r=>{let i,a,o,s,c,l,u,d;i=e.sqr(r),i=e.mul(i,t.Z),a=e.sqr(i),a=e.add(a,i),o=e.add(a,e.ONE),o=e.mul(o,t.B),s=e.cmov(t.Z,e.neg(a),!e.eql(a,e.ZERO)),s=e.mul(s,t.A),a=e.sqr(o),l=e.sqr(s),c=e.mul(l,t.A),a=e.add(a,c),a=e.mul(a,o),l=e.mul(l,s),c=e.mul(l,t.B),a=e.add(a,c),u=e.mul(i,o);let{isValid:f,value:p}=n(a,l);d=e.mul(i,r),d=e.mul(d,p),u=e.cmov(u,o,f),d=e.cmov(d,p,f);let m=e.isOdd(r)===e.isOdd(d);d=e.cmov(e.neg(d),d,m);let h=tD(e,[s],!0)[0];return u=e.mul(u,h),{x:u,y:d}}}function ID(e){return{hash:e,hmac:(t,...n)=>VT(e,t,u(...n)),randomBytes:c}}function LD(e,t){let n=t=>ND({...e,...ID(t)});return{...n(t),create:n}}var RD=A;function zD(e,t){if(VD(e),VD(t),e<0||e>=1<<8*t)throw Error(`invalid I2OSP input: `+e);let n=Array.from({length:t}).fill(0);for(let r=t-1;r>=0;r--)n[r]=e&255,e>>>=8;return new Uint8Array(n)}function BD(e,t){let n=new Uint8Array(e.length);for(let r=0;r255&&(t=r(D(oe(`H2C-OVERSIZE-DST-`),t)));let{outputLen:i,blockLen:a}=r,o=Math.ceil(n/i);if(n>65535||o>255)throw Error(`expand_message_xmd: invalid lenInBytes`);let s=D(t,zD(t.length,1)),c=zD(0,a),l=zD(n,2),u=Array(o),d=r(D(c,e,l,zD(0,1),s));u[0]=r(D(d,zD(1,1),s));for(let e=1;e<=o;e++)u[e]=r(D(BD(d,u[e-1]),zD(e+1,1),s));return D(...u).slice(0,n)}function UD(e,t,n,r,i){if(k(e),k(t),VD(n),t.length>255){let e=Math.ceil(2*r/8);t=i.create({dkLen:e}).update(oe(`H2C-OVERSIZE-DST-`)).update(t).digest()}if(n>65535||t.length>255)throw Error(`expand_message_xof: invalid lenInBytes`);return i.create({dkLen:n}).update(e).update(zD(n,2)).update(t).update(zD(t.length,1)).digest()}function WD(e,t,n){v(n,{DST:`stringOrUint8Array`,p:`bigint`,m:`isSafeInteger`,k:`isSafeInteger`,hash:`hash`});let{p:r,k:i,m:a,hash:o,expand:s,DST:c}=n;k(e),VD(t);let l=typeof c==`string`?oe(c):c,u=r.toString(2).length,d=Math.ceil((u+i)/8),f=t*a*d,p;if(s===`xmd`)p=HD(e,l,f,o);else if(s===`xof`)p=UD(e,l,f,i,o);else if(s===`_internal_pass`)p=e;else throw Error(`expand must be "xmd" or "xof"`);let m=Array(t);for(let e=0;eArray.from(e).reverse());return(t,r)=>{let[i,a,o,s]=n.map(n=>n.reduce((n,r)=>e.add(e.mul(n,t),r))),[c,l]=tD(e,[a,s],!0);return t=e.mul(i,c),r=e.mul(r,e.mul(o,l)),{x:t,y:r}}}function KD(e,t,n){if(typeof t!=`function`)throw Error(`mapToCurve() must be defined`);function r(n){return e.fromAffine(t(n))}function i(t){let n=t.clearCofactor();return n.equals(e.ZERO)?e.ZERO:(n.assertValidity(),n)}return{defaults:n,hashToCurve(e,t){let a=WD(e,2,{...n,DST:n.DST,...t}),o=r(a[0]),s=r(a[1]);return i(o.add(s))},encodeToCurve(e,t){return i(r(WD(e,1,{...n,DST:n.encodeDST,...t})[0]))},mapToCurve(e){if(!Array.isArray(e))throw Error(`expected array of bigints`);for(let t of e)if(typeof t!=`bigint`)throw Error(`expected array of bigints`);return i(r(e))}}}var qD=ge({secp256k1:()=>nO,secp256k1_hasher:()=>aO}),JD=BigInt(`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f`),YD=BigInt(`0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141`),XD=BigInt(0),ZD=BigInt(1),QD=BigInt(2),$D=(e,t)=>(e+t/QD)/t;function eO(e){let t=JD,n=BigInt(3),r=BigInt(6),i=BigInt(11),a=BigInt(22),o=BigInt(23),s=BigInt(44),c=BigInt(88),l=e*e*e%t,u=l*l*e%t,d=KE(KE(KE(u,n,t)*u%t,n,t)*u%t,QD,t)*l%t,f=KE(d,i,t)*d%t,p=KE(f,a,t)*f%t,m=KE(p,s,t)*p%t,h=KE(KE(KE(KE(KE(KE(m,c,t)*m%t,s,t)*p%t,n,t)*u%t,o,t)*f%t,r,t)*l%t,QD,t);if(!tO.eql(tO.sqr(h),e))throw Error(`Cannot find square root`);return h}var tO=iD(JD,void 0,void 0,{sqrt:eO}),nO=LD({a:XD,b:BigInt(7),Fp:tO,n:YD,Gx:BigInt(`55066263022277343669578718895168534326250603453777594175500187360389116729240`),Gy:BigInt(`32670510020758816978083085130507043184471273380659243275938904335757337482424`),h:BigInt(1),lowS:!0,endo:{beta:BigInt(`0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee`),splitScalar:e=>{let t=YD,n=BigInt(`0x3086d221a7d46bcde86c90e49284eb15`),r=-ZD*BigInt(`0xe4437ed6010e88286f547fa90abfe4c3`),i=BigInt(`0x114ca50f7a8e2f3f657c1108d9d44cfd8`),a=n,o=BigInt(`0x100000000000000000000000000000000`),s=$D(a*e,t),c=$D(-r*e,t),l=GE(e-s*n-c*i,t),u=GE(-s*r-c*a,t),d=l>o,f=u>o;if(d&&(l=t-l),f&&(u=t-u),l>o||u>o)throw Error(`splitScalar: Endomorphism failed, k=`+e);return{k1neg:d,k1:l,k2neg:f,k2:u}}}},Xy);nO.ProjectivePoint,nO.utils.randomPrivateKey;var rO=GD(tO,[[`0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7`,`0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581`,`0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262`,`0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c`],[`0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b`,`0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14`,`0x0000000000000000000000000000000000000000000000000000000000000001`],[`0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c`,`0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3`,`0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931`,`0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84`],[`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b`,`0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573`,`0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f`,`0x0000000000000000000000000000000000000000000000000000000000000001`]].map(e=>e.map(e=>BigInt(e)))),iO=FD(tO,{A:BigInt(`0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533`),B:BigInt(`1771`),Z:tO.create(BigInt(`-11`))}),aO=KD(nO.ProjectivePoint,e=>{let{x:t,y:n}=iO(tO.create(e[0]));return rO(t,n)},{DST:`secp256k1_XMD:SHA-256_SSWU_RO_`,encodeDST:`secp256k1_XMD:SHA-256_SSWU_NU_`,p:tO.ORDER,m:1,k:128,expand:`xmd`,hash:Xy});aO.hashToCurve,aO.encodeToCurve;function oO(e,t={}){let{recovered:n}=t;if(e.r===void 0||e.s===void 0||n&&e.yParity===void 0)throw new hO({signature:e});if(e.r<0n||e.r>$T)throw new gO({value:e.r});if(e.s<0n||e.s>$T)throw new _O({value:e.s});if(typeof e.yParity==`number`&&e.yParity!==0&&e.yParity!==1)throw new vO({value:e.yParity})}function sO(e){return cO(_x(e))}function cO(e){if(e.length!==130&&e.length!==132)throw new mO({signature:e});let t=BigInt(Sx(e,0,32)),n=BigInt(Sx(e,32,64)),r=(()=>{let t=Number(`0x${e.slice(130)}`);if(!Number.isNaN(t))try{return pO(t)}catch{throw new vO({value:t})}})();return r===void 0?{r:t,s:n}:{r:t,s:n,yParity:r}}function lO(e){if(e.r!==void 0&&e.s!==void 0)return uO(e)}function uO(e){let t=typeof e==`string`?cO(e):e instanceof Uint8Array?sO(e):typeof e.r==`string`?fO(e):e.v?dO(e):{r:e.r,s:e.s,...e.yParity===void 0?{}:{yParity:e.yParity}};return oO(t),t}function dO(e){return{r:e.r,s:e.s,yParity:pO(e.v)}}function fO(e){let t=(()=>{let t=e.v?Number(e.v):void 0,n=e.yParity?Number(e.yParity):void 0;if(typeof t==`number`&&typeof n!=`number`&&(n=pO(t)),typeof n!=`number`)throw new vO({value:e.yParity});return n})();return{r:BigInt(e.r),s:BigInt(e.s),yParity:t}}function pO(e){if(e===0||e===27)return 0;if(e===1||e===28)return 1;if(e>=35)return+(e%2==0);throw new yO({value:e})}var mO=class extends Y{constructor({signature:e}){super(`Value \`${e}\` is an invalid signature size.`,{metaMessages:[`Expected: 64 bytes or 65 bytes.`,`Received ${Cx(hx(e))} bytes.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidSerializedSizeError`})}},hO=class extends Y{constructor({signature:e}){super(`Signature \`${Gb(e)}\` is missing either an \`r\`, \`s\`, or \`yParity\` property.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.MissingPropertiesError`})}},gO=class extends Y{constructor({value:e}){super(`Value \`${e}\` is an invalid r value. r must be a positive integer less than 2^256.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidRError`})}},_O=class extends Y{constructor({value:e}){super(`Value \`${e}\` is an invalid s value. s must be a positive integer less than 2^256.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidSError`})}},vO=class extends Y{constructor({value:e}){super(`Value \`${e}\` is an invalid y-parity value. Y-parity must be 0 or 1.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidYParityError`})}},yO=class extends Y{constructor({value:e}){super(`Value \`${e}\` is an invalid v value. v must be 27, 28 or >=35.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidVError`})}};function bO(e,t={}){return typeof e.chainId==`string`?xO(e):{...e,...t.signature}}function xO(e){let{address:t,chainId:n,nonce:r}=e,i=lO(e);return{address:t,chainId:Number(n),nonce:BigInt(r),...i}}var SO=AE(`(uint256 chainId, address delegation, uint256 nonce, uint8 yParity, uint256 r, uint256 s), address to, bytes data`);function CO(e){if(typeof e==`string`){if(Sx(e,-32)!==`0x8010801080108010801080108010801080108010801080108010801080108010`)throw new EO(e)}else oO(e.authorization)}function wO(e){CO(e);let t=Tx(Sx(e,-64,-32)),n=Sx(e,-t-64,-64),r=Sx(e,0,-t-64),[i,a,o]=DE(SO,n);return{authorization:bO({address:i.delegation,chainId:Number(i.chainId),nonce:i.nonce,yParity:i.yParity,r:i.r,s:i.s}),signature:r,...o&&o!==`0x`?{data:o,to:a}:{}}}function TO(e){try{return CO(e),!0}catch{return!1}}var EO=class extends Y{constructor(e){super(`Value \`${e}\` is an invalid ERC-8010 wrapped signature.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SignatureErc8010.InvalidWrappedSignatureError`})}};async function DO({message:e,signature:t}){return Kv({hash:cw(e),signature:t})}async function OO({address:e,message:t,signature:n}){return yb(Sg(e),await DO({message:t,signature:n}))}function kO(e){return e.map(e=>({...e,value:BigInt(e.value)}))}function AO(e){return{...e,balance:e.balance?BigInt(e.balance):void 0,nonce:e.nonce?jh(e.nonce):void 0,storageProof:e.storageProof?kO(e.storageProof):void 0}}async function jO(e,{address:t,blockNumber:n,blockTag:r,storageKeys:i}){let a=r??`latest`,o=n===void 0?void 0:J(n);return AO(await e.request({method:`eth_getProof`,params:[t,i,o||a]}))}async function MO(e,{address:t,blockNumber:n,blockTag:r=`latest`,slot:i}){let a=n===void 0?void 0:J(n);return await e.request({method:`eth_getStorageAt`,params:[t,i,a||r]})}async function NO(e,{blockHash:t,blockNumber:n,blockTag:r,hash:i,index:a,sender:o,nonce:s}){let c=r||`latest`,l=n===void 0?void 0:J(n),u=null;if(i?u=await e.request({method:`eth_getTransactionByHash`,params:[i]},{dedupe:!0}):t?u=await e.request({method:`eth_getTransactionByBlockHashAndIndex`,params:[t,J(a)]},{dedupe:!0}):(l||c)&&typeof a==`number`?u=await e.request({method:`eth_getTransactionByBlockNumberAndIndex`,params:[l||c,J(a)]},{dedupe:!!l}):o&&typeof s==`number`&&(u=await e.request({method:`eth_getTransactionBySenderAndNonce`,params:[o,J(s)]},{dedupe:!0})),!u)throw new K_({blockHash:t,blockNumber:n,blockTag:c,hash:i,index:a});return(e.chain?.formatters?.transaction?.format||ky)(u,`getTransaction`)}async function PO(e,{hash:t,transactionReceipt:n}){let[r,i]=await Promise.all([K(e,wS,`getBlockNumber`)({}),t?K(e,NO,`getTransaction`)({hash:t}):void 0]),a=n?.blockNumber||i?.blockNumber;return a?r-a+1n:0n}async function FO(e,{hash:t}){let n=await e.request({method:`eth_getTransactionReceipt`,params:[t]},{dedupe:!0});if(!n)throw new q_({hash:t});return(e.chain?.formatters?.transactionReceipt?.format||RS)(n,`getTransactionReceipt`)}async function IO(e,t){let{account:n,authorizationList:r,allowFailure:i=!0,blockNumber:a,blockOverrides:o,blockTag:s,stateOverride:c}=t,l=t.contracts,{batchSize:u=t.batchSize??1024,deployless:d=t.deployless??!1}=typeof e.batch?.multicall==`object`?e.batch.multicall:{},f=(()=>{if(t.multicallAddress)return t.multicallAddress;if(d)return null;if(e.chain)return eS({blockNumber:a,chain:e.chain,contract:`multicall3`});throw Error(`client chain not configured. multicallAddress is required.`)})(),p=[[]],m=0,h=0;for(let e=0;e0&&h>u&&p[m].length>0&&(m++,h=(e.length-2)/2,p[m]=[]),p[m]=[...p[m],{allowFailure:!0,callData:e,target:r}]}catch(e){let s=Rv(e,{abi:t,address:r,args:a,docsPath:`/docs/contract/multicall`,functionName:o,sender:n});if(!i)throw s;p[m]=[...p[m],{allowFailure:!0,callData:`0x`,target:r}]}}let g=await Promise.allSettled(p.map(t=>K(e,dS,`readContract`)({...f===null?{code:qx}:{address:f},abi:Fx,account:n,args:[t],authorizationList:r,blockNumber:a,blockOverrides:o,blockTag:s,functionName:`aggregate3`,stateOverride:c}))),_=[];for(let e=0;e{let t=e,n=t.account?r_(t.account):void 0,r=t.abi?o_(t):t.data,i={...t,account:n,data:t.dataSuffix?Eg([r||`0x`,t.dataSuffix]):r,from:t.from??n?.address};return Cy(i),_y(i)}),i=e.stateOverrides?xy(e.stateOverrides):void 0;t.push({blockOverrides:n,calls:r,stateOverrides:i})}let c=(typeof n==`bigint`?J(n):void 0)||r;return(await e.request({method:`eth_simulateV1`,params:[{blockStateCalls:t,returnFullTransactions:a,traceTransfers:o,validation:s},c]})).map((e,t)=>({...jy(e),calls:e.calls.map((e,n)=>{let{abi:r,args:a,functionName:o,to:s}=i[t].calls[n],c=e.error?.data??e.returnData,l=BigInt(e.gasUsed),u=e.logs?.map(e=>bb(e)),d=e.status===`0x1`?`success`:`failure`,f=r&&d===`success`&&c!==`0x`?kb({abi:r,data:c,functionName:o}):null,p=(()=>{if(d===`success`)return;let e;if(c===`0x`?e=new Ym:c&&(e=new rv({data:c})),e)return Rv(e,{abi:r??[],address:s??`0x`,args:a,functionName:o??``})})();return{data:c,gasUsed:l,logs:u,status:d,...d===`success`?{result:f}:{error:p}}})}))}catch(e){let t=e,n=py(t,{});throw n instanceof fy?t:n}}function RO(e){let t=!0,n=``,r=0,i=``,a=!1;for(let o=0;ozO(Object.values(e)[n],t)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(r)?n===`number`||n===`bigint`:/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(r)?n===`string`||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\[[0-9]{0,}\])+$/.test(r)?Array.isArray(e)&&e.every(e=>zO(e,{...t,type:r.replace(/(\[[0-9]{0,}\])$/,``)})):!1}}function BO(e,t,n){for(let r in e){let i=e[r],a=t[r];if(i.type===`tuple`&&a.type===`tuple`&&`components`in i&&`components`in a)return BO(i.components,a.components,n[r]);let o=[i.type,a.type];if(o.includes(`address`)&&o.includes(`bytes20`)||(o.includes(`address`)&&o.includes(`string`)||o.includes(`address`)&&o.includes(`bytes`))&&KT(n[r],{strict:!1}))return o}}function VO(e,t={}){let{prepare:n=!0}=t,r=Array.isArray(e)||typeof e==`string`?LT(e):e;return{...r,...n?{hash:GO(r)}:{}}}function HO(e,t,n){let{args:r=[],prepare:i=!0}=n??{},a=Ex(t,{strict:!1}),o=e.filter(e=>a?e.type===`function`||e.type===`error`?UO(e)===Sx(t,0,4):e.type===`event`?GO(e)===t:!1:`name`in e&&e.name===t);if(o.length===0)throw new qO({name:t});if(o.length===1)return{...o[0],...i?{hash:GO(o[0])}:{}};let s;for(let e of o)if(`inputs`in e){if(!r||r.length===0){if(!e.inputs||e.inputs.length===0)return{...e,...i?{hash:GO(e)}:{}};continue}if(e.inputs&&e.inputs.length!==0&&e.inputs.length===r.length&&r.every((t,n)=>{let r=`inputs`in e&&e.inputs[n];return r?zO(t,r):!1})){if(s&&`inputs`in s&&s.inputs){let t=BO(e.inputs,s.inputs,r);if(t)throw new KO({abiItem:e,type:t[0]},{abiItem:s,type:t[1]})}s=e}}let c=(()=>{if(s)return s;let[e,...t]=o;return{...e,overloads:t}})();if(!c)throw new qO({name:t});return{...c,...i?{hash:GO(c)}:{}}}function UO(...e){return Sx(GO((()=>{if(Array.isArray(e[0])){let[t,n]=e;return HO(t,n)}return e[0]})()),0,4)}function WO(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return HO(t,n)}return e[0]})();return RO(typeof t==`string`?t:Nw(t))}function GO(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return HO(t,n)}return e[0]})();return typeof t!=`string`&&`hash`in t&&t.hash?t.hash:HT(yx(WO(t)))}var KO=class extends Y{constructor(e,t){super(`Found ambiguous types in overloaded ABI Items.`,{metaMessages:[`\`${e.type}\` in \`${RO(Nw(e.abiItem))}\`, and`,`\`${t.type}\` in \`${RO(Nw(t.abiItem))}\``,``,`These types encode differently and cannot be distinguished at runtime.`,`Remove one of the ambiguous items in the ABI.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiItem.AmbiguityError`})}},qO=class extends Y{constructor({name:e,data:t,type:n=`item`}){let r=e?` with name "${e}"`:t?` with data "${t}"`:``;super(`ABI ${n}${r} not found.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiItem.NotFoundError`})}};function JO(...e){let[t,n]=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return[XO(t),n]}return e})(),{bytecode:r,args:i}=n;return mx(r,t.inputs?.length&&i?.length?OE(t.inputs,i):`0x`)}function YO(e){return VO(e)}function XO(e){let t=e.find(e=>e.type===`constructor`);if(!t)throw new qO({name:`constructor`});return t}function ZO(...e){let[t,n=[]]=(()=>{if(Array.isArray(e[0])){let[t,n,r]=e;return[$O(t,n,{args:r}),r]}let[t,n]=e;return[t,n]})(),{overloads:r}=t,i=r?$O([t,...r],t.name,{args:n}):t,a=ek(i),o=n.length>0?OE(i.inputs,n):void 0;return o?mx(a,o):a}function QO(e,t={}){return VO(e,t)}function $O(e,t,n){let r=HO(e,t,n);if(r.type!==`function`)throw new qO({name:t,type:`function`});return r}function ek(e){return UO(e)}var tk=`0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`,nk=`0x0000000000000000000000000000000000000000`,rk=`0x6080604052348015600e575f80fd5b5061016d8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063f8b2cb4f1461002d575b5f80fd5b610047600480360381019061004291906100db565b61005d565b604051610054919061011e565b60405180910390f35b5f8173ffffffffffffffffffffffffffffffffffffffff16319050919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100aa82610081565b9050919050565b6100ba816100a0565b81146100c4575f80fd5b50565b5f813590506100d5816100b1565b92915050565b5f602082840312156100f0576100ef61007d565b5b5f6100fd848285016100c7565b91505092915050565b5f819050919050565b61011881610106565b82525050565b5f6020820190506101315f83018461010f565b9291505056fea26469706673582212203b9fe929fe995c7cf9887f0bdba8a36dd78e8b73f149b17d2d9ad7cd09d2dc6264736f6c634300081a0033`;async function ik(e,t){let{blockNumber:n,blockTag:r,calls:i,stateOverrides:a,traceAssetChanges:o,traceTransfers:s,validation:c}=t,l=t.account?r_(t.account):void 0;if(o&&!l)throw new q("`account` is required when `traceAssetChanges` is true");let u=l?JO(YO(`constructor(bytes, bytes)`),{bytecode:Wx,args:[rk,ZO(QO(`function getBalance(address)`),[l.address])]}):void 0,d=o?await Promise.all(t.calls.map(async t=>{if(!t.data&&!t.abi)return;let{accessList:n}=await NC(e,{account:l.address,...t,data:t.abi?o_(t):t.data});return n.map(({address:e,storageKeys:t})=>t.length>0?e:null)})).then(e=>e.flat().filter(Boolean)):[],f=await LO(e,{blockNumber:n,blockTag:r,blocks:[...o?[{calls:[{data:u}],stateOverrides:a},{calls:d.map((e,t)=>({abi:[QO(`function balanceOf(address) returns (uint256)`)],functionName:`balanceOf`,args:[l.address],to:e,from:nk,nonce:t})),stateOverrides:[{address:nk,nonce:0}]}]:[],{calls:[...i,{to:nk}].map(e=>({...e,from:l?.address})),stateOverrides:a},...o?[{calls:[{data:u}]},{calls:d.map((e,t)=>({abi:[QO(`function balanceOf(address) returns (uint256)`)],functionName:`balanceOf`,args:[l.address],to:e,from:nk,nonce:t})),stateOverrides:[{address:nk,nonce:0}]},{calls:d.map((e,t)=>({to:e,abi:[QO(`function decimals() returns (uint256)`)],functionName:`decimals`,from:nk,nonce:t})),stateOverrides:[{address:nk,nonce:0}]},{calls:d.map((e,t)=>({to:e,abi:[QO(`function tokenURI(uint256) returns (string)`)],functionName:`tokenURI`,args:[0n],from:nk,nonce:t})),stateOverrides:[{address:nk,nonce:0}]},{calls:d.map((e,t)=>({to:e,abi:[QO(`function symbol() returns (string)`)],functionName:`symbol`,from:nk,nonce:t})),stateOverrides:[{address:nk,nonce:0}]}]:[]],traceTransfers:s,validation:c}),p=o?f[2]:f[0],[m,h,,g,_,v,y,b]=o?f:[],{calls:x,...S}=p,C=x.slice(0,-1)??[],w=m?.calls??[],T=h?.calls??[],E=[...w,...T].map(e=>e.status===`success`?kh(e.data):null),D=g?.calls??[],ee=_?.calls??[],te=[...D,...ee].map(e=>e.status===`success`?kh(e.data):null),ne=(v?.calls??[]).map(e=>e.status===`success`?e.result:null),O=(b?.calls??[]).map(e=>e.status===`success`?e.result:null),k=(y?.calls??[]).map(e=>e.status===`success`?e.result:null),A=[];for(let[e,t]of te.entries()){let n=E[e];if(typeof t!=`bigint`||typeof n!=`bigint`)continue;let r=ne[e-1],i=O[e-1],a=k[e-1],o=e===0?{address:tk,decimals:18,symbol:`ETH`}:{address:d[e-1],decimals:a||r?Number(r??1):void 0,symbol:i??void 0};A.some(e=>e.token.address===o.address)||A.push({token:o,value:{pre:n,post:t,diff:t-n}})}return{assetChanges:A,block:S,results:C}}var ak=`0x6492649264926492649264926492649264926492649264926492649264926492`;function ok(e){if(Sx(e,-32)!==`0x6492649264926492649264926492649264926492649264926492649264926492`)throw new lk(e)}function sk(e){let{data:t,signature:n,to:r}=e;return mx(OE(AE(`address, bytes, bytes`),[r,t,n]),ak)}function ck(e){try{return ok(e),!0}catch{return!1}}var lk=class extends Y{constructor(e){super(`Value \`${e}\` is an invalid ERC-6492 wrapped signature.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SignatureErc6492.InvalidWrappedSignatureError`})}};function uk({r:e,s:t,to:n=`hex`,v:r,yParity:i}){let a=(()=>{if(i===0||i===1)return i;if(r&&(r===27n||r===28n||r>=35n))return+(r%2n==0n);throw Error("Invalid `v` or `yParity` value")})(),o=`0x${new nO.Signature(kh(e),kh(t)).toCompactHex()}${a===0?`1b`:`1c`}`;return n===`hex`?o:Uh(o)}async function dk(e,t){let{address:n,chain:r=e.chain,hash:i,erc6492VerifierAddress:a=t.universalSignatureVerifierAddress??r?.contracts?.erc6492Verifier?.address,multicallAddress:o=t.multicallAddress??r?.contracts?.multicall3?.address,mode:s=`auto`}=t;if(r?.verifyHash)return await r.verifyHash(e,t);let c=(()=>{let e=t.signature;return Vm(e)?e:typeof e==`object`&&`r`in e&&`s`in e?uk(e):Fh(e)})();try{if(s===`eoa`)try{if(yb(Sg(n),await Kv({hash:i,signature:c})))return!0}catch{}return TO(c)?await fk(e,{...t,multicallAddress:o,signature:c}):await pk(e,{...t,verifierAddress:a,signature:c})}catch(e){if(s!==`eoa`)try{if(yb(Sg(n),await Kv({hash:i,signature:c})))return!0}catch{}if(e instanceof hk)return!1;throw e}}async function fk(e,t){let{address:n,blockNumber:r,blockTag:i,hash:a,multicallAddress:o}=t,{authorization:s,data:c,signature:l,to:u}=wO(t.signature);if(await BC(e,{address:n,blockNumber:r,blockTag:i})===Og([`0xef0100`,s.address]))return await mk(e,{address:n,blockNumber:r,blockTag:i,hash:a,signature:l});let d={address:s.address,chainId:Number(s.chainId),nonce:Number(s.nonce),r:J(s.r,{size:32}),s:J(s.s,{size:32}),yParity:s.yParity};if(!await JC({address:n,authorization:d}))throw new hk;let f=await K(e,dS,`readContract`)({...o?{address:o}:{code:qx},authorizationList:[d],abi:Fx,blockNumber:r,blockTag:`pending`,functionName:`aggregate3`,args:[[...c?[{allowFailure:!0,target:u??n,callData:c}]:[],{allowFailure:!0,target:n,callData:o_({abi:Hx,functionName:`isValidSignature`,args:[a,l]})}]]});if((f[f.length-1]?.returnData)?.startsWith(`0x1626ba7e`))return!0;throw new hk}async function pk(e,t){let{address:n,factory:r,factoryData:i,hash:a,signature:o,verifierAddress:s,...c}=t,l=await(async()=>!r&&!i||ck(o)?o:sk({data:i,signature:o,to:r}))(),u=s?{to:s,data:o_({abi:Ux,functionName:`isValidSig`,args:[n,a,l]}),...c}:{data:$x({abi:Ux,args:[n,a,l],bytecode:Kx}),...c},{data:d}=await K(e,aS,`call`)(u).catch(e=>{throw e instanceof Q_?new hk:e});if(Ah(d??`0x0`))return!0;throw new hk}async function mk(e,t){let{address:n,blockNumber:r,blockTag:i,hash:a,signature:o}=t;if((await K(e,dS,`readContract`)({address:n,abi:Hx,args:[a,o],blockNumber:r,blockTag:i,functionName:`isValidSignature`}).catch(e=>{throw e instanceof $_?new hk:e})).startsWith(`0x1626ba7e`))return!0;throw new hk}var hk=class extends Error{};async function gk(e,{address:t,message:n,factory:r,factoryData:i,signature:a,...o}){let s=cw(n);return K(e,dk,`verifyHash`)({address:t,factory:r,factoryData:i,hash:s,signature:a,...o})}async function _k(e,t){let{address:n,factory:r,factoryData:i,signature:a,message:o,primaryType:s,types:c,domain:l,...u}=t,d=gw({message:o,primaryType:s,types:c,domain:l});return K(e,dk,`verifyHash`)({address:n,factory:r,factoryData:i,hash:d,signature:a,...u})}function vk(e,{emitOnBegin:t=!1,emitMissed:n=!1,onBlockNumber:r,onError:i,poll:a,pollingInterval:o=e.pollingInterval}){let s=a===void 0?!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):a,c;return s?gS(M_([`watchBlockNumber`,e.uid,t,n,o]),{onBlockNumber:r,onError:i},r=>vS(async()=>{try{let t=await K(e,wS,`getBlockNumber`)({cacheTime:0});if(c!==void 0){if(t===c)return;if(t-c>1&&n)for(let e=c+1n;ec)&&(r.onBlockNumber(t,c),c=t)}catch(e){r.onError?.(e)}},{emitOnBegin:t,interval:o})):gS(M_([`watchBlockNumber`,e.uid,t,n]),{onBlockNumber:r,onError:i},t=>{let n=!0,r=()=>n=!1;return(async()=>{try{let{unsubscribe:i}=await(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})().subscribe({params:[`newHeads`],onData(e){if(!n)return;let r=kh(e.result?.number);t.onBlockNumber(r,c),c=r},onError(e){t.onError?.(e)}});r=i,n||r()}catch(e){i?.(e)}})(),()=>r()})}async function yk(e,t){let{checkReplacement:n=!0,confirmations:r=1,hash:i,onReplaced:a,retryCount:o=6,retryDelay:s=({count:e})=>~~(1<{g?.(),h?.(),y(new Y_({hash:i}))},c):void 0;return h=gS(l,{onReplaced:a,resolve:v,reject:y},async t=>{if(p=await K(e,FO,`getTransactionReceipt`)({hash:i}).catch(()=>void 0),p&&r<=1){clearTimeout(b),t.resolve(p),h?.();return}g=K(e,vk,`watchBlockNumber`)({emitMissed:!0,emitOnBegin:!0,poll:!0,pollingInterval:u,async onBlockNumber(a){let c=e=>{clearTimeout(b),g?.(),e(),h?.()},l=a;if(!m)try{if(p){if(r>1&&(!p.blockNumber||l-p.blockNumber+1nt.resolve(p));return}if(n&&!d&&(m=!0,await IS(async()=>{d=await K(e,NO,`getTransaction`)({hash:i}),d.blockNumber&&(l=d.blockNumber)},{delay:s,retryCount:o}),m=!1),p=await K(e,FO,`getTransactionReceipt`)({hash:i}),r>1&&(!p.blockNumber||l-p.blockNumber+1nt.resolve(p))}catch(n){if(n instanceof K_||n instanceof q_){if(!d){m=!1;return}try{f=d,m=!0;let n=await IS(()=>K(e,My,`getBlock`)({blockNumber:l,includeTransactions:!0}),{delay:s,retryCount:o,shouldRetry:({error:e})=>e instanceof Dy});m=!1;let i=n.transactions.find(({from:e,nonce:t})=>e===f.from&&t===f.nonce);if(!i||(p=await K(e,FO,`getTransactionReceipt`)({hash:i.hash}),r>1&&(!p.blockNumber||l-p.blockNumber+1n{t.onReplaced?.({reason:a,replacedTransaction:f,transaction:i,transactionReceipt:p}),t.resolve(p)})}catch(e){c(()=>t.reject(e))}}else c(()=>t.reject(n))}}})}),_}function bk(e,{blockTag:t=e.experimental_blockTag??`latest`,emitMissed:n=!1,emitOnBegin:r=!1,onBlock:i,onError:a,includeTransactions:o,poll:s,pollingInterval:c=e.pollingInterval}){let l=s===void 0?!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):s,u=o??!1,d;return l?gS(M_([`watchBlocks`,e.uid,t,n,r,u,c]),{onBlock:i,onError:a},i=>vS(async()=>{try{let r=await K(e,My,`getBlock`)({blockTag:t,includeTransactions:u});if(r.number!==null&&d?.number!=null){if(r.number===d.number)return;if(r.number-d.number>1&&n)for(let t=d?.number+1n;td.number)&&(i.onBlock(r,d),d=r)}catch(e){i.onError?.(e)}},{emitOnBegin:r,interval:c})):(()=>{let n=!0,o=!0,s=()=>n=!1;return(async()=>{try{r&&K(e,My,`getBlock`)({blockTag:t,includeTransactions:u}).then(e=>{n&&(o&&=(i(e,void 0),!1))}).catch(a);let{unsubscribe:c}=await(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})().subscribe({params:[`newHeads`],async onData(t){if(!n)return;let r=await K(e,My,`getBlock`)({blockNumber:t.result?.number,includeTransactions:u}).catch(()=>{});n&&(i(r,d),o=!1,d=r)},onError(e){a?.(e)}});s=c,n||s()}catch(e){a?.(e)}})(),()=>s()})()}function xk(e,{address:t,args:n,batch:r=!0,event:i,events:a,fromBlock:o,onError:s,onLogs:c,poll:l,pollingInterval:u=e.pollingInterval,strict:d}){let f=l===void 0?typeof o==`bigint`?!0:!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):l,p=d??!1;return f?gS(M_([`watchEvent`,t,n,r,e.uid,i,u,o]),{onLogs:c,onError:s},s=>{let c;o!==void 0&&(c=o-1n);let l,d=!1,f=vS(async()=>{if(!d){try{l=await K(e,FC,`createEventFilter`)({address:t,args:n,event:i,events:a,strict:p,fromBlock:o})}catch{}d=!0;return}try{let o;if(l)o=await K(e,TS,`getFilterChanges`)({filter:l});else{let r=await K(e,wS,`getBlockNumber`)({});o=c&&c!==r?await K(e,Eb,`getLogs`)({address:t,args:n,event:i,events:a,fromBlock:c+1n,toBlock:r}):[],c=r}if(o.length===0)return;if(r)s.onLogs(o);else for(let e of o)s.onLogs([e])}catch(e){l&&e instanceof hv&&(d=!1),s.onError?.(e)}},{emitOnBegin:!0,interval:u});return async()=>{l&&await K(e,ES,`uninstallFilter`)({filter:l}),f()}}):(()=>{let r=!0,o=()=>r=!1;return(async()=>{try{let l=(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})(),u=a??(i?[i]:void 0),f=[];u&&(f=[u.flatMap(e=>$g({abi:[e],eventName:e.name,args:n}))],i&&(f=f[0]));let{unsubscribe:m}=await l.subscribe({params:[`logs`,{address:t,topics:f}],onData(e){if(!r)return;let t=e.result;try{let{eventName:e,args:n}=Sb({abi:u??[],data:t.data,topics:t.topics,strict:p});c([bb(t,{args:n,eventName:e})])}catch(e){let n,r;if(e instanceof uh||e instanceof dh){if(d)return;n=e.abiItem.name,r=e.abiItem.inputs?.some(e=>!(`name`in e&&e.name))}c([bb(t,{args:r?[]:{},eventName:n})])}},onError(e){s?.(e)}});o=m,r||o()}catch(e){s?.(e)}})(),()=>o()})()}function Sk(e,{batch:t=!0,onError:n,onTransactions:r,poll:i,pollingInterval:a=e.pollingInterval}){return(i===void 0?e.transport.type!==`webSocket`&&e.transport.type!==`ipc`:i)?gS(M_([`watchPendingTransactions`,e.uid,t,a]),{onTransactions:r,onError:n},n=>{let r,i=vS(async()=>{try{if(!r)try{r=await K(e,IC,`createPendingTransactionFilter`)({});return}catch(e){throw i(),e}let a=await K(e,TS,`getFilterChanges`)({filter:r});if(a.length===0)return;if(t)n.onTransactions(a);else for(let e of a)n.onTransactions([e])}catch(e){n.onError?.(e)}},{emitOnBegin:!0,interval:a});return async()=>{r&&await K(e,ES,`uninstallFilter`)({filter:r}),i()}}):(()=>{let t=!0,i=()=>t=!1;return(async()=>{try{let{unsubscribe:a}=await e.transport.subscribe({params:[`newPendingTransactions`],onData(e){if(!t)return;let n=e.result;r([n])},onError(e){n?.(e)}});i=a,t||i()}catch(e){n?.(e)}})(),()=>i()})()}function Ck(e){let{scheme:t,statement:n,...r}=e.match(wk)?.groups??{},{chainId:i,expirationTime:a,issuedAt:o,notBefore:s,requestId:c,...l}=e.match(Tk)?.groups??{},u=e.split(`Resources:`)[1]?.split(` +- `).slice(1);return{...r,...l,...i?{chainId:Number(i)}:{},...a?{expirationTime:new Date(a)}:{},...o?{issuedAt:new Date(o)}:{},...s?{notBefore:new Date(s)}:{},...c?{requestId:c}:{},...u?{resources:u}:{},...t?{scheme:t}:{},...n?{statement:n}:{}}}var wk=/^(?:(?[a-zA-Z][a-zA-Z0-9+-.]*):\/\/)?(?[a-zA-Z0-9+-.]*(?::[0-9]{1,5})?) (?:wants you to sign in with your Ethereum account:\n)(?
0x[a-fA-F0-9]{40})\n\n(?:(?.*)\n\n)?/,Tk=/(?:URI: (?.+))\n(?:Version: (?.+))\n(?:Chain ID: (?\d+))\n(?:Nonce: (?[a-zA-Z0-9]+))\n(?:Issued At: (?.+))(?:\nExpiration Time: (?.+))?(?:\nNot Before: (?.+))?(?:\nRequest ID: (?.+))?/;function Ek(e){let{address:t,domain:n,message:r,nonce:i,scheme:a,time:o=new Date}=e;if(n&&r.domain!==n||i&&r.nonce!==i||a&&r.scheme!==a||r.expirationTime&&o>=r.expirationTime||r.notBefore&&oaS(e,t),createAccessList:t=>NC(e,t),createBlockFilter:()=>PC(e),createContractEventFilter:t=>n_(e,t),createEventFilter:t=>FC(e,t),createPendingTransactionFilter:()=>IC(e),estimateContractGas:t=>vb(e,t),estimateGas:t=>_b(e,t),getBalance:t=>LC(e,t),getBlobBaseFee:()=>RC(e),getBlock:t=>My(e,t),getBlockNumber:t=>wS(e,t),getBlockTransactionCount:t=>zC(e,t),getBytecode:t=>BC(e,t),getChainId:()=>db(e),getCode:t=>BC(e,t),getContractEvents:t=>Db(e,t),getDelegation:t=>VC(e,t),getEip712Domain:t=>UC(e,t),getEnsAddress:t=>uC(e,t),getEnsAvatar:t=>AC(e,t),getEnsName:t=>jC(e,t),getEnsResolver:t=>MC(e,t),getEnsText:t=>kC(e,t),getFeeHistory:t=>KC(e,t),estimateFeesPerGas:t=>Iy(e,t),getFilterChanges:t=>TS(e,t),getFilterLogs:t=>qC(e,t),getGasPrice:()=>Ny(e),getLogs:t=>Eb(e,t),getProof:t=>jO(e,t),estimateMaxPriorityFeePerGas:t=>Py(e,t),fillTransaction:t=>fb(e,t),getStorageAt:t=>MO(e,t),getTransaction:t=>NO(e,t),getTransactionConfirmations:t=>PO(e,t),getTransactionCount:t=>Ry(e,t),getTransactionReceipt:t=>FO(e,t),multicall:t=>IO(e,t),prepareTransactionRequest:t=>gb(e,t),readContract:t=>dS(e,t),sendRawTransaction:t=>jS(e,t),sendRawTransactionSync:t=>Ok(e,t),simulate:t=>LO(e,t),simulateBlocks:t=>LO(e,t),simulateCalls:t=>ik(e,t),simulateContract:t=>fS(e,t),verifyHash:t=>dk(e,t),verifyMessage:t=>gk(e,t),verifySiweMessage:t=>Dk(e,t),verifyTypedData:t=>_k(e,t),uninstallFilter:t=>ES(e,t),waitForTransactionReceipt:t=>yk(e,t),watchBlocks:t=>bk(e,t),watchBlockNumber:t=>vk(e,t),watchContractEvent:t=>DS(e,t),watchEvent:t=>xk(e,t),watchPendingTransactions:t=>Sk(e,t)}}function Ak(e){let{key:t=`public`,name:n=`Public Client`}=e;return YS({...e,key:t,name:n,type:`publicClient`}).extend(kk)}async function jk(e,{chain:t}){let{id:n,name:r,nativeCurrency:i,rpcUrls:a,blockExplorers:o}=t;await e.request({method:`wallet_addEthereumChain`,params:[{chainId:J(n),chainName:r,nativeCurrency:i,rpcUrls:a.default.http,blockExplorerUrls:o?Object.values(o).map(({url:e})=>e):void 0}]},{dedupe:!0,retryCount:0})}function Mk(e,t){let{abi:n,args:r,bytecode:i,...a}=t,o=$x({abi:n,args:r,bytecode:i});return NS(e,{...a,...a.authorizationList?{to:null}:{},data:o})}async function Nk(e){return e.account?.type===`local`?[e.account.address]:(await e.request({method:`eth_accounts`},{dedupe:!0})).map(e=>xg(e))}async function Pk(e,t={}){let{account:n=e.account,chainId:r}=t,i=n?r_(n):void 0,a=r?[i?.address,[J(r)]]:[i?.address],o=await e.request({method:`wallet_getCapabilities`,params:a}),s={};for(let[e,t]of Object.entries(o)){s[Number(e)]={};for(let[n,r]of Object.entries(t))n===`addSubAccount`&&(n=`unstable_addSubAccount`),s[Number(e)][n]=r}return typeof r==`number`?s[r]:s}async function Fk(e){return await e.request({method:`wallet_getPermissions`},{dedupe:!0})}async function Ik(e,t){let{account:n=e.account,chainId:r,nonce:i}=t;if(!n)throw new OS({docsPath:`/docs/eip7702/prepareAuthorization`});let a=r_(n),o=(()=>{if(t.executor)return t.executor===`self`?t.executor:r_(t.executor)})(),s={address:t.contractAddress??t.address,chainId:r,nonce:i};return s.chainId===void 0&&(s.chainId=e.chain?.id??await K(e,db,`getChainId`)({})),s.nonce===void 0&&(s.nonce=await K(e,Ry,`getTransactionCount`)({address:a.address,blockTag:`pending`}),(o===`self`||o?.address&&yb(o.address,a.address))&&(s.nonce+=1)),s}async function Lk(e){return(await e.request({method:`eth_requestAccounts`},{dedupe:!0,retryCount:0})).map(e=>Sg(e))}async function Rk(e,t){return e.request({method:`wallet_requestPermissions`,params:[t]},{retryCount:0})}async function zk(e,t){let{chain:n=e.chain}=t,r=t.timeout??Math.max((n?.blockTime??0)*3,5e3),i=await K(e,VS,`sendCalls`)(t);return await K(e,US,`waitForCallsStatus`)({...t,id:i.id,timeout:r})}var Bk=new yg(128);async function Vk(e,t){let{account:n=e.account,assertChainId:r=!0,chain:i=e.chain,accessList:a,authorizationList:o,blobs:s,data:c,dataSuffix:l=typeof e.dataSuffix==`string`?e.dataSuffix:e.dataSuffix?.value,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,pollingInterval:g,throwOnReceiptRevert:_,type:v,value:y,...b}=t,x=t.timeout??Math.max((i?.blockTime??0)*3,5e3);if(n===void 0)throw new OS({docsPath:`/docs/actions/wallet/sendTransactionSync`});let S=n?r_(n):null;try{Cy(t);let n=await(async()=>{if(t.to)return t.to;if(t.to!==null&&o&&o.length>0)return await $v({authorization:o[0]}).catch(()=>{throw new q("`to` is required. Could not infer from `authorizationList`.")})})();if(S?.type===`json-rpc`||S===null){let t;i!==null&&(t=await K(e,db,`getChainId`)({}),r&&AS({currentChainId:t,chain:i}));let C=e.chain?.formatters?.transactionRequest?.format,w=(C||_y)({...hy(b,{format:C}),accessList:a,account:S,authorizationList:o,blobs:s,chainId:t,data:c&&Eg([c,l??`0x`]),gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,to:n,type:v,value:y},`sendTransaction`),T=Bk.get(e.uid),E=T?`wallet_sendTransaction`:`eth_sendTransaction`,D=await(async()=>{try{return await e.request({method:E,params:[w]},{retryCount:0})}catch(t){if(T===!1)throw t;let n=t;if(n.name===`InvalidInputRpcError`||n.name===`InvalidParamsRpcError`||n.name===`MethodNotFoundRpcError`||n.name===`MethodNotSupportedRpcError`)return await e.request({method:`wallet_sendTransaction`,params:[w]},{retryCount:0}).then(t=>(Bk.set(e.uid,!0),t)).catch(t=>{let r=t;throw r.name===`MethodNotFoundRpcError`||r.name===`MethodNotSupportedRpcError`?(Bk.set(e.uid,!1),n):r});throw n}})(),ee=await K(e,yk,`waitForTransactionReceipt`)({checkReplacement:!1,hash:D,pollingInterval:g,timeout:x});if(_&&ee.status===`reverted`)throw new J_({receipt:ee});return ee}if(S?.type===`local`){let r=await K(e,gb,`prepareTransactionRequest`)({account:S,accessList:a,authorizationList:o,blobs:s,chain:i,data:c&&Eg([c,l??`0x`]),gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,nonceManager:S.nonceManager,parameters:[...pb,`sidecars`],type:v,value:y,...b,to:n}),g=i?.serializers?.transaction,x=await S.signTransaction(r,{serializer:g});return await K(e,Ok,`sendRawTransactionSync`)({serializedTransaction:x,throwOnReceiptRevert:_,timeout:t.timeout})}throw S?.type===`smart`?new kS({metaMessages:["Consider using the `sendUserOperation` Action instead."],docsPath:`/docs/actions/bundler/sendUserOperation`,type:`smart`}):new kS({docsPath:`/docs/actions/wallet/sendTransactionSync`,type:S?.type})}catch(e){throw e instanceof kS?e:ub(e,{...t,account:S,chain:t.chain||void 0})}}async function Hk(e,t){let{id:n}=t;await e.request({method:`wallet_showCallsStatus`,params:[n]})}async function Uk(e,t){let{account:n=e.account}=t;if(!n)throw new OS({docsPath:`/docs/eip7702/signAuthorization`});let r=r_(n);if(!r.signAuthorization)throw new kS({docsPath:`/docs/eip7702/signAuthorization`,metaMessages:["The `signAuthorization` Action does not support JSON-RPC Accounts."],type:r.type});let i=await Ik(e,t);return r.signAuthorization(i)}async function Wk(e,{account:t=e.account,message:n}){if(!t)throw new OS({docsPath:`/docs/actions/wallet/signMessage`});let r=r_(t);if(r.signMessage)return r.signMessage({message:n});let i=typeof n==`string`?Lh(n):n.raw instanceof Uint8Array?Nh(n.raw):n.raw;return e.request({method:`personal_sign`,params:[i,r.address]},{retryCount:0})}async function Gk(e,t){let{account:n=e.account,chain:r=e.chain,...i}=t;if(!n)throw new OS({docsPath:`/docs/actions/wallet/signTransaction`});let a=r_(n);Cy({account:a,...t});let o=await K(e,db,`getChainId`)({});r!==null&&AS({currentChainId:o,chain:r});let s=(r?.formatters||e.chain?.formatters)?.transactionRequest?.format||_y;return a.signTransaction?a.signTransaction({...i,account:a,chainId:o},{serializer:e.chain?.serializers?.transaction}):await e.request({method:`eth_signTransaction`,params:[{...s({...i,account:a},`signTransaction`),chainId:J(o),from:a.address}]},{retryCount:0})}async function Kk(e,t){let{account:n=e.account,domain:r,message:i,primaryType:a}=t;if(!n)throw new OS({docsPath:`/docs/actions/wallet/signTypedData`});let o=r_(n),s={EIP712Domain:mw({domain:r}),...t.types};if(pw({domain:r,message:i,primaryType:a,types:s}),o.signTypedData)return o.signTypedData({domain:r,message:i,primaryType:a,types:s});let c=fw({domain:r,message:i,primaryType:a,types:s});return e.request({method:`eth_signTypedData_v4`,params:[o.address,c]},{retryCount:0})}async function qk(e,{id:t}){await e.request({method:`wallet_switchEthereumChain`,params:[{chainId:J(t)}]},{retryCount:0})}async function Jk(e,t){return await e.request({method:`wallet_watchAsset`,params:t},{retryCount:0})}async function Yk(e,t){return PS.internal(e,Vk,`sendTransactionSync`,t)}function Xk(e){return{addChain:t=>jk(e,t),deployContract:t=>Mk(e,t),fillTransaction:t=>fb(e,t),getAddresses:()=>Nk(e),getCallsStatus:t=>HS(e,t),getCapabilities:t=>Pk(e,t),getChainId:()=>db(e),getPermissions:()=>Fk(e),prepareAuthorization:t=>Ik(e,t),prepareTransactionRequest:t=>gb(e,t),requestAddresses:()=>Lk(e),requestPermissions:t=>Rk(e,t),sendCalls:t=>VS(e,t),sendCallsSync:t=>zk(e,t),sendRawTransaction:t=>jS(e,t),sendRawTransactionSync:t=>Ok(e,t),sendTransaction:t=>NS(e,t),sendTransactionSync:t=>Vk(e,t),showCallsStatus:t=>Hk(e,t),signAuthorization:t=>Uk(e,t),signMessage:t=>Wk(e,t),signTransaction:t=>Gk(e,t),signTypedData:t=>Kk(e,t),switchChain:t=>qk(e,t),waitForCallsStatus:t=>US(e,t),watchAsset:t=>Jk(e,t),writeContract:t=>PS(e,t),writeContractSync:t=>Yk(e,t)}}function Zk(e){let{key:t=`wallet`,name:n=`Wallet Client`,transport:r}=e;return YS({...e,key:t,name:n,transport:r,type:`walletClient`}).extend(Xk)}function Qk({key:e,methods:t,name:n,request:r,retryCount:i=3,retryDelay:a=150,timeout:o,type:s},c){let l=JS();return{config:{key:e,methods:t,name:n,request:r,retryCount:i,retryDelay:a,timeout:o,type:s},request:ZC(r,{methods:t,retryCount:i,retryDelay:a,uid:l}),value:c}}function $k(e,t={}){let{key:n=`custom`,methods:r,name:i=`Custom Provider`,retryDelay:a}=t;return({retryCount:o})=>Qk({key:n,methods:r,name:i,request:e.request.bind(e),retryCount:t.retryCount??o,retryDelay:a,type:`custom`})}var eA=class extends q{constructor(){super(`No URL was provided to the Transport. Please provide a valid RPC URL to the Transport.`,{docsPath:`/docs/clients/intro`,name:`UrlRequiredError`})}};function tA(e,t={}){let{batch:n,fetchFn:r,fetchOptions:i,key:a=`http`,methods:o,name:s=`HTTP JSON-RPC`,onFetchRequest:c,onFetchResponse:l,retryDelay:u,raw:d}=t;return({chain:f,retryCount:p,timeout:m})=>{let{batchSize:h=1e3,wait:g=0}=typeof n==`object`?n:{},_=t.retryCount??p,v=m??t.timeout??1e4,y=e||f?.rpcUrls.default.http[0];if(!y)throw new eA;let b=iw(y,{fetchFn:r,fetchOptions:i,onRequest:c,onResponse:l,timeout:v});return Qk({key:a,methods:o,name:s,async request({method:e,params:t}){let r={method:e,params:t},{schedule:i}=iS({id:y,wait:g,shouldSplitBatch(e){return e.length>h},fn:e=>b.request({body:e}),sort:(e,t)=>e.id-t.id}),[{error:a,result:o}]=await(async e=>n?i(e):[await b.request({body:e})])(r);if(d)return{error:a,result:o};if(a)throw new av({body:r,error:a,url:y});return o},retryCount:_,retryDelay:u,timeout:v,type:`http`},{fetchOptions:i,url:y})}}var nA;(function(e){e[e.Home=1]=`Home`,e[e.Escrow=2]=`Escrow`})(nA||={});var rA;(function(e){e[e.User=0]=`User`,e[e.Node=1]=`Node`})(rA||={});var iA;(function(e){e[e.Default=0]=`Default`,e[e.SessionKey=1]=`SessionKey`})(iA||={});var aA;(function(e){e[e.Void=0]=`Void`,e[e.Open=1]=`Open`,e[e.Challenged=2]=`Challenged`,e[e.Closed=3]=`Closed`})(aA||={});var X;(function(e){e[e.Void=0]=`Void`,e[e.Acknowledgement=1]=`Acknowledgement`,e[e.HomeDeposit=10]=`HomeDeposit`,e[e.HomeWithdrawal=11]=`HomeWithdrawal`,e[e.EscrowDeposit=20]=`EscrowDeposit`,e[e.EscrowWithdraw=21]=`EscrowWithdraw`,e[e.TransferSend=30]=`TransferSend`,e[e.TransferReceive=31]=`TransferReceive`,e[e.Commit=40]=`Commit`,e[e.Release=41]=`Release`,e[e.Migrate=100]=`Migrate`,e[e.EscrowLock=110]=`EscrowLock`,e[e.MutualLock=120]=`MutualLock`,e[e.Finalize=200]=`Finalize`})(X||={});var oA;(function(e){e[e.HomeDeposit=10]=`HomeDeposit`,e[e.HomeWithdrawal=11]=`HomeWithdrawal`,e[e.EscrowDeposit=20]=`EscrowDeposit`,e[e.EscrowWithdraw=21]=`EscrowWithdraw`,e[e.Transfer=30]=`Transfer`,e[e.Commit=40]=`Commit`,e[e.Release=41]=`Release`,e[e.Rebalance=42]=`Rebalance`,e[e.Migrate=100]=`Migrate`,e[e.EscrowLock=110]=`EscrowLock`,e[e.MutualLock=120]=`MutualLock`,e[e.Finalize=200]=`Finalize`})(oA||={});function sA(e,t){return{id:``,transition:{type:X.Void,txId:``,amount:new R(0)},asset:e,userWallet:t,epoch:0n,version:0n,homeLedger:{tokenAddress:`0x0`,blockchainId:0n,userBalance:new R(0),userNetFlow:new R(0),nodeBalance:new R(0),nodeNetFlow:new R(0)}}}function cA(e,t,n,r){return{type:e,txId:t,accountId:n,amount:r}}function lA(e,t){return e.type===t.type?e.txId===t.txId?e.accountId===t.accountId?e.amount.equals(t.amount)?null:`amount mismatch: expected=${e.amount.toString()}, proposed=${t.amount.toString()}`:`account ID mismatch: expected=${e.accountId}, proposed=${t.accountId}`:`tx ID mismatch: expected=${e.txId}, proposed=${t.txId}`:`type mismatch: expected=${e.type}, proposed=${t.type}`}function uA(e,t){return e.tokenAddress.toLowerCase()===t.tokenAddress.toLowerCase()?e.blockchainId===t.blockchainId?e.userBalance.equals(t.userBalance)?e.userNetFlow.equals(t.userNetFlow)?e.nodeBalance.equals(t.nodeBalance)?e.nodeNetFlow.equals(t.nodeNetFlow)?null:`node net flow mismatch: expected=${e.nodeNetFlow.toString()}, proposed=${t.nodeNetFlow.toString()}`:`node balance mismatch: expected=${e.nodeBalance.toString()}, proposed=${t.nodeBalance.toString()}`:`user net flow mismatch: expected=${e.userNetFlow.toString()}, proposed=${t.userNetFlow.toString()}`:`user balance mismatch: expected=${e.userBalance.toString()}, proposed=${t.userBalance.toString()}`:`blockchain ID mismatch: expected=${e.blockchainId}, proposed=${t.blockchainId}`:`token address mismatch: expected=${e.tokenAddress}, proposed=${t.tokenAddress}`}function dA(e){if(!e.tokenAddress||e.tokenAddress===`0x0`)throw Error(`invalid token address`);if(e.blockchainId===0n)throw Error(`invalid blockchain ID`);if(e.userBalance.isNegative())throw Error(`user balance cannot be negative`);if(e.nodeBalance.isNegative())throw Error(`node balance cannot be negative`);let t=e.userBalance.add(e.nodeBalance),n=e.userNetFlow.add(e.nodeNetFlow);if(!t.equals(n))throw Error(`ledger balances do not match net flows: balances=${t.toString()}, net_flows=${n.toString()}`)}R.set({precision:50});function fA(e){switch(e.type){case X.Void:case X.TransferSend:case X.TransferReceive:case X.Commit:case X.Release:return 0;case X.Finalize:return 1;case X.HomeDeposit:return 2;case X.HomeWithdrawal:return 3;case X.MutualLock:return 4;case X.EscrowDeposit:return 5;case X.EscrowLock:return 6;case X.EscrowWithdraw:return 7;case X.Migrate:return 8;default:return 0}}function pA(e,t){let n=e.decimalPlaces();if(n>t)throw Error(`amount exceeds maximum decimal precision: max ${t} decimals allowed, got ${n}`)}function mA(e,t){let n=new R(10).pow(t),r=e.mul(n);if(!r.isInteger())throw Error(`amount ${e.toString()} exceeds maximum decimal precision: max ${t} decimals allowed`);return BigInt(r.toFixed(0))}function hA(e,t,n,r,i,a=`0x00`){let o=xA(n),s=dg(Ig([{name:`channelDefinition`,type:`tuple`,components:[{name:`challengeDuration`,type:`uint32`},{name:`user`,type:`address`},{name:`node`,type:`address`},{name:`nonce`,type:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`},{name:`metadata`,type:`bytes32`}]}],[{challengeDuration:i,user:t,node:e,nonce:r,approvedSignatureValidators:BigInt(a||`0x00`),metadata:o}]));return`0x${`1`.padStart(2,`0`)}${s.slice(4)}`}function gA(e,t){return dg(Ig([{type:`bytes32`},{type:`uint64`}],[e,t]))}function _A(e,t,n,r){return dg(Ig([{type:`address`},{type:`string`},{type:`uint256`},{type:`uint256`}],[e,t,n,r]))}function vA(e){return dg(Ig([{type:`tuple`,components:[{name:`type`,type:`uint8`},{name:`txId`,type:`bytes32`},{name:`accountId`,type:`bytes32`},{name:`amount`,type:`string`}]}],[{type:e.type,txId:SA(e.txId),accountId:CA(e.accountId),amount:e.amount.toString()}]))}function yA(e,t){return bA(e,t)}function bA(e,t){return dg(Ig([{type:`string`},{type:`bytes32`}],[e,t]))}function xA(e){return bh(kg(dg(Nh(e)),0,8),{dir:`right`,size:32})}function SA(e){let t=e.startsWith(`0x`)?e.slice(2):e;t.length%2==1&&(t=`0`+t);let n=[];for(let e=0;ee.toString(16).padStart(2,`0`)).join(``)}`,{dir:`left`,size:32})}function CA(e){if(!e||e===``)return`0x0000000000000000000000000000000000000000000000000000000000000000`;let t=e.startsWith(`0x`)?e.slice(2):e,n=t.length;if((n===40||n===64)&&/^[0-9a-fA-F]+$/.test(t))return n===40?bh(`0x${t}`,{size:32}):`0x${t}`;t.length%2==1&&(t=`0`+t);let r=[];for(let e=0;ee.toString(16).padStart(2,`0`)).join(``)}`,{dir:`left`,size:32})}function wA(e,t,n){return dg(Ig([{type:`uint64`},{type:`string[]`},{type:`uint64`}],[e,t,n]))}function TA(e,t){return Ig([{type:`address`},{type:`bytes32`}],[e,t])}function EA(e){return e.transition.type===X.Finalize}function DA(e){let t,n={type:X.Void,txId:``,amount:new R(0)};return t=EA(e)?{id:``,transition:n,asset:e.asset,userWallet:e.userWallet,epoch:e.epoch+1n,version:0n,homeChannelId:void 0,escrowChannelId:void 0,homeLedger:{tokenAddress:`0x0`,blockchainId:0n,userBalance:new R(0),userNetFlow:new R(0),nodeBalance:new R(0),nodeNetFlow:new R(0)},escrowLedger:void 0}:{id:``,transition:n,asset:e.asset,userWallet:e.userWallet,epoch:e.epoch,version:e.version+1n,homeChannelId:e.homeChannelId,escrowChannelId:e.escrowChannelId,homeLedger:{...e.homeLedger},escrowLedger:void 0},e.escrowLedger&&(t.escrowLedger={...e.escrowLedger},e.userSig?(e.transition.type===X.EscrowDeposit||e.transition.type===X.EscrowWithdraw)&&(t.escrowChannelId=void 0,t.escrowLedger=void 0):t.transition={...e.transition}),t.id=_A(t.userWallet,t.asset,t.epoch,t.version),t}function OA(e,t,n,r,i){e.homeLedger.tokenAddress=r,e.homeLedger.blockchainId=n;let a=hA(i,e.userWallet,e.asset,t.nonce,t.challenge,t.approvedSigValidators);return e.homeChannelId=a,a}function kA(e){if(e.transition.type!==X.Void)throw Error(`state already has a transition: ${e.transition.type}`);let t=`0x0000000000000000000000000000000000000000000000000000000000000000`,n=cA(X.Acknowledgement,t,t,new R(0));return e.transition=n,n}function AA(e,t){if(!e.homeChannelId)throw Error(`missing home channel ID`);let n=e.homeChannelId,r=yA(n,e.id),i=cA(X.HomeDeposit,r,n,t);return e.transition=i,e.homeLedger.userNetFlow=e.homeLedger.userNetFlow.add(i.amount),e.homeLedger.userBalance=e.homeLedger.userBalance.add(i.amount),i}function jA(e,t){if(!e.homeChannelId)throw Error(`missing home channel ID`);let n=e.homeChannelId,r=yA(n,e.id),i=cA(X.HomeWithdrawal,r,n,t);return e.transition=i,e.homeLedger.userNetFlow=e.homeLedger.userNetFlow.sub(i.amount),e.homeLedger.userBalance=e.homeLedger.userBalance.sub(i.amount),i}function MA(e,t,n){let r=t,i=yA(r,e.id),a=cA(X.TransferSend,i,r,n);return e.transition=a,e.homeLedger.userBalance=e.homeLedger.userBalance.sub(a.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.sub(a.amount),a}function NA(e,t,n){let r=yA(t,e.id),i=cA(X.Commit,r,t,n);return e.transition=i,e.homeLedger.userBalance=e.homeLedger.userBalance.sub(i.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.sub(i.amount),i}function PA(e,t,n,r){if(!e.homeChannelId)throw Error(`missing home channel ID`);if(t===0n)throw Error(`invalid blockchain ID`);if(!n||n===`0x0`)throw Error(`invalid token address`);let i=gA(e.homeChannelId,e.version);e.escrowChannelId=i;let a=i,o=yA(a,e.id),s=cA(X.MutualLock,o,a,r);return e.transition=s,e.homeLedger.nodeBalance=e.homeLedger.nodeBalance.add(s.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.add(s.amount),e.escrowLedger={blockchainId:t,tokenAddress:n,userBalance:new R(0).add(s.amount),userNetFlow:new R(0).add(s.amount),nodeBalance:new R(0),nodeNetFlow:new R(0)},s}function FA(e,t){if(!e.escrowChannelId)throw Error(`internal error: escrow channel ID is nil`);if(!e.escrowLedger)throw Error(`escrow ledger is nil`);let n=e.escrowChannelId,r=yA(n,e.id),i=cA(X.EscrowDeposit,r,n,t);return e.transition=i,e.homeLedger.userBalance=e.homeLedger.userBalance.add(i.amount),e.homeLedger.nodeBalance=new R(0),e.escrowLedger.userBalance=e.escrowLedger.userBalance.sub(i.amount),e.escrowLedger.nodeNetFlow=e.escrowLedger.nodeNetFlow.sub(i.amount),i}function IA(e,t,n,r){if(!e.homeChannelId)throw Error(`missing home channel ID`);if(t===0n)throw Error(`invalid blockchain ID`);if(!n||n===`0x0`)throw Error(`invalid token address`);let i=gA(e.homeChannelId,e.version);e.escrowChannelId=i;let a=i,o=yA(a,e.id),s=cA(X.EscrowLock,o,a,r);return e.transition=s,e.escrowLedger={blockchainId:t,tokenAddress:n,userBalance:new R(0),userNetFlow:new R(0),nodeBalance:new R(0).add(s.amount),nodeNetFlow:new R(0).add(s.amount)},s}function LA(e,t){if(!e.escrowChannelId)throw Error(`internal error: escrow channel ID is nil`);if(!e.escrowLedger)throw Error(`escrow ledger is nil`);let n=e.escrowChannelId,r=yA(n,e.id),i=cA(X.EscrowWithdraw,r,n,t);return e.transition=i,e.homeLedger.userBalance=e.homeLedger.userBalance.sub(i.amount),e.homeLedger.nodeNetFlow=e.homeLedger.nodeNetFlow.sub(i.amount),e.escrowLedger.userNetFlow=e.escrowLedger.userNetFlow.sub(i.amount),e.escrowLedger.nodeBalance=e.escrowLedger.nodeBalance.sub(i.amount),i}function RA(e,t){throw Error(`migrate transition not implemented yet`)}function zA(e){if(!e.homeChannelId)throw Error(`missing home channel ID`);let t=e.homeChannelId,n=e.homeLedger.userBalance,r=yA(t,e.id),i=cA(X.Finalize,r,t,n);return e.transition=i,e.homeLedger.userNetFlow=e.homeLedger.userNetFlow.sub(e.homeLedger.userBalance),e.homeLedger.userBalance=new R(0),i}var BA=class{constructor(e){this.assetStore=e}async packSigningData(e){if(!e.homeChannelId)throw Error(`state.homeChannelId is required for packing`);let t=e.homeChannelId,n=vA(e.transition),r=await this.assetStore.getTokenDecimals(e.homeLedger.blockchainId,e.homeLedger.tokenAddress),i={chainId:e.homeLedger.blockchainId,token:e.homeLedger.tokenAddress,decimals:r,userAllocation:mA(e.homeLedger.userBalance,r),userNetFlow:mA(e.homeLedger.userNetFlow,r),nodeAllocation:mA(e.homeLedger.nodeBalance,r),nodeNetFlow:mA(e.homeLedger.nodeNetFlow,r)},a;if(e.escrowLedger){let t=await this.assetStore.getTokenDecimals(e.escrowLedger.blockchainId,e.escrowLedger.tokenAddress);a={chainId:e.escrowLedger.blockchainId,token:e.escrowLedger.tokenAddress,decimals:t,userAllocation:mA(e.escrowLedger.userBalance,t),userNetFlow:mA(e.escrowLedger.userNetFlow,t),nodeAllocation:mA(e.escrowLedger.nodeBalance,t),nodeNetFlow:mA(e.escrowLedger.nodeNetFlow,t)}}else a={chainId:0n,token:`0x0000000000000000000000000000000000000000`,decimals:0,userAllocation:0n,userNetFlow:0n,nodeAllocation:0n,nodeNetFlow:0n};let o=fA(e.transition),s=[{name:`chainId`,type:`uint64`},{name:`token`,type:`address`},{name:`decimals`,type:`uint8`},{name:`userAllocation`,type:`uint256`},{name:`userNetFlow`,type:`int256`},{name:`nodeAllocation`,type:`uint256`},{name:`nodeNetFlow`,type:`int256`}];return{channelId:t,signingData:Ig([{type:`uint64`},{type:`uint8`},{type:`bytes32`},{type:`tuple`,components:s},{type:`tuple`,components:s}],[e.version,o,n,i,a])}}packWithChannelId(e,t){return Ig([{type:`bytes32`},{type:`bytes`}],[e,t])}async packState(e){let{channelId:t,signingData:n}=await this.packSigningData(e);return this.packWithChannelId(t,n)}async packChallengeState(e){let{channelId:t,signingData:n}=await this.packSigningData(e),r=Eg([n,Nh(`challenge`)]);return this.packWithChannelId(t,r)}};function VA(e){return new BA(e)}async function HA(e,t){return VA(t).packState(e)}async function UA(e,t){return VA(t).packChallengeState(e)}var WA=class{constructor(e){this.assetStore=e}async validateAdvancement(e,t){let n=DA(e);if(!t.homeChannelId)throw Error(`home channel ID cannot be nil`);if(n.homeChannelId||(n.homeChannelId=t.homeChannelId,n.homeLedger.blockchainId=t.homeLedger.blockchainId,n.homeLedger.tokenAddress=t.homeLedger.tokenAddress),t.homeChannelId!==n.homeChannelId)throw Error(`home channel ID mismatch: expected=${n.homeChannelId}, proposed=${t.homeChannelId}`);if(t.version!==n.version)throw Error(`version mismatch: expected=${n.version}, proposed=${t.version}`);if(t.userWallet.toLowerCase()!==n.userWallet.toLowerCase())throw Error(`user wallet mismatch: expected=${n.userWallet}, proposed=${t.userWallet}`);if(t.asset!==n.asset)throw Error(`asset mismatch: expected=${n.asset}, proposed=${t.asset}`);if(t.epoch!==n.epoch)throw Error(`epoch mismatch: expected=${n.epoch}, proposed=${t.epoch}`);if(t.id!==n.id)throw Error(`state ID mismatch: expected=${n.id}, proposed=${t.id}`);let r=t.transition,i=await this.assetStore.getAssetDecimals(t.asset);switch(pA(r.amount,i),r.type){case X.Acknowledgement:if(!r.amount.isZero())throw Error(`transition amount must be zero, got ${r.amount.toString()}`);break;case X.Finalize:if(r.amount.isNegative())throw Error(`transition amount must not be negative, got ${r.amount.toString()}`);break;default:if(r.amount.isNegative()||r.amount.isZero())throw Error(`transition amount must be positive, got ${r.amount.toString()}`)}let a=e.transition;switch(r.type){case X.Void:throw Error(`cannot apply void transition as new transition`);case X.Acknowledgement:if(e.userSig)throw Error(`current state is already acknowledged`);kA(n);break;case X.HomeDeposit:AA(n,r.amount);break;case X.HomeWithdrawal:jA(n,r.amount);break;case X.TransferSend:if(!r.accountId)throw Error(`missing account ID for transfer send transition`);MA(n,r.accountId,r.amount);break;case X.Commit:if(!r.accountId)throw Error(`missing account ID for commit transition`);NA(n,r.accountId,r.amount);break;case X.MutualLock:if(!t.escrowLedger)throw Error(`proposed state escrow ledger is nil`);PA(n,t.escrowLedger.blockchainId,t.escrowLedger.tokenAddress,r.amount);break;case X.EscrowDeposit:if(a.type===X.MutualLock){if(!a.amount.equals(r.amount))throw Error(`escrow deposit amount must be the same as mutual lock amount`);FA(n,r.amount)}else throw Error(`escrow deposit transition must follow a mutual lock transition`);break;case X.EscrowLock:if(!t.escrowLedger)throw Error(`proposed state escrow ledger is nil`);IA(n,t.escrowLedger.blockchainId,t.escrowLedger.tokenAddress,r.amount);break;case X.EscrowWithdraw:if(a.type===X.EscrowLock){if(!a.amount.equals(r.amount))throw Error(`escrow withdraw amount must be the same as escrow lock amount`);LA(n,r.amount)}else throw Error(`escrow withdraw transition must follow an escrow lock transition`);break;case X.Migrate:RA(n,r.amount);break;case X.Finalize:zA(n);break;default:throw Error(`unsupported type for new transition: ${r.type}`)}let o=n.transition,s=lA(o,r);if(s)throw Error(`new transition does not match expected: ${s}`);let c=uA(n.homeLedger,t.homeLedger);if(c)throw Error(`home ledger mismatch: ${c}`);if(dA(t.homeLedger),n.escrowChannelId!==void 0!=(t.escrowChannelId!==void 0))throw Error(`escrow channel ID presence mismatch`);if(n.escrowChannelId&&t.escrowChannelId&&n.escrowChannelId!==t.escrowChannelId)throw Error(`escrow channel ID mismatch: expected=${n.escrowChannelId}, proposed=${t.escrowChannelId}`);if(n.escrowLedger!==void 0!=(t.escrowLedger!==void 0))throw Error(`escrow ledger presence mismatch`);if(n.escrowLedger&&t.escrowLedger){let e=uA(n.escrowLedger,t.escrowLedger);if(e)throw Error(`escrow ledger mismatch: expected=${JSON.stringify(n.escrowLedger)}, proposed=${JSON.stringify(t.escrowLedger)}: ${e}`);if(dA(t.escrowLedger),t.escrowLedger.blockchainId===t.homeLedger.blockchainId)throw Error(`escrow ledger blockchain ID cannot match home ledger blockchain ID`)}}},GA;(function(e){e[e.Operate=0]=`Operate`,e[e.Deposit=1]=`Deposit`,e[e.Withdraw=2]=`Withdraw`,e[e.Close=3]=`Close`,e[e.Rebalance=4]=`Rebalance`})(GA||={});var KA;(function(e){e[e.Void=0]=`Void`,e[e.Open=1]=`Open`,e[e.Closed=2]=`Closed`})(KA||={});function qA(e,t){let n=[{name:`walletAddress`,type:`address`},{name:`signatureWeight`,type:`uint8`}],r=e.participants.map(e=>({walletAddress:e.walletAddress,signatureWeight:e.signatureWeight}));return dg(Ig([{type:`string`},{type:`tuple[]`,components:n},{type:`uint8`},{type:`uint64`},{type:`string`}],[e.applicationId,r,e.quorum,e.nonce,t]))}function JA(e){let t=[{name:`participant`,type:`address`},{name:`asset`,type:`string`},{name:`amount`,type:`string`}],n=e.allocations.map(e=>({participant:e.participant,asset:e.asset,amount:e.amount.toString()})),r=e.appSessionId;return dg(Ig([{type:`bytes32`},{type:`uint8`},{type:`uint64`},{type:`tuple[]`,components:t},{type:`string`}],[r,e.intent,e.version,n,e.sessionData]))}function YA(e){let t=dg(Nh(new TextEncoder().encode(e.metadata)));return dg(Ig([{type:`string`},{type:`address`},{type:`bytes32`},{type:`uint64`},{type:`bool`}],[e.id,e.owner_wallet,t,BigInt(e.version),e.creation_approval_not_required]))}function XA(e){let t=e.startsWith(`0x`)||e.startsWith(`0X`)?e.slice(2):e;return t.length%2==1&&(t=`0`+t),!/^[0-9a-fA-F]*$/.test(t)||t.length===0?bh(`0x00`,{size:32}):(t.length>64&&(t=t.slice(t.length-64)),`0x${t.padStart(64,`0`)}`)}function ZA(e){let t=e.application_ids.map(XA),n=e.app_session_ids.map(XA);return dg(Ig([{type:`address`},{type:`address`},{type:`uint64`},{type:`bytes32[]`},{type:`bytes32[]`},{type:`uint64`}],[e.user_address,e.session_key,BigInt(e.version),t,n,BigInt(e.expires_at)]))}var QA=`error`,$A=class extends Error{constructor(e){super(e),this.name=`RPCError`}},ej=new $A(`already connected`),tj=new $A(`not connected`);new $A(`connection timeout`),new $A(`error reading message`),new $A(`nil request`),new $A(`invalid request method`),new $A(`error marshaling request`),new $A(`error sending request`),new $A(`no response received`),new $A(`error sending ping`),new $A(`error dialing websocket`);var nj;(function(e){e[e.Req=1]=`Req`,e[e.Resp=2]=`Resp`,e[e.Event=3]=`Event`,e[e.RespErr=4]=`RespErr`})(nj||={});function rj(e,t){return typeof t==`bigint`||(e===`blockchain_id`||e===`epoch`||e===`version`||e===`nonce`)&&(typeof t==`number`||typeof t==`bigint`)?t.toString():t}function ij(e){return e==null?{}:JSON.parse(JSON.stringify(e,rj))}function aj(e){return e}function oj(e){let t=e[QA];return typeof t==`string`?Error(t):null}function sj(e){return e.type===nj.RespErr?oj(e.payload):null}function cj(e,t,n,r={}){return{type:e,requestId:t,method:n,payload:r,timestamp:Date.now()}}function lj(e,t,n={}){return cj(nj.Req,e,t,n)}function uj(e){let t=[e.type,e.requestId,e.method,e.payload,e.timestamp];return JSON.stringify(t,rj)}function dj(e){let t=JSON.parse(e);if(!Array.isArray(t)||t.length!==5)throw Error(`invalid RPCData: expected 5 elements in array`);let[n,r,i,a,o]=t;if(typeof n!=`number`)throw Error(`invalid type: expected number`);if(typeof r!=`number`)throw Error(`invalid requestId: expected number`);if(typeof i!=`string`)throw Error(`invalid method: expected string`);if(typeof a!=`object`||!a)throw Error(`invalid payload: expected object`);if(typeof o!=`number`)throw Error(`invalid timestamp: expected number`);return{type:n,requestId:r,method:i,payload:a,timestamp:o}}var fj=`channels.v1.get_home_channel`,pj=`channels.v1.get_escrow_channel`,mj=`channels.v1.get_channels`,hj=`channels.v1.get_latest_state`,gj=`channels.v1.request_creation`,_j=`channels.v1.submit_state`,vj=`channels.v1.submit_session_key_state`,yj=`channels.v1.get_last_key_states`,bj=`app_sessions.v1.submit_deposit_state`,xj=`app_sessions.v1.submit_app_state`,Sj=`app_sessions.v1.rebalance_app_sessions`,Cj=`app_sessions.v1.get_app_definition`,wj=`app_sessions.v1.get_app_sessions`,Tj=`app_sessions.v1.create_app_session`,Ej=`app_sessions.v1.submit_session_key_state`,Dj=`app_sessions.v1.get_last_key_states`,Oj=`apps.v1.get_apps`,kj=`apps.v1.submit_app_version`,Aj=`user.v1.get_balances`,jj=`user.v1.get_transactions`,Mj=`user.v1.get_action_allowances`,Nj=`node.v1.ping`,Pj=`node.v1.get_config`,Fj=`node.v1.get_assets`,Ij=class{constructor(e){this.dialer=e}async start(e,t){return this.dialer.dial(e,t)}async call(e,t,n){let r=lj(Math.floor(Math.random()*(2**53-1)),e,ij(t)),i=await this.dialer.call(r,n),a=sj(i);if(a)throw Error(`rpc returned error: ${a.message}`);return aj(i.payload)}async channelsV1GetHomeChannel(e,t){return this.call(fj,e,t)}async channelsV1GetEscrowChannel(e,t){return this.call(pj,e,t)}async channelsV1GetChannels(e,t){return this.call(mj,e,t)}async channelsV1GetLatestState(e,t){return this.call(hj,e,t)}async channelsV1RequestCreation(e,t){return this.call(gj,e,t)}async channelsV1SubmitState(e,t){return this.call(_j,e,t)}async channelsV1SubmitSessionKeyState(e,t){return this.call(vj,e,t)}async channelsV1GetLastKeyStates(e,t){return this.call(yj,e,t)}async appSessionsV1SubmitDepositState(e,t){return this.call(bj,e,t)}async appSessionsV1SubmitAppState(e,t){return this.call(xj,e,t)}async appSessionsV1RebalanceAppSessions(e,t){return this.call(Sj,e,t)}async appSessionsV1GetAppDefinition(e,t){return this.call(Cj,e,t)}async appSessionsV1GetAppSessions(e,t){return this.call(wj,e,t)}async appSessionsV1CreateAppSession(e,t){return this.call(Tj,e,t)}async appSessionsV1SubmitSessionKeyState(e,t){return this.call(Ej,e,t)}async appSessionsV1GetLastKeyStates(e,t){return this.call(Dj,e,t)}async appsV1GetApps(e,t){return this.call(Oj,e,t)}async appsV1SubmitAppVersion(e,t){return this.call(kj,e,t)}async userV1GetBalances(e,t){return this.call(Aj,e,t)}async userV1GetTransactions(e,t){return this.call(jj,e,t)}async userV1GetActionAllowances(e,t){return this.call(Mj,e,t)}async nodeV1Ping(e){await this.call(Nj,{},e)}async nodeV1GetConfig(e){return this.call(Pj,{},e)}async nodeV1GetAssets(e,t){return this.call(Fj,e,t)}async close(){return this.dialer.close()}isConnected(){return this.dialer.isConnected()}eventChannel(){return this.dialer.eventChannel()}},Lj={handshakeTimeout:5e3,eventChanSize:100},Rj=class{constructor(e=Lj){this.ws=null,this.responseSinks=new Map,this.eventQueue=[],this.eventResolvers=[],this.config=e}async dial(e,t){if(this.ws&&this.ws.readyState===WebSocket.OPEN)throw ej;return this.closeHandler=t,new Promise((t,n)=>{let r=new WebSocket(e),i=setTimeout(()=>{r.close(),n(Error(`WebSocket handshake timeout`))},this.config.handshakeTimeout);r.onopen=()=>{clearTimeout(i),this.ws=r,t()},r.onerror=()=>{clearTimeout(i);let e=Error(`WebSocket error`);this.ws===r&&this.handleClose(e),n(e)},r.onclose=()=>{clearTimeout(i),this.ws===r&&this.handleClose()},r.onmessage=e=>{this.handleMessage(e.data)}})}isConnected(){return this.ws!==null&&this.ws.readyState===WebSocket.OPEN}async call(e,t){if(!this.isConnected())throw tj;return new Promise((n,r)=>{if(t?.aborted){r(Error(`Request aborted`));return}let i=()=>{this.responseSinks.delete(e.requestId),r(Error(`Request aborted`))};t?.addEventListener(`abort`,i,{once:!0}),this.responseSinks.set(e.requestId,e=>{t?.removeEventListener(`abort`,i),n(e)});try{let t=uj(e);this.ws.send(t)}catch(n){this.responseSinks.delete(e.requestId),t?.removeEventListener(`abort`,i),r(n)}})}async*eventChannel(){for(;this.isConnected();)this.eventQueue.length>0?yield this.eventQueue.shift():yield await new Promise(e=>{this.eventResolvers.push(e)})}async close(){this.ws&&=(this.ws.close(),null)}handleMessage(e){try{let t=dj(e),n=this.responseSinks.get(t.requestId);n?(this.responseSinks.delete(t.requestId),n(t)):this.eventResolvers.length>0?this.eventResolvers.shift()(t):(this.eventQueue.push(t),this.eventQueue.length>this.config.eventChanSize&&this.eventQueue.shift())}catch(e){console.error(`Failed to parse WebSocket message:`,e)}}handleClose(e){this.ws=null;for(let[e,t]of this.responseSinks.entries())t({type:4,requestId:e,method:``,payload:{error:`Connection closed`},timestamp:Date.now()});this.responseSinks.clear(),this.closeHandler&&this.closeHandler(e)}},zj=class{constructor(e){this.cache=new Map,this.getAssetsFn=e}async getAssetDecimals(e){let t=this.cache.get(e.toLowerCase());if(t)return t.decimals;let n=await this.getAssetsFn();for(let t of n)if(this.cache.set(t.symbol.toLowerCase(),t),t.symbol.toLowerCase()===e.toLowerCase())return t.decimals;throw Error(`asset ${e} not found`)}async getTokenDecimals(e,t){if(this.cache.size===0){let e=await this.getAssetsFn();for(let t of e)this.cache.set(t.symbol.toLowerCase(),t)}let n=t.toLowerCase();for(let t of this.cache.values())for(let r of t.tokens)if(r.blockchainId===e&&r.address.toLowerCase()===n)return r.decimals;throw Error(`token ${t} on blockchain ${e} not found`)}async getTokenAddress(e,t){if(this.cache.size===0){let e=await this.getAssetsFn();for(let t of e)this.cache.set(t.symbol.toLowerCase(),t)}let n=e.toLowerCase();for(let r of this.cache.values())if(r.symbol.toLowerCase()===n){for(let e of r.tokens)if(e.blockchainId===t)return e.address;throw Error(`asset ${e} not available on blockchain ${t}`)}let r=await this.getAssetsFn();for(let i of r)if(this.cache.set(i.symbol.toLowerCase(),i),i.symbol.toLowerCase()===n){for(let e of i.tokens)if(e.blockchainId===t)return e.address;throw Error(`asset ${e} not available on blockchain ${t}`)}throw Error(`asset ${e} not found`)}async assetExistsOnBlockchain(e,t){let n=t.toLowerCase();for(let t of this.cache.values())if(t.symbol.toLowerCase()===n){for(let n of t.tokens)if(n.blockchainId===e)return!0;return!1}let r=await this.getAssetsFn();for(let t of r)if(this.cache.set(t.symbol.toLowerCase(),t),t.symbol.toLowerCase()===n){for(let n of t.tokens)if(n.blockchainId===e)return!0;return!1}return!1}async getSuggestedBlockchainId(e){let t=e.toLowerCase(),n=this.cache.get(t);if(n){if(n.suggestedBlockchainId===0n)throw Error(`no suggested blockchain ID for asset ${e}`);return n.suggestedBlockchainId}let r=await this.getAssetsFn();for(let e of r)this.cache.set(e.symbol.toLowerCase(),e);let i=this.cache.get(t);if(i){if(i.suggestedBlockchainId===0n)throw Error(`no suggested blockchain ID for asset ${e}`);return i.suggestedBlockchainId}throw Error(`asset ${e} not found`)}clearCache(){this.cache.clear()}};function Bj(e){e&&console.error(`[nitrolite]`,`connection error:`,e)}var Vj={handshakeTimeout:5e3,errorHandler:Bj,blockchainRPCs:new Map},Hj=`app_id`;function Uj(e,t){if(!t)return e;let n;try{n=new URL(e)}catch(t){let n=t instanceof Error?t.message:String(t);throw Error(`cannot append ${Hj}: invalid url ${JSON.stringify(e)} (${n})`)}return n.searchParams.set(Hj,t),n.toString()}function Wj(e,t){return n=>{n.blockchainRPCs||=new Map,n.blockchainRPCs.set(e,t)}}function Gj(){return BigInt(Date.now())*1000000n+BigInt(Math.floor(Math.random()*1e6))}function Kj(e){if(Array.isArray(e))return e;if(typeof e==`string`&&e.length>0){let t=atob(e);return Array.from(t,e=>e.charCodeAt(0))}return[]}function qj(e){let t=e.blockchains.map(e=>({name:e.name,id:BigInt(e.blockchain_id),channelHubAddress:e.channel_hub_address,lockingContractAddress:e.locking_contract_address,blockStep:0n}));return{nodeAddress:e.node_address,nodeVersion:e.node_version,supportedSigValidators:Kj(e.supported_sig_validators),blockchains:t}}function Jj(e){return e.map(e=>({name:e.name,symbol:e.symbol,decimals:e.decimals,suggestedBlockchainId:BigInt(e.suggested_blockchain_id),tokens:e.tokens.map(e=>({name:e.name,symbol:e.symbol,address:e.address,blockchainId:BigInt(e.blockchain_id),decimals:e.decimals}))}))}function Yj(e){return e.map(e=>({asset:e.asset,balance:new R(e.amount),enforced:new R(e.enforced)}))}function Xj(e){switch(e.toLowerCase()){case`home`:return nA.Home;case`escrow`:return nA.Escrow;default:return nA.Home}}function Zj(e){switch(e.toLowerCase()){case`void`:return aA.Void;case`open`:return aA.Open;case`challenged`:return aA.Challenged;case`closed`:return aA.Closed;default:return aA.Void}}function Qj(e){let t={channelId:e.channel_id,userWallet:e.user_wallet,asset:e.asset,type:Xj(e.type),blockchainId:BigInt(e.blockchain_id),tokenAddress:e.token_address,challengeDuration:e.challenge_duration,nonce:BigInt(e.nonce),approvedSigValidators:e.approved_sig_validators,status:Zj(e.status),stateVersion:BigInt(e.state_version)};return e.challenge_expires_at&&(t.challengeExpiresAt=new Date(e.challenge_expires_at)),t}function $j(e){return{tokenAddress:e.token_address,blockchainId:BigInt(e.blockchain_id),userBalance:new R(e.user_balance),userNetFlow:new R(e.user_net_flow),nodeBalance:new R(e.node_balance),nodeNetFlow:new R(e.node_net_flow)}}function eM(e){let t={type:e.type,txId:e.tx_id,amount:new R(e.amount)};return e.account_id&&(t.accountId=e.account_id),t}function tM(e){let t={id:e.id,transition:eM(e.transition),asset:e.asset,userWallet:e.user_wallet,epoch:BigInt(e.epoch),version:BigInt(e.version),homeLedger:$j(e.home_ledger)};return e.home_channel_id&&(t.homeChannelId=e.home_channel_id),e.escrow_channel_id&&(t.escrowChannelId=e.escrow_channel_id),e.escrow_ledger&&(t.escrowLedger=$j(e.escrow_ledger)),e.user_sig&&(t.userSig=e.user_sig),e.node_sig&&(t.nodeSig=e.node_sig),t}function nM(e){let t={id:e.id,asset:e.asset,txType:e.tx_type,fromAccount:e.from_account,toAccount:e.to_account,amount:new R(e.amount),createdAt:new Date(e.created_at)};return e.sender_new_state_id&&(t.senderNewStateId=e.sender_new_state_id),e.receiver_new_state_id&&(t.receiverNewStateId=e.receiver_new_state_id),t}function rM(e){return{page:e.page,perPage:e.per_page,totalCount:e.total_count,pageCount:e.page_count}}function iM(e){return{gatedAction:e.gated_action,timeWindow:e.time_window,allowance:BigInt(e.allowance),used:BigInt(e.used)}}function aM(e){return{application_id:e.applicationId,participants:e.participants.map(e=>({wallet_address:e.walletAddress,signature_weight:e.signatureWeight})),quorum:e.quorum,nonce:e.nonce.toString()}}function oM(e){return{app_session_id:e.appSessionId,intent:e.intent,version:e.version.toString(),allocations:e.allocations.map(e=>({participant:e.participant,asset:e.asset,amount:e.amount.toString()})),session_data:e.sessionData}}function sM(e){return{app_state_update:oM(e.appStateUpdate),quorum_sigs:e.quorumSigs}}function cM(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Invalid app session: expected object payload`);let t=e.allocations;if(!Array.isArray(t))throw Error(`Invalid app session allocations: expected allocations to be an array`);return{appSessionId:e.app_session_id,appDefinition:uM(e.app_definition),isClosed:e.status===`closed`,sessionData:e.session_data||``,version:BigInt(e.version),allocations:t.map(lM)}}function lM(e,t){let n=`app session allocation[${t}]`;if(!e||typeof e.participant!=`string`)throw Error(`Invalid ${n}: missing required string field participant`);if(typeof e.asset!=`string`)throw Error(`Invalid ${n}: missing required string field asset`);if(typeof e.amount!=`string`)throw Error(`Invalid ${n}: missing required string field amount`);return{participant:e.participant,asset:e.asset,amount:new R(e.amount)}}function uM(e){if(!e||typeof e!=`object`||Array.isArray(e)||!e.application_id||e.nonce===void 0||e.nonce===null)throw Error(`Invalid app definition: missing required fields (application_id, nonce)`);if(!Array.isArray(e.participants))throw Error(`Invalid app definition: expected participants to be an array`);if(e.quorum===void 0||e.quorum===null)throw Error(`Invalid app definition: missing required field quorum`);return{applicationId:e.application_id,participants:e.participants.map(dM),quorum:e.quorum,nonce:BigInt(e.nonce)}}function dM(e,t){let n=`app definition participant[${t}]`;if(!e||typeof e.wallet_address!=`string`)throw Error(`Invalid ${n}: missing required string field wallet_address`);if(typeof e.signature_weight!=`number`)throw Error(`Invalid ${n}: missing required numeric field signature_weight`);return{walletAddress:e.wallet_address,signatureWeight:e.signature_weight}}function fM(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Invalid ${t}: expected object`);return e}function pM(e,t,n){let r=fM(e,t)[n];if(typeof r!=`string`)throw Error(`Invalid ${t}: missing required string field ${n}`);return r}function mM(e,t,n){let r=fM(e,t)[n];if(!Array.isArray(r)||r.some(e=>typeof e!=`string`))throw Error(`Invalid ${t}: expected ${n} to be string[]`);return r}function hM(e,t=`channel session key state`){return{user_address:pM(e,t,`user_address`),session_key:pM(e,t,`session_key`),version:pM(e,t,`version`),assets:mM(e,t,`assets`),expires_at:pM(e,t,`expires_at`),user_sig:pM(e,t,`user_sig`)}}function gM(e,t=`app session key state`){return{user_address:pM(e,t,`user_address`),session_key:pM(e,t,`session_key`),version:pM(e,t,`version`),application_ids:mM(e,t,`application_ids`),app_session_ids:mM(e,t,`app_session_ids`),expires_at:pM(e,t,`expires_at`),user_sig:pM(e,t,`user_sig`)}}function _M(e,t,n,r){return{challengeDuration:e.challenge,user:n,node:r,nonce:e.nonce,approvedSignatureValidators:BigInt(e.approvedSigValidators||`0x00`),metadata:xA(t)}}async function vM(e,t){let n=await t(e.homeLedger.blockchainId,e.homeLedger.tokenAddress),r=yM(e.homeLedger,n),i;if(e.escrowLedger){let n=await t(e.escrowLedger.blockchainId,e.escrowLedger.tokenAddress);i=yM(e.escrowLedger,n)}else i={chainId:0n,token:`0x0000000000000000000000000000000000000000`,decimals:0,userAllocation:0n,userNetFlow:0n,nodeAllocation:0n,nodeNetFlow:0n};let a=SM(e.transition.type),o=vA(e.transition),s=e.userSig?e.userSig:`0x`,c=e.nodeSig?e.nodeSig:`0x`;return{version:e.version,intent:a,metadata:o,homeLedger:r,nonHomeLedger:i,userSig:s,nodeSig:c}}function yM(e,t){let n=mA(e.userBalance,t),r=mA(e.userNetFlow,t),i=mA(e.nodeBalance,t),a=mA(e.nodeNetFlow,t);return{chainId:e.blockchainId,token:e.tokenAddress,decimals:t,userAllocation:n,userNetFlow:r,nodeAllocation:i,nodeNetFlow:a}}function bM(e,t,n){let r=xM(e.homeLedger),i;e.nonHomeLedger.chainId!==0n&&(i=xM(e.nonHomeLedger));let a=t||void 0,o=n||void 0,s,c;return e.userSig&&e.userSig!==`0x`&&(s=e.userSig),e.nodeSig&&e.nodeSig!==`0x`&&(c=e.nodeSig),{id:``,transition:{type:X.Void,txId:``,amount:new R(0)},asset:``,userWallet:`0x0000000000000000000000000000000000000000`,epoch:0n,version:e.version,homeChannelId:a,escrowChannelId:o,homeLedger:r,escrowLedger:i,userSig:s,nodeSig:c}}function xM(e){let t=-e.decimals;return{blockchainId:e.chainId,tokenAddress:e.token,userBalance:new R(e.userAllocation.toString()).mul(R.pow(10,t)),userNetFlow:new R(e.userNetFlow.toString()).mul(R.pow(10,t)),nodeBalance:new R(e.nodeAllocation.toString()).mul(R.pow(10,t)),nodeNetFlow:new R(e.nodeNetFlow.toString()).mul(R.pow(10,t))}}function SM(e){switch(e){case X.HomeDeposit:return 2;case X.HomeWithdrawal:return 3;case X.Finalize:return 1;case X.EscrowDeposit:return 4;case X.EscrowWithdraw:return 6;case X.Migrate:return 8;default:return 0}}var CM=[{type:`function`,name:`name`,inputs:[],outputs:[{name:``,type:`string`}],stateMutability:`view`},{type:`function`,name:`symbol`,inputs:[],outputs:[{name:``,type:`string`}],stateMutability:`view`},{type:`function`,name:`decimals`,inputs:[],outputs:[{name:``,type:`uint8`}],stateMutability:`view`},{type:`function`,name:`totalSupply`,inputs:[],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`balanceOf`,inputs:[{name:`account`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`transfer`,inputs:[{name:`to`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[{name:``,type:`bool`}],stateMutability:`nonpayable`},{type:`function`,name:`allowance`,inputs:[{name:`owner`,type:`address`},{name:`spender`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`approve`,inputs:[{name:`spender`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[{name:``,type:`bool`}],stateMutability:`nonpayable`},{type:`function`,name:`transferFrom`,inputs:[{name:`from`,type:`address`},{name:`to`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[{name:``,type:`bool`}],stateMutability:`nonpayable`},{type:`event`,name:`Transfer`,inputs:[{name:`from`,type:`address`,indexed:!0},{name:`to`,type:`address`,indexed:!0},{name:`value`,type:`uint256`,indexed:!1}]},{type:`event`,name:`Approval`,inputs:[{name:`owner`,type:`address`,indexed:!0},{name:`spender`,type:`address`,indexed:!0},{name:`value`,type:`uint256`,indexed:!1}]}],wM=class{constructor(e,t,n){this.tokenAddress=e,this.client=t,this.walletSigner=n}async balanceOf(e){return this.client.readContract({address:this.tokenAddress,abi:CM,functionName:`balanceOf`,args:[e]})}async allowance(e,t){return this.client.readContract({address:this.tokenAddress,abi:CM,functionName:`allowance`,args:[e,t]})}async approve(e,t){if(!this.walletSigner)throw Error(`Wallet signer is required for approve operation`);try{let{request:n}=await this.client.simulateContract({address:this.tokenAddress,abi:CM,functionName:`approve`,args:[e,t],account:this.walletSigner.account.address}),r=await this.walletSigner.writeContract(n);return await this.client.waitForTransactionReceipt({hash:r}),r}catch(e){throw console.error(`❌ Approve simulation/execution failed!`),e.message&&console.error(` Reason:`,e.message),e}}async decimals(){throw Error(`decimals() not available in minimal ERC20 ABI`)}};function TM(e,t,n){return new wM(e,t,n)}var EM=[{type:`constructor`,inputs:[{name:`_defaultSigValidator`,type:`address`,internalType:`contract ISignatureValidator`},{name:`_node`,type:`address`,internalType:`address`}],stateMutability:`nonpayable`},{type:`function`,name:`DEFAULT_SIG_VALIDATOR`,inputs:[],outputs:[{name:``,type:`address`,internalType:`contract ISignatureValidator`}],stateMutability:`view`},{type:`function`,name:`ESCROW_DEPOSIT_UNLOCK_DELAY`,inputs:[],outputs:[{name:``,type:`uint32`,internalType:`uint32`}],stateMutability:`view`},{type:`function`,name:`MAX_DEPOSIT_ESCROW_STEPS`,inputs:[],outputs:[{name:``,type:`uint32`,internalType:`uint32`}],stateMutability:`view`},{type:`function`,name:`MIN_CHALLENGE_DURATION`,inputs:[],outputs:[{name:``,type:`uint32`,internalType:`uint32`}],stateMutability:`view`},{type:`function`,name:`NODE`,inputs:[],outputs:[{name:``,type:`address`,internalType:`address`}],stateMutability:`view`},{type:`function`,name:`TRANSFER_GAS_LIMIT`,inputs:[],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`VALIDATOR_ACTIVATION_DELAY`,inputs:[],outputs:[{name:``,type:`uint64`,internalType:`uint64`}],stateMutability:`view`},{type:`function`,name:`VERSION`,inputs:[],outputs:[{name:``,type:`uint8`,internalType:`uint8`}],stateMutability:`view`},{type:`function`,name:`challengeChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengerSig`,type:`bytes`,internalType:`bytes`},{name:`challengerIdx`,type:`uint8`,internalType:`enum ParticipantIndex`}],outputs:[],stateMutability:`payable`},{type:`function`,name:`challengeEscrowDeposit`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`challengerSig`,type:`bytes`,internalType:`bytes`},{name:`challengerIdx`,type:`uint8`,internalType:`enum ParticipantIndex`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`challengeEscrowWithdrawal`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`challengerSig`,type:`bytes`,internalType:`bytes`},{name:`challengerIdx`,type:`uint8`,internalType:`enum ParticipantIndex`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`checkpointChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`claimFunds`,inputs:[{name:`token`,type:`address`,internalType:`address`},{name:`destination`,type:`address`,internalType:`address`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`closeChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`createChannel`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`initState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`depositToChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`depositToNode`,inputs:[{name:`token`,type:`address`,internalType:`address`},{name:`amount`,type:`uint256`,internalType:`uint256`}],outputs:[],stateMutability:`payable`},{type:`function`,name:`escrowHead`,inputs:[],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`finalizeEscrowDeposit`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`finalizeEscrowWithdrawal`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`escrowId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`finalizeMigration`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`getChannelData`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`}],outputs:[{name:`status`,type:`uint8`,internalType:`enum ChannelStatus`},{name:`definition`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`lastState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpiry`,type:`uint256`,internalType:`uint256`},{name:`lockedFunds`,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`getChannelIds`,inputs:[{name:`user`,type:`address`,internalType:`address`}],outputs:[{name:``,type:`bytes32[]`,internalType:`bytes32[]`}],stateMutability:`view`},{type:`function`,name:`getEscrowDepositData`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`}],outputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`status`,type:`uint8`,internalType:`enum EscrowStatus`},{name:`unlockAt`,type:`uint64`,internalType:`uint64`},{name:`challengeExpiry`,type:`uint64`,internalType:`uint64`},{name:`lockedAmount`,type:`uint256`,internalType:`uint256`},{name:`initState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],stateMutability:`view`},{type:`function`,name:`getEscrowDepositIds`,inputs:[{name:`page`,type:`uint256`,internalType:`uint256`},{name:`pageSize`,type:`uint256`,internalType:`uint256`}],outputs:[{name:`ids`,type:`bytes32[]`,internalType:`bytes32[]`}],stateMutability:`view`},{type:`function`,name:`getEscrowWithdrawalData`,inputs:[{name:`escrowId`,type:`bytes32`,internalType:`bytes32`}],outputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`status`,type:`uint8`,internalType:`enum EscrowStatus`},{name:`challengeExpiry`,type:`uint64`,internalType:`uint64`},{name:`lockedAmount`,type:`uint256`,internalType:`uint256`},{name:`initState`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],stateMutability:`view`},{type:`function`,name:`getNodeBalance`,inputs:[{name:`token`,type:`address`,internalType:`address`}],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`getNodeValidator`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`}],outputs:[{name:`validator`,type:`address`,internalType:`contract ISignatureValidator`},{name:`registeredAt`,type:`uint64`,internalType:`uint64`}],stateMutability:`view`},{type:`function`,name:`getOpenChannels`,inputs:[{name:`user`,type:`address`,internalType:`address`}],outputs:[{name:`openChannels`,type:`bytes32[]`,internalType:`bytes32[]`}],stateMutability:`view`},{type:`function`,name:`getReclaimBalance`,inputs:[{name:`account`,type:`address`,internalType:`address`},{name:`token`,type:`address`,internalType:`address`}],outputs:[{name:``,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`getUnlockableEscrowDepositStats`,inputs:[],outputs:[{name:`count`,type:`uint256`,internalType:`uint256`},{name:`totalAmount`,type:`uint256`,internalType:`uint256`}],stateMutability:`view`},{type:`function`,name:`initiateEscrowDeposit`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`payable`},{type:`function`,name:`initiateEscrowWithdrawal`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`initiateMigration`,inputs:[{name:`def`,type:`tuple`,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`purgeEscrowDeposits`,inputs:[{name:`maxSteps`,type:`uint256`,internalType:`uint256`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`registerNodeValidator`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`},{name:`validator`,type:`address`,internalType:`contract ISignatureValidator`},{name:`signature`,type:`bytes`,internalType:`bytes`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`withdrawFromChannel`,inputs:[{name:`channelId`,type:`bytes32`,internalType:`bytes32`},{name:`candidate`,type:`tuple`,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`withdrawFromNode`,inputs:[{name:`to`,type:`address`,internalType:`address`},{name:`token`,type:`address`,internalType:`address`},{name:`amount`,type:`uint256`,internalType:`uint256`}],outputs:[],stateMutability:`nonpayable`},{type:`event`,name:`ChannelChallenged`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpireAt`,type:`uint64`,indexed:!1,internalType:`uint64`}],anonymous:!1},{type:`event`,name:`ChannelCheckpointed`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelClosed`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`finalState`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelCreated`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`user`,type:`address`,indexed:!0,internalType:`address`},{name:`definition`,type:`tuple`,indexed:!1,internalType:`struct ChannelDefinition`,components:[{name:`challengeDuration`,type:`uint32`,internalType:`uint32`},{name:`user`,type:`address`,internalType:`address`},{name:`node`,type:`address`,internalType:`address`},{name:`nonce`,type:`uint64`,internalType:`uint64`},{name:`approvedSignatureValidators`,type:`uint256`,internalType:`uint256`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`}]},{name:`initialState`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelDeposited`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`ChannelWithdrawn`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`candidate`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`Deposited`,inputs:[{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`EscrowDepositChallenged`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpireAt`,type:`uint64`,indexed:!1,internalType:`uint64`}],anonymous:!1},{type:`event`,name:`EscrowDepositFinalized`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositFinalizedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositInitiated`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositInitiatedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowDepositsPurged`,inputs:[{name:`purgedCount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalChallenged`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]},{name:`challengeExpireAt`,type:`uint64`,indexed:!1,internalType:`uint64`}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalFinalized`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalFinalizedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalInitiated`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`EscrowWithdrawalInitiatedOnHome`,inputs:[{name:`escrowId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`FundsClaimed`,inputs:[{name:`account`,type:`address`,indexed:!0,internalType:`address`},{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`destination`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`MigrationInFinalized`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`MigrationInInitiated`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`MigrationOutFinalized`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`MigrationOutInitiated`,inputs:[{name:`channelId`,type:`bytes32`,indexed:!0,internalType:`bytes32`},{name:`state`,type:`tuple`,indexed:!1,internalType:`struct State`,components:[{name:`version`,type:`uint64`,internalType:`uint64`},{name:`intent`,type:`uint8`,internalType:`enum StateIntent`},{name:`metadata`,type:`bytes32`,internalType:`bytes32`},{name:`homeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`nonHomeLedger`,type:`tuple`,internalType:`struct Ledger`,components:[{name:`chainId`,type:`uint64`,internalType:`uint64`},{name:`token`,type:`address`,internalType:`address`},{name:`decimals`,type:`uint8`,internalType:`uint8`},{name:`userAllocation`,type:`uint256`,internalType:`uint256`},{name:`userNetFlow`,type:`int256`,internalType:`int256`},{name:`nodeAllocation`,type:`uint256`,internalType:`uint256`},{name:`nodeNetFlow`,type:`int256`,internalType:`int256`}]},{name:`userSig`,type:`bytes`,internalType:`bytes`},{name:`nodeSig`,type:`bytes`,internalType:`bytes`}]}],anonymous:!1},{type:`event`,name:`NodeBalanceUpdated`,inputs:[{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`TransferFailed`,inputs:[{name:`recipient`,type:`address`,indexed:!0,internalType:`address`},{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`event`,name:`ValidatorRegistered`,inputs:[{name:`validatorId`,type:`uint8`,indexed:!0,internalType:`uint8`},{name:`validator`,type:`address`,indexed:!0,internalType:`contract ISignatureValidator`}],anonymous:!1},{type:`event`,name:`Withdrawn`,inputs:[{name:`token`,type:`address`,indexed:!0,internalType:`address`},{name:`amount`,type:`uint256`,indexed:!1,internalType:`uint256`}],anonymous:!1},{type:`error`,name:`AddressCollision`,inputs:[{name:`collision`,type:`address`,internalType:`address`}]},{type:`error`,name:`ChallengerVersionTooLow`,inputs:[]},{type:`error`,name:`ECDSAInvalidSignature`,inputs:[]},{type:`error`,name:`ECDSAInvalidSignatureLength`,inputs:[{name:`length`,type:`uint256`,internalType:`uint256`}]},{type:`error`,name:`ECDSAInvalidSignatureS`,inputs:[{name:`s`,type:`bytes32`,internalType:`bytes32`}]},{type:`error`,name:`EmptySignature`,inputs:[]},{type:`error`,name:`IncorrectAmount`,inputs:[]},{type:`error`,name:`IncorrectChallengeDuration`,inputs:[]},{type:`error`,name:`IncorrectChannelId`,inputs:[]},{type:`error`,name:`IncorrectChannelStatus`,inputs:[]},{type:`error`,name:`IncorrectMsgSender`,inputs:[]},{type:`error`,name:`IncorrectNode`,inputs:[]},{type:`error`,name:`IncorrectSignature`,inputs:[]},{type:`error`,name:`IncorrectStateIntent`,inputs:[]},{type:`error`,name:`IncorrectValue`,inputs:[]},{type:`error`,name:`InsufficientBalance`,inputs:[]},{type:`error`,name:`InvalidAddress`,inputs:[]},{type:`error`,name:`InvalidValidatorId`,inputs:[]},{type:`error`,name:`NativeTransferFailed`,inputs:[{name:`to`,type:`address`,internalType:`address`},{name:`amount`,type:`uint256`,internalType:`uint256`}]},{type:`error`,name:`NoChannelIdFoundForEscrow`,inputs:[]},{type:`error`,name:`ReentrancyGuardReentrantCall`,inputs:[]},{type:`error`,name:`SafeCastOverflowedIntToUint`,inputs:[{name:`value`,type:`int256`,internalType:`int256`}]},{type:`error`,name:`SafeERC20FailedOperation`,inputs:[{name:`token`,type:`address`,internalType:`address`}]},{type:`error`,name:`ValidatorAlreadyRegistered`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`}]},{type:`error`,name:`ValidatorNotActive`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`},{name:`activatesAt`,type:`uint64`,internalType:`uint64`}]},{type:`error`,name:`ValidatorNotApproved`,inputs:[]},{type:`error`,name:`ValidatorNotRegistered`,inputs:[{name:`validatorId`,type:`uint8`,internalType:`uint8`}]}],DM=class{constructor(e,t,n,r,i,a,o){this.contractAddress=e,this.evmClient=t,this.walletSigner=n,this.blockchainId=r,this.nodeAddress=i,this.assetStore=a,this.requireCheckAllowance=o?.requireCheckAllowance??!0,this.requireCheckBalance=o?.requireCheckBalance??!0}hexToBytes32(e){let t=Uh(e);if(t.length!==32)throw Error(`invalid length: expected 32 bytes, got ${t.length}`);return`0x${Array.from(t).map(e=>e.toString(16).padStart(2,`0`)).join(``)}`}async getAllowance(e,t){let n=await this.assetStore.getTokenAddress(e,this.blockchainId);if(n===`0x0000000000000000000000000000000000000000`)return new R(`1e18`);let r=await TM(n,this.evmClient).allowance(t,this.contractAddress),i=await this.assetStore.getTokenDecimals(this.blockchainId,n);return new R(r.toString()).div(R.pow(10,i))}async getTokenBalance(e,t){let n=await this.assetStore.getTokenAddress(e,this.blockchainId);if(n===`0x0000000000000000000000000000000000000000`)return new R((await this.evmClient.getBalance({address:t})).toString()).div(R.pow(10,18));let r=await TM(n,this.evmClient).balanceOf(t),i=await this.assetStore.getTokenDecimals(this.blockchainId,n);return new R(r.toString()).div(R.pow(10,i))}async checkAllowance(e,t){return await this.getAllowance(e,t)}async approve(e,t){let n=await this.assetStore.getTokenAddress(e,this.blockchainId);if(n===`0x0000000000000000000000000000000000000000`)throw Error(`Native tokens do not require approval`);let r=mA(t,await this.assetStore.getTokenDecimals(this.blockchainId,n));return await TM(n,this.evmClient,this.walletSigner).approve(this.contractAddress,r)}async approveTokenByAddress(e,t){return await TM(e,this.evmClient,this.walletSigner).approve(this.contractAddress,t)}async checkAllowanceByAddress(e,t){return await TM(e,this.evmClient).allowance(t,this.contractAddress)}async getNodeBalance(e){let t=await this.evmClient.readContract({address:this.contractAddress,abi:EM,functionName:`getNodeBalance`,args:[e]}),n=await this.assetStore.getTokenDecimals(this.blockchainId,e);return new R(t.toString()).div(R.pow(10,n))}async getOpenChannels(e){return(await this.evmClient.readContract({address:this.contractAddress,abi:EM,functionName:`getOpenChannels`,args:[e]})).map(e=>e)}async getHomeChannelData(e){let t=this.hexToBytes32(e),n=await this.evmClient.readContract({address:this.contractAddress,abi:EM,functionName:`getChannelData`,args:[t]}),[,r,i,a]=Array.isArray(n)?n:[n.status,n.definition,n.lastState,n.challengeExpiry,n.lockedFunds],o=bM(i,e);return{definition:{nonce:r.nonce,challenge:r.challengeDuration,approvedSigValidators:`0x`+(r.approvedSignatureValidators??0n).toString(16)},node:r.node,lastState:o,challengeExpiry:a}}async getEscrowDepositData(e){throw Error(`getEscrowDepositData not implemented - needs contract ABI update`)}async getEscrowWithdrawalData(e){throw Error(`getEscrowWithdrawalData not implemented - needs contract ABI update`)}async deposit(e,t){let n=mA(t,await this.assetStore.getTokenDecimals(this.blockchainId,e));console.log(`💳 EVM Client - Deposit transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),token:e,amount:t.toString(),amountBig:n.toString(),walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});try{console.log(`🔍 Simulating deposit...`);let{request:t}=await this.evmClient.simulateContract({address:this.contractAddress,abi:EM,functionName:`depositToNode`,args:[e,n],account:this.walletSigner.account.address,...e===`0x0000000000000000000000000000000000000000`?{value:n}:{}});console.log(`✅ Simulation successful - executing deposit...`);let r=await this.walletSigner.writeContract(t);console.log(`📤 Deposit transaction submitted - hash:`,r),console.log(`⏳ Waiting for confirmation...`);let i=await this.evmClient.waitForTransactionReceipt({hash:r});return console.log(`✅ Deposit transaction confirmed!`,{blockNumber:i.blockNumber,gasUsed:i.gasUsed.toString()}),r}catch(e){throw console.error(`❌ Deposit transaction failed at blockchain level`),(e.message?.includes(`not supported`)||e.message?.includes(`not available`))&&(console.error(`⚠️ RPC ENDPOINT ISSUE: The RPC endpoint does not support sending transactions.`),console.error(` This usually means the RPC only supports read operations (eth_call, eth_getBalance, etc.)`),console.error(` but not write operations (eth_sendTransaction).`),console.error(` Solutions:`),console.error(` 1. Use an RPC provider that supports transactions (Infura, Alchemy, etc.)`),console.error(` 2. Make sure your RPC endpoint includes transaction capabilities`)),e}}async withdraw(e,t,n){let r=mA(n,await this.assetStore.getTokenDecimals(this.blockchainId,t));console.log(`💳 EVM Client - Withdraw transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),to:e,token:t,amount:n.toString(),amountBig:r.toString(),walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});try{console.log(`🔍 Simulating withdrawal...`);let{request:n}=await this.evmClient.simulateContract({address:this.contractAddress,abi:EM,functionName:`withdrawFromNode`,args:[e,t,r],account:this.walletSigner.account.address});console.log(`✅ Simulation successful - executing withdrawal...`);let i=await this.walletSigner.writeContract(n);console.log(`📤 Withdraw transaction submitted - hash:`,i),console.log(`⏳ Waiting for confirmation...`);let a=await this.evmClient.waitForTransactionReceipt({hash:i});return console.log(`✅ Withdraw transaction confirmed!`,{blockNumber:a.blockNumber,gasUsed:a.gasUsed.toString()}),i}catch(e){throw console.error(`❌ Withdraw simulation/execution failed!`),e.message&&console.error(` Reason:`,e.message),e}}async create(e,t){let n=_M(e,t.asset,t.userWallet,this.nodeAddress),r=await vM(t,(e,t)=>this.assetStore.getTokenDecimals(e,t));if(t.transition.type===X.HomeDeposit||t.transition.type===X.EscrowDeposit){if(this.requireCheckAllowance&&(await this.getAllowance(t.asset,t.userWallet)).lessThan(t.transition.amount))throw Error(`Allowance is not sufficient to cover the deposit amount`);if(this.requireCheckBalance&&(await this.getTokenBalance(t.asset,t.userWallet)).lessThan(t.transition.amount))throw Error(`Balance is not sufficient to cover the deposit amount`)}console.log(`💳 EVM Client - Create channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});let i;(t.transition.type===X.HomeDeposit||t.transition.type===X.EscrowDeposit)&&r.homeLedger.token===`0x0000000000000000000000000000000000000000`&&(i=mA(t.transition.amount,r.homeLedger.decimals)),console.log(`🔍 Simulating transaction...`);try{let{request:e}=await this.evmClient.simulateContract({address:this.contractAddress,abi:EM,functionName:`createChannel`,args:[n,r],account:this.walletSigner.account.address,...i==null?{}:{value:i}});console.log(`✅ Simulation successful - executing transaction...`);let t=await this.walletSigner.writeContract(e);console.log(`📤 Transaction submitted - hash:`,t),console.log(`⏳ Waiting for confirmation...`);let a=await this.evmClient.waitForTransactionReceipt({hash:t});return console.log(`✅ Create channel transaction confirmed!`,{blockNumber:a.blockNumber,gasUsed:a.gasUsed.toString()}),t}catch(e){throw console.error(`❌ Transaction simulation failed!`),console.error(` This means the transaction would revert on-chain.`),e.message&&console.error(` Revert reason:`,e.message),e}}async checkpoint(e){if(!e.homeChannelId)throw Error(`Candidate state must have a home channel ID`);let t=this.hexToBytes32(e.homeChannelId),n=await vM(e,(e,t)=>this.assetStore.getTokenDecimals(e,t));if(e.transition.type===X.HomeDeposit){if(this.requireCheckAllowance&&(await this.getAllowance(e.asset,e.userWallet)).lessThan(e.transition.amount))throw Error(`Allowance is not sufficient to cover the deposit amount`);if(this.requireCheckBalance&&(await this.getTokenBalance(e.asset,e.userWallet)).lessThan(e.transition.amount))throw Error(`Balance is not sufficient to cover the deposit amount`);let r=n.homeLedger.token===`0x0000000000000000000000000000000000000000`?mA(e.transition.amount,n.homeLedger.decimals):void 0;console.log(`💳 EVM Client - Deposit to channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id});let i=await this.walletSigner.writeContract({address:this.contractAddress,abi:EM,functionName:`depositToChannel`,args:[t,n],gas:5000000n,...r==null?{}:{value:r}});return console.log(`✅ Deposit to channel transaction hash:`,i),i}if(e.transition.type===X.HomeWithdrawal){console.log(`💳 EVM Client - Withdraw from channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id});let e=await this.walletSigner.writeContract({address:this.contractAddress,abi:EM,functionName:`withdrawFromChannel`,args:[t,n],gas:5000000n});return console.log(`✅ Withdraw from channel transaction hash:`,e),e}console.log(`💳 EVM Client - Checkpoint channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id});let r=await this.walletSigner.writeContract({address:this.contractAddress,abi:EM,functionName:`checkpointChannel`,args:[t,n],gas:5000000n});return console.log(`✅ Checkpoint channel transaction hash:`,r),r}async challenge(e,t,n=0){if(!e.homeChannelId)throw Error(`Candidate state must have a home channel ID`);let r=this.hexToBytes32(e.homeChannelId),i=await vM(e,(e,t)=>this.assetStore.getTokenDecimals(e,t));console.log(`💳 EVM Client - Challenge channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:r,walletChain:this.walletSigner.chain?.id});let a=await this.walletSigner.writeContract({address:this.contractAddress,abi:EM,functionName:`challengeChannel`,args:[r,i,t,n],gas:5000000n});return console.log(`✅ Challenge channel transaction hash:`,a),a}async close(e){if(!e.homeChannelId)throw Error(`Candidate state must have a home channel ID`);let t=this.hexToBytes32(e.homeChannelId),n=await vM(e,(e,t)=>this.assetStore.getTokenDecimals(e,t));if(e.transition.type!==X.Finalize)throw Error(`Unsupported intent for close`);console.log(`💳 EVM Client - Close channel transaction:`,{contractAddress:this.contractAddress,blockchainId:this.blockchainId.toString(),channelId:t,walletChain:this.walletSigner.chain?.id,walletChainName:this.walletSigner.chain?.name});let r=await this.walletSigner.writeContract({address:this.contractAddress,abi:EM,functionName:`closeChannel`,args:[t,n],gas:5000000n});return console.log(`✅ Close channel transaction hash:`,r),r}async initiateEscrowDeposit(e,t){throw Error(`initiateEscrowDeposit not implemented - needs contract ABI update`)}async challengeEscrowDeposit(e,t,n=0){throw Error(`challengeEscrowDeposit not implemented - needs contract ABI update`)}async finalizeEscrowDeposit(e){throw Error(`finalizeEscrowDeposit not implemented - needs contract ABI update`)}async initiateEscrowWithdrawal(e,t){throw Error(`initiateEscrowWithdrawal not implemented - needs contract ABI update`)}async challengeEscrowWithdrawal(e,t,n=0){throw Error(`challengeEscrowWithdrawal not implemented - needs contract ABI update`)}async finalizeEscrowWithdrawal(e){throw Error(`finalizeEscrowWithdrawal not implemented - needs contract ABI update`)}async migrateChannelHere(e,t){throw Error(`migrateChannelHere not implemented - needs contract ABI update`)}},OM=[{type:`function`,name:`asset`,inputs:[],outputs:[{name:``,type:`address`}],stateMutability:`view`},{type:`function`,name:`UNLOCK_PERIOD`,inputs:[],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`balanceOf`,inputs:[{name:`user`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`lockStateOf`,inputs:[{name:`user`,type:`address`}],outputs:[{name:``,type:`uint8`}],stateMutability:`view`},{type:`function`,name:`unlockTimestampOf`,inputs:[{name:`user`,type:`address`}],outputs:[{name:``,type:`uint256`}],stateMutability:`view`},{type:`function`,name:`lock`,inputs:[{name:`target`,type:`address`},{name:`amount`,type:`uint256`}],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`relock`,inputs:[],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`unlock`,inputs:[],outputs:[],stateMutability:`nonpayable`},{type:`function`,name:`withdraw`,inputs:[{name:`destination`,type:`address`}],outputs:[],stateMutability:`nonpayable`}],kM=class{constructor(e,t,n){this.contractAddress=e,this.evmClient=t,this.walletSigner=n}requireWalletSigner(){if(!this.walletSigner)throw Error(`Write operations require a wallet signer. In Node.js, use a TransactionSigner that implements getAccount() (e.g., EthereumRawSigner)`);return this.walletSigner}async ensureTokenInfo(){if(this.tokenAddress!==void 0&&this.tokenDecimals!==void 0)return{address:this.tokenAddress,decimals:this.tokenDecimals};let e=await this.evmClient.readContract({address:this.contractAddress,abi:OM,functionName:`asset`}),t=await this.evmClient.readContract({address:e,abi:CM,functionName:`decimals`});return this.tokenAddress=e,this.tokenDecimals=t,{address:e,decimals:t}}async lock(e,t){let n=this.requireWalletSigner(),{decimals:r}=await this.ensureTokenInfo(),i=mA(t,r),{request:a}=await this.evmClient.simulateContract({address:this.contractAddress,abi:OM,functionName:`lock`,args:[e,i],account:n.account.address}),o=await n.writeContract(a);return await this.evmClient.waitForTransactionReceipt({hash:o}),o}async relock(){let e=this.requireWalletSigner(),{request:t}=await this.evmClient.simulateContract({address:this.contractAddress,abi:OM,functionName:`relock`,account:e.account.address}),n=await e.writeContract(t);return await this.evmClient.waitForTransactionReceipt({hash:n}),n}async unlock(){let e=this.requireWalletSigner(),{request:t}=await this.evmClient.simulateContract({address:this.contractAddress,abi:OM,functionName:`unlock`,account:e.account.address}),n=await e.writeContract(t);return await this.evmClient.waitForTransactionReceipt({hash:n}),n}async withdraw(e){let t=this.requireWalletSigner(),{request:n}=await this.evmClient.simulateContract({address:this.contractAddress,abi:OM,functionName:`withdraw`,args:[e],account:t.account.address}),r=await t.writeContract(n);return await this.evmClient.waitForTransactionReceipt({hash:r}),r}async approveToken(e){let t=this.requireWalletSigner(),{address:n,decimals:r}=await this.ensureTokenInfo(),i=mA(e,r),{request:a}=await this.evmClient.simulateContract({address:n,abi:CM,functionName:`approve`,args:[this.contractAddress,i],account:t.account.address}),o=await t.writeContract(a);return await this.evmClient.waitForTransactionReceipt({hash:o}),o}async getBalance(e){let{decimals:t}=await this.ensureTokenInfo();return new R((await this.evmClient.readContract({address:this.contractAddress,abi:OM,functionName:`balanceOf`,args:[e]})).toString()).div(R.pow(10,t))}async getLockState(e){return await this.evmClient.readContract({address:this.contractAddress,abi:OM,functionName:`lockStateOf`,args:[e]})}async getTokenDecimals(){let{decimals:e}=await this.ensureTokenInfo();return e}},AM=86400;function jM(e){if(e.length<6)throw Error(`signature too short to contain a signer type prefix: ${e}`);let t=parseInt(e.slice(2,4),16);if(t!==iA.Default)throw Error(`expected ChannelDefaultSigner prefix 0x00, got 0x${t.toString(16).padStart(2,`0`)}; session key signing requires the default wallet signer, not a session key signer`);return`0x${e.slice(4)}`}var MM=class e{constructor(e,t,n,r,i){this.rpcClient=e,this.config=t,this.stateSigner=n,this.txSigner=r,this.assetStore=i,this.blockchainClients=new Map,this.blockchainLockingClients=new Map,this.homeBlockchains=new Map,this.stateAdvancer=new WA(i),this.exitPromise=new Promise(e=>{this.exitResolve=e})}static async create(t,n,r,...i){let a={url:t,handshakeTimeout:Vj.handshakeTimeout,pingInterval:Vj.pingInterval,errorHandler:Vj.errorHandler,blockchainRPCs:Vj.blockchainRPCs||new Map};for(let e of i)e(a);let o=new Ij(new Rj),s;s=new e(o,a,n,r,new zj(async()=>await s.getAssets()));let c=e=>{e&&a.errorHandler&&a.errorHandler(e),s.exitResolve?.()},l=Uj(t,a.applicationID);return await o.start(l,c),s}async setHomeBlockchain(e,t){let n=this.homeBlockchains.get(e);if(n!==void 0)throw Error(`home blockchain is already set for asset ${e} to ${n}, please use Migrate() if you want to change home blockchain`);if(!await this.assetStore.assetExistsOnBlockchain(t,e))throw Error(`asset ${e} not supported on blockchain ${t}`);this.homeBlockchains.set(e,t)}async close(){this.exitResolve?.()}waitForClose(){return this.exitPromise}async signState(e){let t=await HA(e,this.assetStore);return await this.stateSigner.signMessage(t)}getUserAddress(){return this.stateSigner.getAddress()}async validateAndSignState(e,t){return await this.stateAdvancer.validateAdvancement(e,t),this.signState(t)}async signAndSubmitState(e,t){t.userSig=await this.validateAndSignState(e,t);let n=await this.submitState(t);return t.nodeSig=n,n}async deposit(e,t,n){let r=this.getUserAddress(),i=await this.getNodeAddress();if(!i)throw Error(`node address is undefined - ensure node config is properly loaded`);let a=await this.assetStore.getTokenAddress(t,e);if(!a)throw Error(`token address not found for asset ${t} on blockchain ${e}`);let o=null,s=!1;try{o=await this.getLatestState(r,t,!1),o&&o.homeChannelId&&(s=o.transition.type!==X.Finalize)}catch{}if(!o||!s){let s=await this.getSupportedSigValidatorsBitmap(),c={nonce:Gj(),challenge:AM,approvedSigValidators:s};o||=sA(t,r);let l=DA(o);return OA(l,c,e,a,i),AA(l,n),l.userSig=await this.signState(l),l.nodeSig=await this.requestChannelCreation(l,c),l}let c=DA(o);return AA(c,n),await this.signAndSubmitState(o,c),c}async withdraw(e,t,n){let r=this.getUserAddress(),i=await this.getNodeAddress();if(!i)throw Error(`node address is undefined - ensure node config is properly loaded`);let a=await this.assetStore.getTokenAddress(t,e);if(!a)throw Error(`token address not found for asset ${t} on blockchain ${e}`);let o=null,s=!1;try{o=await this.getLatestState(r,t,!1),o&&o.homeChannelId&&(s=o.transition.type!==X.Finalize)}catch{}if(!o||!s){let s=await this.getSupportedSigValidatorsBitmap(),c={nonce:Gj(),challenge:AM,approvedSigValidators:s};o||=sA(t,r);let l=DA(o);return OA(l,c,e,a,i),jA(l,n),l.userSig=await this.signState(l),l.nodeSig=await this.requestChannelCreation(l,c),l}let c=DA(o);return jA(c,n),await this.signAndSubmitState(o,c),c}async transfer(e,t,n){let r=this.getUserAddress(),i=null;try{i=await this.getLatestState(r,t,!1)}catch{}if(!i||!i.homeChannelId){let a=await this.getSupportedSigValidatorsBitmap(),o={nonce:Gj(),challenge:AM,approvedSigValidators:a};i||=sA(t,r);let s=DA(i),c=this.homeBlockchains.get(t);c||=i.homeLedger.blockchainId===0n?await this.assetStore.getSuggestedBlockchainId(t):i.homeLedger.blockchainId;let l=await this.getNodeAddress();if(!l)throw Error(`node address is undefined - ensure node config is properly loaded`);let u=await this.assetStore.getTokenAddress(t,c);if(!u)throw Error(`token address not found for asset ${t} on blockchain ${c}`);return OA(s,o,c,u,l),MA(s,e,n),s.userSig=await this.signState(s),s.nodeSig=await this.requestChannelCreation(s,o),s}let a=DA(i);return MA(a,e,n),await this.signAndSubmitState(i,a),a}async acknowledge(e){let t=this.getUserAddress(),n=null;try{n=await this.getLatestState(t,e,!1)}catch{}if(n?.userSig)throw Error(`state already acknowledged by user`);if(!n||!n.homeChannelId){let r=await this.getSupportedSigValidatorsBitmap(),i={nonce:Gj(),challenge:AM,approvedSigValidators:r};n||=sA(e,t);let a=DA(n),o=this.homeBlockchains.get(e);o||=n.homeLedger.blockchainId===0n?await this.assetStore.getSuggestedBlockchainId(e):n.homeLedger.blockchainId;let s=await this.getNodeAddress();if(!s)throw Error(`node address is undefined - ensure node config is properly loaded`);let c=await this.assetStore.getTokenAddress(e,o);if(!c)throw Error(`token address not found for asset ${e} on blockchain ${o}`);return OA(a,i,o,c,s),kA(a),a.userSig=await this.signState(a),a.nodeSig=await this.requestChannelCreation(a,i),a}let r=DA(n);return kA(r),await this.signAndSubmitState(n,r),r}async closeHomeChannel(e){let t=this.getUserAddress(),n=await this.getLatestState(t,e,!1);if(!n.homeChannelId)throw Error(`no channel exists for asset ${e}`);let r=DA(n);return zA(r),await this.signAndSubmitState(n,r),r}async checkpoint(e){let t=this.getUserAddress(),n=await this.getLatestState(t,e,!0);if(!n.homeChannelId)throw Error(`no channel exists for asset ${e}`);let r=n.homeLedger.blockchainId;await this.initializeBlockchainClient(r);let i=this.blockchainClients.get(r),a=await this.getHomeChannel(t,e);switch(n.transition.type){case X.Acknowledgement:case X.HomeDeposit:case X.HomeWithdrawal:case X.TransferSend:case X.TransferReceive:case X.Commit:case X.Release:if(a.status===aA.Void){let e={nonce:a.nonce,challenge:a.challengeDuration,approvedSigValidators:a.approvedSigValidators};return await i.create(e,n)}return await i.checkpoint(n);case X.Finalize:return await i.close(n);default:throw Error(`transition type ${n.transition.type} does not require a blockchain operation`)}}async challenge(e){if(!e.userSig||!e.nodeSig)throw Error(`state must have both user and node signatures`);if(!e.homeChannelId)throw Error(`state must have a home channel ID`);let t=await HA(e,this.assetStore),n=`0x${e.userSig.slice(4)}`;if(!await OO({address:e.userWallet,message:{raw:t},signature:n}))throw Error(`invalid user signature`);let r=await this.getNodeAddress(),i=`0x${e.nodeSig.slice(4)}`;if(!await OO({address:r,message:{raw:t},signature:i}))throw Error(`invalid node signature`);let a=await UA(e,this.assetStore),o=await this.stateSigner.signMessage(a),s=e.homeLedger.blockchainId;return await this.initializeBlockchainClient(s),await this.blockchainClients.get(s).challenge(e,o)}async approveToken(e,t,n){return await this.initializeBlockchainClient(e),await this.blockchainClients.get(e).approve(t,n)}async getOnChainBalance(e,t,n){return await this.initializeBlockchainClient(e),await this.blockchainClients.get(e).getTokenBalance(t,n)}async checkTokenAllowance(e,t,n){return await this.initializeBlockchainClient(e),await this.blockchainClients.get(e).checkAllowanceByAddress(t,n)}async escrowSecurityTokens(e,t,n){return await this.initializeLockingClient(t),this.blockchainLockingClients.get(t).lock(e,n)}async initiateSecurityTokensWithdrawal(e){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).unlock()}async cancelSecurityTokensWithdrawal(e){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).relock()}async withdrawSecurityTokens(e,t){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).withdraw(t)}async approveSecurityToken(e,t){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).approveToken(t)}async getLockedBalance(e,t){return await this.initializeLockingClient(e),this.blockchainLockingClients.get(e).getBalance(t)}async ping(){await this.rpcClient.nodeV1Ping()}async getConfig(){return qj(await this.rpcClient.nodeV1GetConfig())}async getBlockchains(){return(await this.getConfig()).blockchains}async getAssets(e){let t={};return e!==void 0&&(t.blockchain_id=e),Jj((await this.rpcClient.nodeV1GetAssets(t)).assets)}async getBalances(e){let t={wallet:e};return Yj((await this.rpcClient.userV1GetBalances(t)).balances)}async getTransactions(e,t){let n={wallet:e,asset:t?.asset,tx_type:t?.txType,from_time:t?.fromTime,to_time:t?.toTime,pagination:t?.page&&t?.pageSize?{offset:(t.page-1)*t.pageSize,limit:t.pageSize}:void 0},r=await this.rpcClient.userV1GetTransactions(n);return{transactions:r.transactions.map(nM),metadata:rM(r.metadata)}}async getActionAllowances(e){let t={wallet:e};return(await this.rpcClient.userV1GetActionAllowances(t)).allowances.map(iM)}async getChannels(e,t){let n={wallet:e,status:t?.status,asset:t?.asset,channel_type:t?.channelType,pagination:t?.pagination?{offset:t.pagination.offset,limit:t.pagination.limit}:void 0},r=await this.rpcClient.channelsV1GetChannels(n);return{channels:r.channels.map(Qj),metadata:rM(r.metadata)}}async getHomeChannel(e,t){let n={wallet:e,asset:t};return Qj((await this.rpcClient.channelsV1GetHomeChannel(n)).channel)}async getEscrowChannel(e){let t={escrow_channel_id:e};return Qj((await this.rpcClient.channelsV1GetEscrowChannel(t)).channel)}async getLatestState(e,t,n){let r={wallet:e,asset:t,only_signed:n};return tM((await this.rpcClient.channelsV1GetLatestState(r)).state)}async getAppSessions(e){let t={app_session_id:e?.appSessionId,participant:e?.wallet,status:e?.status,pagination:e?.page&&e?.pageSize?{offset:(e.page-1)*e.pageSize,limit:e.pageSize}:void 0},n=await this.rpcClient.appSessionsV1GetAppSessions(t);return{sessions:n.app_sessions.map(cM),metadata:rM(n.metadata)}}async getAppDefinition(e){let t={app_session_id:e};return uM((await this.rpcClient.appSessionsV1GetAppDefinition(t)).definition)}async createAppSession(e,t,n,r){let i={definition:aM(e),session_data:t,quorum_sigs:n};r?.ownerSig&&(i.owner_sig=r.ownerSig);let a=await this.rpcClient.appSessionsV1CreateAppSession(i);return{appSessionId:a.app_session_id,version:a.version,status:a.status}}async submitAppSessionDeposit(e,t,n,r){let i=DA(await this.getLatestState(this.getUserAddress(),n,!1));NA(i,e.appSessionId,r);let a=oM(e);i.userSig=await this.signState(i);let o={app_state_update:a,quorum_sigs:t,user_state:this.transformStateToRPC(i)};return(await this.rpcClient.appSessionsV1SubmitDepositState(o)).signature}async submitAppState(e,t){let n={app_state_update:oM(e),quorum_sigs:t};await this.rpcClient.appSessionsV1SubmitAppState(n)}async rebalanceAppSessions(e){let t={signed_updates:e.map(sM)};return(await this.rpcClient.appSessionsV1RebalanceAppSessions(t)).batch_id}async getApps(e){let t={app_id:e?.appId,owner_wallet:e?.ownerWallet,pagination:e?.page&&e?.pageSize?{offset:(e.page-1)*e.pageSize,limit:e.pageSize}:void 0},n=await this.rpcClient.appsV1GetApps(t);return{apps:n.apps,metadata:rM(n.metadata)}}async registerApp(e,t,n){let r={id:e,owner_wallet:this.txSigner.getAddress(),metadata:t,version:`1`,creation_approval_not_required:n},i=YA(r);if(!this.txSigner.signPersonalMessage)throw Error(`TransactionSigner must implement signPersonalMessage for app registration`);let a={app:r,owner_sig:await this.txSigner.signPersonalMessage(i)};await this.rpcClient.appsV1SubmitAppVersion(a)}async signChannelSessionKeyState(e){let t=wA(BigInt(e.version),e.assets,BigInt(e.expires_at)),n=TA(e.session_key,t);return jM(await this.stateSigner.signMessage(n))}async submitChannelSessionKeyState(e){let t={state:e};await this.rpcClient.channelsV1SubmitSessionKeyState(t)}async getLastChannelKeyStates(e,t){let n={user_address:e,session_key:t},r=await this.rpcClient.channelsV1GetLastKeyStates(n);if(!Array.isArray(r.states))throw Error(`Invalid channel key states response: expected states to be an array`);return r.states.map((e,t)=>hM(e,`channel session key state[${t}]`))}async signSessionKeyState(e){let t=ZA(e);return jM(await this.stateSigner.signMessage(t))}async submitSessionKeyState(e){let t={state:e};await this.rpcClient.appSessionsV1SubmitSessionKeyState(t)}async getLastKeyStates(e,t){let n={user_address:e,session_key:t},r=await this.rpcClient.appSessionsV1GetLastKeyStates(n);if(!Array.isArray(r.states))throw Error(`Invalid app key states response: expected states to be an array`);return r.states.map((e,t)=>gM(e,`app session key state[${t}]`))}async getBlockchainRPCInfo(e){let t=this.config.blockchainRPCs?.get(e);if(!t)throw Error(`blockchain RPC not configured for chain ${e} (use withBlockchainRPC)`);let n=await this.getConfig(),r=n.blockchains.find(t=>t.id===e);if(!r)throw Error(`blockchain ${e} not found in node config`);return{rpcUrl:t,blockchainInfo:r,config:n}}createEVMClients(e,t){let n=Ak({transport:tA(t)}),r={id:Number(e),name:`Chain ${e}`,nativeCurrency:{name:`ETH`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[t]},public:{http:[t]}}},i=typeof window<`u`&&window.ethereum!==void 0,a=null;if(i)a=Zk({chain:r,transport:$k(window.ethereum),account:this.txSigner.getAddress()});else{let e=this.txSigner.getAccount?this.txSigner.getAccount():void 0;e&&(a=Zk({chain:r,transport:tA(t),account:e}))}return{publicClient:n,walletClient:a}}async initializeBlockchainClient(e){if(this.blockchainClients.has(e))return;let{rpcUrl:t,blockchainInfo:n,config:r}=await this.getBlockchainRPCInfo(e);if(!n.channelHubAddress)throw Error(`channel hub address not configured for blockchain ${e}`);let{publicClient:i,walletClient:a}=this.createEVMClients(e,t);if(!a)throw Error(`Node.js environment requires a TransactionSigner that implements getAccount() (e.g., EthereumRawSigner)`);let o=new DM(n.channelHubAddress,i,a,e,r.nodeAddress,this.assetStore);this.blockchainClients.set(e,o)}async initializeLockingClient(e){if(this.blockchainLockingClients.has(e))return;let{rpcUrl:t,blockchainInfo:n}=await this.getBlockchainRPCInfo(e);if(!n.lockingContractAddress)throw Error(`locking contract address not configured for blockchain ${e}`);let{publicClient:r,walletClient:i}=this.createEVMClients(e,t),a=new kM(n.lockingContractAddress,r,i||void 0);this.blockchainLockingClients.set(e,a)}buildSigValidatorsBitmap(e){let t=new Uint8Array(32);for(let n of e){let e=n&255;t[31-Math.floor(e/8)]|=1<e.toString(16).padStart(2,`0`)).join(``);return`0x00`}async getSupportedSigValidatorsBitmap(){let e=await this.getConfig();return this.buildSigValidatorsBitmap(e.supportedSigValidators)}async getNodeAddress(){return(await this.getConfig()).nodeAddress}async submitState(e){let t={state:this.transformStateToRPC(e)};return(await this.rpcClient.channelsV1SubmitState(t)).signature}async requestChannelCreation(e,t){let n={state:this.transformStateToRPC(e),channel_definition:this.transformChannelDefinitionToRPC(t)};return(await this.rpcClient.channelsV1RequestCreation(n)).signature}transformStateToRPC(e){return{id:e.id,transition:{type:e.transition.type,tx_id:e.transition.txId,account_id:e.transition.accountId||``,amount:e.transition.amount.toString()},asset:e.asset,user_wallet:e.userWallet,epoch:e.epoch.toString(),version:e.version.toString(),home_channel_id:e.homeChannelId,escrow_channel_id:e.escrowChannelId,home_ledger:{token_address:e.homeLedger.tokenAddress,blockchain_id:e.homeLedger.blockchainId.toString(),user_balance:e.homeLedger.userBalance.toString(),user_net_flow:e.homeLedger.userNetFlow.toString(),node_balance:e.homeLedger.nodeBalance.toString(),node_net_flow:e.homeLedger.nodeNetFlow.toString()},escrow_ledger:e.escrowLedger?{token_address:e.escrowLedger.tokenAddress,blockchain_id:e.escrowLedger.blockchainId.toString(),user_balance:e.escrowLedger.userBalance.toString(),user_net_flow:e.escrowLedger.userNetFlow.toString(),node_balance:e.escrowLedger.nodeBalance.toString(),node_net_flow:e.escrowLedger.nodeNetFlow.toString()}:void 0,user_sig:e.userSig,node_sig:e.nodeSig}}transformChannelDefinitionToRPC(e){return{nonce:e.nonce.toString(),challenge:e.challenge,approved_sig_validators:e.approvedSigValidators}}transitionTypeToString(e){return{[X.Void]:`void`,[X.Acknowledgement]:`acknowledgement`,[X.HomeDeposit]:`home_deposit`,[X.HomeWithdrawal]:`home_withdrawal`,[X.EscrowDeposit]:`escrow_deposit`,[X.EscrowWithdraw]:`escrow_withdraw`,[X.TransferSend]:`transfer_send`,[X.TransferReceive]:`transfer_receive`,[X.Commit]:`commit`,[X.Release]:`release`,[X.Migrate]:`migrate`,[X.EscrowLock]:`escrow_lock`,[X.MutualLock]:`mutual_lock`,[X.Finalize]:`finalize`}[e]||`home_deposit`}},NM=class{constructor(e){this.inner=e}getAddress(){return this.inner.getAddress()}async signMessage(e){return`0x00${(await this.inner.signMessage(e)).slice(2)}`}},PM=class{constructor(e){this.inner=e}getAddress(){return this.inner.getAddress()}async signMessage(e){return`0xa1${(await this.inner.signMessage(e)).slice(2)}`}},FM=ew({id:11155111,name:`Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://11155111.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://sepolia.etherscan.io`,apiUrl:`https://api-sepolia.etherscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:751532},ensUniversalResolver:{address:`0xeeeeeeee14d718c2b47d9923deab1335e144eeee`,blockCreated:8928790}},testnet:!0}),IM=(e,t)=>{let n=Array(e.length+t.length);for(let t=0;t({classGroupId:e,validator:t}),RM=(e=new Map,t=null,n)=>({nextPart:e,validators:t,classGroupId:n}),zM=`-`,BM=[],VM=`arbitrary..`,HM=e=>{let t=GM(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:e=>{if(e.startsWith(`[`)&&e.endsWith(`]`))return WM(e);let n=e.split(zM);return UM(n,+(n[0]===``&&n.length>1),t)},getConflictingClassGroupIds:(e,t)=>{if(t){let t=r[e],i=n[e];return t?i?IM(i,t):t:i||BM}return n[e]||BM}}},UM=(e,t,n)=>{if(e.length-t===0)return n.classGroupId;let r=e[t],i=n.nextPart.get(r);if(i){let n=UM(e,t+1,i);if(n)return n}let a=n.validators;if(a===null)return;let o=t===0?e.join(zM):e.slice(t).join(zM),s=a.length;for(let e=0;ee.slice(1,-1).indexOf(`:`)===-1?void 0:(()=>{let t=e.slice(1,-1),n=t.indexOf(`:`),r=t.slice(0,n);return r?VM+r:void 0})(),GM=e=>{let{theme:t,classGroups:n}=e;return KM(n,t)},KM=(e,t)=>{let n=RM();for(let r in e){let i=e[r];qM(i,n,r,t)}return n},qM=(e,t,n,r)=>{let i=e.length;for(let a=0;a{if(typeof e==`string`){YM(e,t,n);return}if(typeof e==`function`){XM(e,t,n,r);return}ZM(e,t,n,r)},YM=(e,t,n)=>{let r=e===``?t:QM(t,e);r.classGroupId=n},XM=(e,t,n,r)=>{if($M(e)){qM(e(r),t,n,r);return}t.validators===null&&(t.validators=[]),t.validators.push(LM(n,e))},ZM=(e,t,n,r)=>{let i=Object.entries(e),a=i.length;for(let e=0;e{let n=e,r=t.split(zM),i=r.length;for(let e=0;e`isThemeGetter`in e&&e.isThemeGetter===!0,eN=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,n=Object.create(null),r=Object.create(null),i=(i,a)=>{n[i]=a,t++,t>e&&(t=0,r=n,n=Object.create(null))};return{get(e){let t=n[e];if(t!==void 0)return t;if((t=r[e])!==void 0)return i(e,t),t},set(e,t){e in n?n[e]=t:i(e,t)}}},tN=`!`,nN=`:`,rN=[],iN=(e,t,n,r,i)=>({modifiers:e,hasImportantModifier:t,baseClassName:n,maybePostfixModifierPosition:r,isExternal:i}),aN=e=>{let{prefix:t,experimentalParseClassName:n}=e,r=e=>{let t=[],n=0,r=0,i=0,a,o=e.length;for(let s=0;si?a-i:void 0;return iN(t,l,c,u)};if(t){let e=t+nN,n=r;r=t=>t.startsWith(e)?n(t.slice(e.length)):iN(rN,!1,t,void 0,!0)}if(n){let e=r;r=t=>n({className:t,parseClassName:e})}return r},oN=e=>{let t=new Map;return e.orderSensitiveModifiers.forEach((e,n)=>{t.set(e,1e6+n)}),e=>{let n=[],r=[];for(let i=0;i0&&(r.sort(),n.push(...r),r=[]),n.push(a)):r.push(a)}return r.length>0&&(r.sort(),n.push(...r)),n}},sN=e=>({cache:eN(e.cacheSize),parseClassName:aN(e),sortModifiers:oN(e),...HM(e)}),cN=/\s+/,lN=(e,t)=>{let{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i,sortModifiers:a}=t,o=[],s=e.trim().split(cN),c=``;for(let e=s.length-1;e>=0;--e){let t=s[e],{isExternal:l,modifiers:u,hasImportantModifier:d,baseClassName:f,maybePostfixModifierPosition:p}=n(t);if(l){c=t+(c.length>0?` `+c:c);continue}let m=!!p,h=r(m?f.substring(0,p):f);if(!h){if(!m){c=t+(c.length>0?` `+c:c);continue}if(h=r(f),!h){c=t+(c.length>0?` `+c:c);continue}m=!1}let g=u.length===0?``:u.length===1?u[0]:a(u).join(`:`),_=d?g+tN:g,v=_+h;if(o.indexOf(v)>-1)continue;o.push(v);let y=i(h,m);for(let e=0;e0?` `+c:c)}return c},uN=(...e)=>{let t=0,n,r,i=``;for(;t{if(typeof e==`string`)return e;let t,n=``;for(let r=0;r{let n,r,i,a,o=o=>(n=sN(t.reduce((e,t)=>t(e),e())),r=n.cache.get,i=n.cache.set,a=s,s(o)),s=e=>{let t=r(e);if(t)return t;let a=lN(e,n);return i(e,a),a};return a=o,(...e)=>a(uN(...e))},pN=[],mN=e=>{let t=t=>t[e]||pN;return t.isThemeGetter=!0,t},hN=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,gN=/^\((?:(\w[\w-]*):)?(.+)\)$/i,_N=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,vN=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,yN=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,bN=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,xN=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,SN=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,CN=e=>_N.test(e),Z=e=>!!e&&!Number.isNaN(Number(e)),wN=e=>!!e&&Number.isInteger(Number(e)),TN=e=>e.endsWith(`%`)&&Z(e.slice(0,-1)),EN=e=>vN.test(e),DN=()=>!0,ON=e=>yN.test(e)&&!bN.test(e),kN=()=>!1,AN=e=>xN.test(e),jN=e=>SN.test(e),MN=e=>!Q(e)&&!$(e),NN=e=>JN(e,QN,kN),Q=e=>hN.test(e),PN=e=>JN(e,$N,ON),FN=e=>JN(e,eP,Z),IN=e=>JN(e,nP,DN),LN=e=>JN(e,tP,kN),RN=e=>JN(e,XN,kN),zN=e=>JN(e,ZN,jN),BN=e=>JN(e,rP,AN),$=e=>gN.test(e),VN=e=>YN(e,$N),HN=e=>YN(e,tP),UN=e=>YN(e,XN),WN=e=>YN(e,QN),GN=e=>YN(e,ZN),KN=e=>YN(e,rP,!0),qN=e=>YN(e,nP,!0),JN=(e,t,n)=>{let r=hN.exec(e);return r?r[1]?t(r[1]):n(r[2]):!1},YN=(e,t,n=!1)=>{let r=gN.exec(e);return r?r[1]?t(r[1]):n:!1},XN=e=>e===`position`||e===`percentage`,ZN=e=>e===`image`||e===`url`,QN=e=>e===`length`||e===`size`||e===`bg-size`,$N=e=>e===`length`,eP=e=>e===`number`,tP=e=>e===`family-name`,nP=e=>e===`number`||e===`weight`,rP=e=>e===`shadow`,iP=fN(()=>{let e=mN(`color`),t=mN(`font`),n=mN(`text`),r=mN(`font-weight`),i=mN(`tracking`),a=mN(`leading`),o=mN(`breakpoint`),s=mN(`container`),c=mN(`spacing`),l=mN(`radius`),u=mN(`shadow`),d=mN(`inset-shadow`),f=mN(`text-shadow`),p=mN(`drop-shadow`),m=mN(`blur`),h=mN(`perspective`),g=mN(`aspect`),_=mN(`ease`),v=mN(`animate`),y=()=>[`auto`,`avoid`,`all`,`avoid-page`,`page`,`left`,`right`,`column`],b=()=>[`center`,`top`,`bottom`,`left`,`right`,`top-left`,`left-top`,`top-right`,`right-top`,`bottom-right`,`right-bottom`,`bottom-left`,`left-bottom`],x=()=>[...b(),$,Q],S=()=>[`auto`,`hidden`,`clip`,`visible`,`scroll`],C=()=>[`auto`,`contain`,`none`],w=()=>[$,Q,c],T=()=>[CN,`full`,`auto`,...w()],E=()=>[wN,`none`,`subgrid`,$,Q],D=()=>[`auto`,{span:[`full`,wN,$,Q]},wN,$,Q],ee=()=>[wN,`auto`,$,Q],te=()=>[`auto`,`min`,`max`,`fr`,$,Q],ne=()=>[`start`,`end`,`center`,`between`,`around`,`evenly`,`stretch`,`baseline`,`center-safe`,`end-safe`],O=()=>[`start`,`end`,`center`,`stretch`,`center-safe`,`end-safe`],k=()=>[`auto`,...w()],A=()=>[CN,`auto`,`full`,`dvw`,`dvh`,`lvw`,`lvh`,`svw`,`svh`,`min`,`max`,`fit`,...w()],j=()=>[CN,`screen`,`full`,`dvw`,`lvw`,`svw`,`min`,`max`,`fit`,...w()],re=()=>[CN,`screen`,`full`,`lh`,`dvh`,`lvh`,`svh`,`min`,`max`,`fit`,...w()],M=()=>[e,$,Q],ie=()=>[...b(),UN,RN,{position:[$,Q]}],ae=()=>[`no-repeat`,{repeat:[``,`x`,`y`,`space`,`round`]}],oe=()=>[`auto`,`cover`,`contain`,WN,NN,{size:[$,Q]}],se=()=>[TN,VN,PN],ce=()=>[``,`none`,`full`,l,$,Q],le=()=>[``,Z,VN,PN],ue=()=>[`solid`,`dashed`,`dotted`,`double`],de=()=>[`normal`,`multiply`,`screen`,`overlay`,`darken`,`lighten`,`color-dodge`,`color-burn`,`hard-light`,`soft-light`,`difference`,`exclusion`,`hue`,`saturation`,`color`,`luminosity`],fe=()=>[Z,TN,UN,RN],pe=()=>[``,`none`,m,$,Q],me=()=>[`none`,Z,$,Q],he=()=>[`none`,Z,$,Q],ge=()=>[Z,$,Q],_e=()=>[CN,`full`,...w()];return{cacheSize:500,theme:{animate:[`spin`,`ping`,`pulse`,`bounce`],aspect:[`video`],blur:[EN],breakpoint:[EN],color:[DN],container:[EN],"drop-shadow":[EN],ease:[`in`,`out`,`in-out`],font:[MN],"font-weight":[`thin`,`extralight`,`light`,`normal`,`medium`,`semibold`,`bold`,`extrabold`,`black`],"inset-shadow":[EN],leading:[`none`,`tight`,`snug`,`normal`,`relaxed`,`loose`],perspective:[`dramatic`,`near`,`normal`,`midrange`,`distant`,`none`],radius:[EN],shadow:[EN],spacing:[`px`,Z],text:[EN],"text-shadow":[EN],tracking:[`tighter`,`tight`,`normal`,`wide`,`wider`,`widest`]},classGroups:{aspect:[{aspect:[`auto`,`square`,CN,Q,$,g]}],container:[`container`],columns:[{columns:[Z,Q,$,s]}],"break-after":[{"break-after":y()}],"break-before":[{"break-before":y()}],"break-inside":[{"break-inside":[`auto`,`avoid`,`avoid-page`,`avoid-column`]}],"box-decoration":[{"box-decoration":[`slice`,`clone`]}],box:[{box:[`border`,`content`]}],display:[`block`,`inline-block`,`inline`,`flex`,`inline-flex`,`table`,`inline-table`,`table-caption`,`table-cell`,`table-column`,`table-column-group`,`table-footer-group`,`table-header-group`,`table-row-group`,`table-row`,`flow-root`,`grid`,`inline-grid`,`contents`,`list-item`,`hidden`],sr:[`sr-only`,`not-sr-only`],float:[{float:[`right`,`left`,`none`,`start`,`end`]}],clear:[{clear:[`left`,`right`,`both`,`none`,`start`,`end`]}],isolation:[`isolate`,`isolation-auto`],"object-fit":[{object:[`contain`,`cover`,`fill`,`none`,`scale-down`]}],"object-position":[{object:x()}],overflow:[{overflow:S()}],"overflow-x":[{"overflow-x":S()}],"overflow-y":[{"overflow-y":S()}],overscroll:[{overscroll:C()}],"overscroll-x":[{"overscroll-x":C()}],"overscroll-y":[{"overscroll-y":C()}],position:[`static`,`fixed`,`absolute`,`relative`,`sticky`],inset:[{inset:T()}],"inset-x":[{"inset-x":T()}],"inset-y":[{"inset-y":T()}],start:[{"inset-s":T(),start:T()}],end:[{"inset-e":T(),end:T()}],"inset-bs":[{"inset-bs":T()}],"inset-be":[{"inset-be":T()}],top:[{top:T()}],right:[{right:T()}],bottom:[{bottom:T()}],left:[{left:T()}],visibility:[`visible`,`invisible`,`collapse`],z:[{z:[wN,`auto`,$,Q]}],basis:[{basis:[CN,`full`,`auto`,s,...w()]}],"flex-direction":[{flex:[`row`,`row-reverse`,`col`,`col-reverse`]}],"flex-wrap":[{flex:[`nowrap`,`wrap`,`wrap-reverse`]}],flex:[{flex:[Z,CN,`auto`,`initial`,`none`,Q]}],grow:[{grow:[``,Z,$,Q]}],shrink:[{shrink:[``,Z,$,Q]}],order:[{order:[wN,`first`,`last`,`none`,$,Q]}],"grid-cols":[{"grid-cols":E()}],"col-start-end":[{col:D()}],"col-start":[{"col-start":ee()}],"col-end":[{"col-end":ee()}],"grid-rows":[{"grid-rows":E()}],"row-start-end":[{row:D()}],"row-start":[{"row-start":ee()}],"row-end":[{"row-end":ee()}],"grid-flow":[{"grid-flow":[`row`,`col`,`dense`,`row-dense`,`col-dense`]}],"auto-cols":[{"auto-cols":te()}],"auto-rows":[{"auto-rows":te()}],gap:[{gap:w()}],"gap-x":[{"gap-x":w()}],"gap-y":[{"gap-y":w()}],"justify-content":[{justify:[...ne(),`normal`]}],"justify-items":[{"justify-items":[...O(),`normal`]}],"justify-self":[{"justify-self":[`auto`,...O()]}],"align-content":[{content:[`normal`,...ne()]}],"align-items":[{items:[...O(),{baseline:[``,`last`]}]}],"align-self":[{self:[`auto`,...O(),{baseline:[``,`last`]}]}],"place-content":[{"place-content":ne()}],"place-items":[{"place-items":[...O(),`baseline`]}],"place-self":[{"place-self":[`auto`,...O()]}],p:[{p:w()}],px:[{px:w()}],py:[{py:w()}],ps:[{ps:w()}],pe:[{pe:w()}],pbs:[{pbs:w()}],pbe:[{pbe:w()}],pt:[{pt:w()}],pr:[{pr:w()}],pb:[{pb:w()}],pl:[{pl:w()}],m:[{m:k()}],mx:[{mx:k()}],my:[{my:k()}],ms:[{ms:k()}],me:[{me:k()}],mbs:[{mbs:k()}],mbe:[{mbe:k()}],mt:[{mt:k()}],mr:[{mr:k()}],mb:[{mb:k()}],ml:[{ml:k()}],"space-x":[{"space-x":w()}],"space-x-reverse":[`space-x-reverse`],"space-y":[{"space-y":w()}],"space-y-reverse":[`space-y-reverse`],size:[{size:A()}],"inline-size":[{inline:[`auto`,...j()]}],"min-inline-size":[{"min-inline":[`auto`,...j()]}],"max-inline-size":[{"max-inline":[`none`,...j()]}],"block-size":[{block:[`auto`,...re()]}],"min-block-size":[{"min-block":[`auto`,...re()]}],"max-block-size":[{"max-block":[`none`,...re()]}],w:[{w:[s,`screen`,...A()]}],"min-w":[{"min-w":[s,`screen`,`none`,...A()]}],"max-w":[{"max-w":[s,`screen`,`none`,`prose`,{screen:[o]},...A()]}],h:[{h:[`screen`,`lh`,...A()]}],"min-h":[{"min-h":[`screen`,`lh`,`none`,...A()]}],"max-h":[{"max-h":[`screen`,`lh`,...A()]}],"font-size":[{text:[`base`,n,VN,PN]}],"font-smoothing":[`antialiased`,`subpixel-antialiased`],"font-style":[`italic`,`not-italic`],"font-weight":[{font:[r,qN,IN]}],"font-stretch":[{"font-stretch":[`ultra-condensed`,`extra-condensed`,`condensed`,`semi-condensed`,`normal`,`semi-expanded`,`expanded`,`extra-expanded`,`ultra-expanded`,TN,Q]}],"font-family":[{font:[HN,LN,t]}],"font-features":[{"font-features":[Q]}],"fvn-normal":[`normal-nums`],"fvn-ordinal":[`ordinal`],"fvn-slashed-zero":[`slashed-zero`],"fvn-figure":[`lining-nums`,`oldstyle-nums`],"fvn-spacing":[`proportional-nums`,`tabular-nums`],"fvn-fraction":[`diagonal-fractions`,`stacked-fractions`],tracking:[{tracking:[i,$,Q]}],"line-clamp":[{"line-clamp":[Z,`none`,$,FN]}],leading:[{leading:[a,...w()]}],"list-image":[{"list-image":[`none`,$,Q]}],"list-style-position":[{list:[`inside`,`outside`]}],"list-style-type":[{list:[`disc`,`decimal`,`none`,$,Q]}],"text-alignment":[{text:[`left`,`center`,`right`,`justify`,`start`,`end`]}],"placeholder-color":[{placeholder:M()}],"text-color":[{text:M()}],"text-decoration":[`underline`,`overline`,`line-through`,`no-underline`],"text-decoration-style":[{decoration:[...ue(),`wavy`]}],"text-decoration-thickness":[{decoration:[Z,`from-font`,`auto`,$,PN]}],"text-decoration-color":[{decoration:M()}],"underline-offset":[{"underline-offset":[Z,`auto`,$,Q]}],"text-transform":[`uppercase`,`lowercase`,`capitalize`,`normal-case`],"text-overflow":[`truncate`,`text-ellipsis`,`text-clip`],"text-wrap":[{text:[`wrap`,`nowrap`,`balance`,`pretty`]}],indent:[{indent:w()}],"vertical-align":[{align:[`baseline`,`top`,`middle`,`bottom`,`text-top`,`text-bottom`,`sub`,`super`,$,Q]}],whitespace:[{whitespace:[`normal`,`nowrap`,`pre`,`pre-line`,`pre-wrap`,`break-spaces`]}],break:[{break:[`normal`,`words`,`all`,`keep`]}],wrap:[{wrap:[`break-word`,`anywhere`,`normal`]}],hyphens:[{hyphens:[`none`,`manual`,`auto`]}],content:[{content:[`none`,$,Q]}],"bg-attachment":[{bg:[`fixed`,`local`,`scroll`]}],"bg-clip":[{"bg-clip":[`border`,`padding`,`content`,`text`]}],"bg-origin":[{"bg-origin":[`border`,`padding`,`content`]}],"bg-position":[{bg:ie()}],"bg-repeat":[{bg:ae()}],"bg-size":[{bg:oe()}],"bg-image":[{bg:[`none`,{linear:[{to:[`t`,`tr`,`r`,`br`,`b`,`bl`,`l`,`tl`]},wN,$,Q],radial:[``,$,Q],conic:[wN,$,Q]},GN,zN]}],"bg-color":[{bg:M()}],"gradient-from-pos":[{from:se()}],"gradient-via-pos":[{via:se()}],"gradient-to-pos":[{to:se()}],"gradient-from":[{from:M()}],"gradient-via":[{via:M()}],"gradient-to":[{to:M()}],rounded:[{rounded:ce()}],"rounded-s":[{"rounded-s":ce()}],"rounded-e":[{"rounded-e":ce()}],"rounded-t":[{"rounded-t":ce()}],"rounded-r":[{"rounded-r":ce()}],"rounded-b":[{"rounded-b":ce()}],"rounded-l":[{"rounded-l":ce()}],"rounded-ss":[{"rounded-ss":ce()}],"rounded-se":[{"rounded-se":ce()}],"rounded-ee":[{"rounded-ee":ce()}],"rounded-es":[{"rounded-es":ce()}],"rounded-tl":[{"rounded-tl":ce()}],"rounded-tr":[{"rounded-tr":ce()}],"rounded-br":[{"rounded-br":ce()}],"rounded-bl":[{"rounded-bl":ce()}],"border-w":[{border:le()}],"border-w-x":[{"border-x":le()}],"border-w-y":[{"border-y":le()}],"border-w-s":[{"border-s":le()}],"border-w-e":[{"border-e":le()}],"border-w-bs":[{"border-bs":le()}],"border-w-be":[{"border-be":le()}],"border-w-t":[{"border-t":le()}],"border-w-r":[{"border-r":le()}],"border-w-b":[{"border-b":le()}],"border-w-l":[{"border-l":le()}],"divide-x":[{"divide-x":le()}],"divide-x-reverse":[`divide-x-reverse`],"divide-y":[{"divide-y":le()}],"divide-y-reverse":[`divide-y-reverse`],"border-style":[{border:[...ue(),`hidden`,`none`]}],"divide-style":[{divide:[...ue(),`hidden`,`none`]}],"border-color":[{border:M()}],"border-color-x":[{"border-x":M()}],"border-color-y":[{"border-y":M()}],"border-color-s":[{"border-s":M()}],"border-color-e":[{"border-e":M()}],"border-color-bs":[{"border-bs":M()}],"border-color-be":[{"border-be":M()}],"border-color-t":[{"border-t":M()}],"border-color-r":[{"border-r":M()}],"border-color-b":[{"border-b":M()}],"border-color-l":[{"border-l":M()}],"divide-color":[{divide:M()}],"outline-style":[{outline:[...ue(),`none`,`hidden`]}],"outline-offset":[{"outline-offset":[Z,$,Q]}],"outline-w":[{outline:[``,Z,VN,PN]}],"outline-color":[{outline:M()}],shadow:[{shadow:[``,`none`,u,KN,BN]}],"shadow-color":[{shadow:M()}],"inset-shadow":[{"inset-shadow":[`none`,d,KN,BN]}],"inset-shadow-color":[{"inset-shadow":M()}],"ring-w":[{ring:le()}],"ring-w-inset":[`ring-inset`],"ring-color":[{ring:M()}],"ring-offset-w":[{"ring-offset":[Z,PN]}],"ring-offset-color":[{"ring-offset":M()}],"inset-ring-w":[{"inset-ring":le()}],"inset-ring-color":[{"inset-ring":M()}],"text-shadow":[{"text-shadow":[`none`,f,KN,BN]}],"text-shadow-color":[{"text-shadow":M()}],opacity:[{opacity:[Z,$,Q]}],"mix-blend":[{"mix-blend":[...de(),`plus-darker`,`plus-lighter`]}],"bg-blend":[{"bg-blend":de()}],"mask-clip":[{"mask-clip":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]},`mask-no-clip`],"mask-composite":[{mask:[`add`,`subtract`,`intersect`,`exclude`]}],"mask-image-linear-pos":[{"mask-linear":[Z]}],"mask-image-linear-from-pos":[{"mask-linear-from":fe()}],"mask-image-linear-to-pos":[{"mask-linear-to":fe()}],"mask-image-linear-from-color":[{"mask-linear-from":M()}],"mask-image-linear-to-color":[{"mask-linear-to":M()}],"mask-image-t-from-pos":[{"mask-t-from":fe()}],"mask-image-t-to-pos":[{"mask-t-to":fe()}],"mask-image-t-from-color":[{"mask-t-from":M()}],"mask-image-t-to-color":[{"mask-t-to":M()}],"mask-image-r-from-pos":[{"mask-r-from":fe()}],"mask-image-r-to-pos":[{"mask-r-to":fe()}],"mask-image-r-from-color":[{"mask-r-from":M()}],"mask-image-r-to-color":[{"mask-r-to":M()}],"mask-image-b-from-pos":[{"mask-b-from":fe()}],"mask-image-b-to-pos":[{"mask-b-to":fe()}],"mask-image-b-from-color":[{"mask-b-from":M()}],"mask-image-b-to-color":[{"mask-b-to":M()}],"mask-image-l-from-pos":[{"mask-l-from":fe()}],"mask-image-l-to-pos":[{"mask-l-to":fe()}],"mask-image-l-from-color":[{"mask-l-from":M()}],"mask-image-l-to-color":[{"mask-l-to":M()}],"mask-image-x-from-pos":[{"mask-x-from":fe()}],"mask-image-x-to-pos":[{"mask-x-to":fe()}],"mask-image-x-from-color":[{"mask-x-from":M()}],"mask-image-x-to-color":[{"mask-x-to":M()}],"mask-image-y-from-pos":[{"mask-y-from":fe()}],"mask-image-y-to-pos":[{"mask-y-to":fe()}],"mask-image-y-from-color":[{"mask-y-from":M()}],"mask-image-y-to-color":[{"mask-y-to":M()}],"mask-image-radial":[{"mask-radial":[$,Q]}],"mask-image-radial-from-pos":[{"mask-radial-from":fe()}],"mask-image-radial-to-pos":[{"mask-radial-to":fe()}],"mask-image-radial-from-color":[{"mask-radial-from":M()}],"mask-image-radial-to-color":[{"mask-radial-to":M()}],"mask-image-radial-shape":[{"mask-radial":[`circle`,`ellipse`]}],"mask-image-radial-size":[{"mask-radial":[{closest:[`side`,`corner`],farthest:[`side`,`corner`]}]}],"mask-image-radial-pos":[{"mask-radial-at":b()}],"mask-image-conic-pos":[{"mask-conic":[Z]}],"mask-image-conic-from-pos":[{"mask-conic-from":fe()}],"mask-image-conic-to-pos":[{"mask-conic-to":fe()}],"mask-image-conic-from-color":[{"mask-conic-from":M()}],"mask-image-conic-to-color":[{"mask-conic-to":M()}],"mask-mode":[{mask:[`alpha`,`luminance`,`match`]}],"mask-origin":[{"mask-origin":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]}],"mask-position":[{mask:ie()}],"mask-repeat":[{mask:ae()}],"mask-size":[{mask:oe()}],"mask-type":[{"mask-type":[`alpha`,`luminance`]}],"mask-image":[{mask:[`none`,$,Q]}],filter:[{filter:[``,`none`,$,Q]}],blur:[{blur:pe()}],brightness:[{brightness:[Z,$,Q]}],contrast:[{contrast:[Z,$,Q]}],"drop-shadow":[{"drop-shadow":[``,`none`,p,KN,BN]}],"drop-shadow-color":[{"drop-shadow":M()}],grayscale:[{grayscale:[``,Z,$,Q]}],"hue-rotate":[{"hue-rotate":[Z,$,Q]}],invert:[{invert:[``,Z,$,Q]}],saturate:[{saturate:[Z,$,Q]}],sepia:[{sepia:[``,Z,$,Q]}],"backdrop-filter":[{"backdrop-filter":[``,`none`,$,Q]}],"backdrop-blur":[{"backdrop-blur":pe()}],"backdrop-brightness":[{"backdrop-brightness":[Z,$,Q]}],"backdrop-contrast":[{"backdrop-contrast":[Z,$,Q]}],"backdrop-grayscale":[{"backdrop-grayscale":[``,Z,$,Q]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[Z,$,Q]}],"backdrop-invert":[{"backdrop-invert":[``,Z,$,Q]}],"backdrop-opacity":[{"backdrop-opacity":[Z,$,Q]}],"backdrop-saturate":[{"backdrop-saturate":[Z,$,Q]}],"backdrop-sepia":[{"backdrop-sepia":[``,Z,$,Q]}],"border-collapse":[{border:[`collapse`,`separate`]}],"border-spacing":[{"border-spacing":w()}],"border-spacing-x":[{"border-spacing-x":w()}],"border-spacing-y":[{"border-spacing-y":w()}],"table-layout":[{table:[`auto`,`fixed`]}],caption:[{caption:[`top`,`bottom`]}],transition:[{transition:[``,`all`,`colors`,`opacity`,`shadow`,`transform`,`none`,$,Q]}],"transition-behavior":[{transition:[`normal`,`discrete`]}],duration:[{duration:[Z,`initial`,$,Q]}],ease:[{ease:[`linear`,`initial`,_,$,Q]}],delay:[{delay:[Z,$,Q]}],animate:[{animate:[`none`,v,$,Q]}],backface:[{backface:[`hidden`,`visible`]}],perspective:[{perspective:[h,$,Q]}],"perspective-origin":[{"perspective-origin":x()}],rotate:[{rotate:me()}],"rotate-x":[{"rotate-x":me()}],"rotate-y":[{"rotate-y":me()}],"rotate-z":[{"rotate-z":me()}],scale:[{scale:he()}],"scale-x":[{"scale-x":he()}],"scale-y":[{"scale-y":he()}],"scale-z":[{"scale-z":he()}],"scale-3d":[`scale-3d`],skew:[{skew:ge()}],"skew-x":[{"skew-x":ge()}],"skew-y":[{"skew-y":ge()}],transform:[{transform:[$,Q,``,`none`,`gpu`,`cpu`]}],"transform-origin":[{origin:x()}],"transform-style":[{transform:[`3d`,`flat`]}],translate:[{translate:_e()}],"translate-x":[{"translate-x":_e()}],"translate-y":[{"translate-y":_e()}],"translate-z":[{"translate-z":_e()}],"translate-none":[`translate-none`],accent:[{accent:M()}],appearance:[{appearance:[`none`,`auto`]}],"caret-color":[{caret:M()}],"color-scheme":[{scheme:[`normal`,`dark`,`light`,`light-dark`,`only-dark`,`only-light`]}],cursor:[{cursor:[`auto`,`default`,`pointer`,`wait`,`text`,`move`,`help`,`not-allowed`,`none`,`context-menu`,`progress`,`cell`,`crosshair`,`vertical-text`,`alias`,`copy`,`no-drop`,`grab`,`grabbing`,`all-scroll`,`col-resize`,`row-resize`,`n-resize`,`e-resize`,`s-resize`,`w-resize`,`ne-resize`,`nw-resize`,`se-resize`,`sw-resize`,`ew-resize`,`ns-resize`,`nesw-resize`,`nwse-resize`,`zoom-in`,`zoom-out`,$,Q]}],"field-sizing":[{"field-sizing":[`fixed`,`content`]}],"pointer-events":[{"pointer-events":[`auto`,`none`]}],resize:[{resize:[`none`,``,`y`,`x`]}],"scroll-behavior":[{scroll:[`auto`,`smooth`]}],"scroll-m":[{"scroll-m":w()}],"scroll-mx":[{"scroll-mx":w()}],"scroll-my":[{"scroll-my":w()}],"scroll-ms":[{"scroll-ms":w()}],"scroll-me":[{"scroll-me":w()}],"scroll-mbs":[{"scroll-mbs":w()}],"scroll-mbe":[{"scroll-mbe":w()}],"scroll-mt":[{"scroll-mt":w()}],"scroll-mr":[{"scroll-mr":w()}],"scroll-mb":[{"scroll-mb":w()}],"scroll-ml":[{"scroll-ml":w()}],"scroll-p":[{"scroll-p":w()}],"scroll-px":[{"scroll-px":w()}],"scroll-py":[{"scroll-py":w()}],"scroll-ps":[{"scroll-ps":w()}],"scroll-pe":[{"scroll-pe":w()}],"scroll-pbs":[{"scroll-pbs":w()}],"scroll-pbe":[{"scroll-pbe":w()}],"scroll-pt":[{"scroll-pt":w()}],"scroll-pr":[{"scroll-pr":w()}],"scroll-pb":[{"scroll-pb":w()}],"scroll-pl":[{"scroll-pl":w()}],"snap-align":[{snap:[`start`,`end`,`center`,`align-none`]}],"snap-stop":[{snap:[`normal`,`always`]}],"snap-type":[{snap:[`none`,`x`,`y`,`both`]}],"snap-strictness":[{snap:[`mandatory`,`proximity`]}],touch:[{touch:[`auto`,`none`,`manipulation`]}],"touch-x":[{"touch-pan":[`x`,`left`,`right`]}],"touch-y":[{"touch-pan":[`y`,`up`,`down`]}],"touch-pz":[`touch-pinch-zoom`],select:[{select:[`none`,`text`,`all`,`auto`]}],"will-change":[{"will-change":[`auto`,`scroll`,`contents`,`transform`,$,Q]}],fill:[{fill:[`none`,...M()]}],"stroke-w":[{stroke:[Z,VN,PN,FN]}],stroke:[{stroke:[`none`,...M()]}],"forced-color-adjust":[{"forced-color-adjust":[`auto`,`none`]}]},conflictingClassGroups:{overflow:[`overflow-x`,`overflow-y`],overscroll:[`overscroll-x`,`overscroll-y`],inset:[`inset-x`,`inset-y`,`inset-bs`,`inset-be`,`start`,`end`,`top`,`right`,`bottom`,`left`],"inset-x":[`right`,`left`],"inset-y":[`top`,`bottom`],flex:[`basis`,`grow`,`shrink`],gap:[`gap-x`,`gap-y`],p:[`px`,`py`,`ps`,`pe`,`pbs`,`pbe`,`pt`,`pr`,`pb`,`pl`],px:[`pr`,`pl`],py:[`pt`,`pb`],m:[`mx`,`my`,`ms`,`me`,`mbs`,`mbe`,`mt`,`mr`,`mb`,`ml`],mx:[`mr`,`ml`],my:[`mt`,`mb`],size:[`w`,`h`],"font-size":[`leading`],"fvn-normal":[`fvn-ordinal`,`fvn-slashed-zero`,`fvn-figure`,`fvn-spacing`,`fvn-fraction`],"fvn-ordinal":[`fvn-normal`],"fvn-slashed-zero":[`fvn-normal`],"fvn-figure":[`fvn-normal`],"fvn-spacing":[`fvn-normal`],"fvn-fraction":[`fvn-normal`],"line-clamp":[`display`,`overflow`],rounded:[`rounded-s`,`rounded-e`,`rounded-t`,`rounded-r`,`rounded-b`,`rounded-l`,`rounded-ss`,`rounded-se`,`rounded-ee`,`rounded-es`,`rounded-tl`,`rounded-tr`,`rounded-br`,`rounded-bl`],"rounded-s":[`rounded-ss`,`rounded-es`],"rounded-e":[`rounded-se`,`rounded-ee`],"rounded-t":[`rounded-tl`,`rounded-tr`],"rounded-r":[`rounded-tr`,`rounded-br`],"rounded-b":[`rounded-br`,`rounded-bl`],"rounded-l":[`rounded-tl`,`rounded-bl`],"border-spacing":[`border-spacing-x`,`border-spacing-y`],"border-w":[`border-w-x`,`border-w-y`,`border-w-s`,`border-w-e`,`border-w-bs`,`border-w-be`,`border-w-t`,`border-w-r`,`border-w-b`,`border-w-l`],"border-w-x":[`border-w-r`,`border-w-l`],"border-w-y":[`border-w-t`,`border-w-b`],"border-color":[`border-color-x`,`border-color-y`,`border-color-s`,`border-color-e`,`border-color-bs`,`border-color-be`,`border-color-t`,`border-color-r`,`border-color-b`,`border-color-l`],"border-color-x":[`border-color-r`,`border-color-l`],"border-color-y":[`border-color-t`,`border-color-b`],translate:[`translate-x`,`translate-y`,`translate-none`],"translate-none":[`translate`,`translate-x`,`translate-y`,`translate-z`],"scroll-m":[`scroll-mx`,`scroll-my`,`scroll-ms`,`scroll-me`,`scroll-mbs`,`scroll-mbe`,`scroll-mt`,`scroll-mr`,`scroll-mb`,`scroll-ml`],"scroll-mx":[`scroll-mr`,`scroll-ml`],"scroll-my":[`scroll-mt`,`scroll-mb`],"scroll-p":[`scroll-px`,`scroll-py`,`scroll-ps`,`scroll-pe`,`scroll-pbs`,`scroll-pbe`,`scroll-pt`,`scroll-pr`,`scroll-pb`,`scroll-pl`],"scroll-px":[`scroll-pr`,`scroll-pl`],"scroll-py":[`scroll-pt`,`scroll-pb`],touch:[`touch-x`,`touch-y`,`touch-pz`],"touch-x":[`touch`],"touch-y":[`touch`],"touch-pz":[`touch`]},conflictingClassGroupModifiers:{"font-size":[`leading`]},orderSensitiveModifiers:[`*`,`**`,`after`,`backdrop`,`before`,`details-content`,`file`,`first-letter`,`first-line`,`marker`,`placeholder`,`selection`]}}),aP=`yusd`,oP=[`yusd`,`yellow`],sP=`nitrolite-store:selected-asset`,cP=45e3,lP=new R(`1e18`),uP=`wss://nitronode-stress.yellow.org/v1/ws`,dP={11155111:`https://ethereum-sepolia-rpc.publicnode.com`},fP=class{client;account;constructor(e,t){this.client=e,this.account=t}getAddress(){return this.account}async signMessage(e){let t=typeof e==`string`?e:e.raw;return this.client.signMessage({account:this.account,message:{raw:t}})}async signPersonalMessage(e){return this.signMessage(e)}async sendTransaction(e){let t={...e};return delete t.account,delete t.chain,this.client.sendTransaction({...t,account:this.account,chain:FM})}};function pP(...e){return iP(Ep(e))}function mP(){let e=window.ethereum;return e?Array.isArray(e.providers)?e.providers?.find(e=>e.isMetaMask)??null:e.isMetaMask?e:null:null}function hP(){try{let e=window.localStorage.getItem(sP);return e&&oP.includes(e)?e:aP}catch{return aP}}function gP(e){try{window.localStorage.setItem(sP,e)}catch{}}async function _P(e,t){let n=Zk({account:t,chain:FM,transport:$k(e)}),r=new fP(n,t);return{client:n,nitrolite:await MM.create(uP,new NM(r),r,Wj(11155111n,dP[11155111]))}}async function vP(e,t){let n=await fetch(e,{headers:{"Content-Type":`application/json`,...t?.headers||{}},...t});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error?.message||`Request failed with status ${n.status}`)}return n.json()}function yP(e){return e?e.length<=12?e:`${e.slice(0,6)}...${e.slice(-4)}`:`Not connected`}function bP(e){return new R(e||`0`).toFixed()}function xP(e){try{let t=new R(e);return t.isFinite()?t:null}catch{return null}}function SP(e){return xP(e)?.greaterThan(0)??!1}function CP(e,t){return e.lessThan(t)?e:t}function wP(e){let t=(e instanceof Error?e.message:String(e)).toLowerCase();return t.includes(`allowance`)&&t.includes(`sufficient`)}function TP(e){if(!e)return`No store activity yet.`;try{let t=JSON.parse(e);switch(t.intent){case`init`:return`Store session ready.`;case`user_deposit`:return`Last action: deposit signed.`;case`purchase`:return`Last action: purchased ${t.item_id} for ${t.item_price}`;case`user_withdraw`:return`Last action: withdrew from store.`;default:return`Store session active.`}}catch{return`Store session active.`}}function EP(e){switch(e){case`ready`:return`ready`;case`ack_required`:return`ack required`;case`deposit_required`:return`deposit required`;case`funds_required`:return`funds needed`;case`unavailable`:return`sync unavailable`;default:return`offline`}}function DP(e,t){switch(e?.status){case`ready`:return`Home channel is ready with ${bP(e.available_balance)} ${t.toUpperCase()}.`;case`ack_required`:return e.requires_channel_creation?`${bP(e.pending_balance)} ${t.toUpperCase()} was received off-chain. Sign once to open a home channel and make it available.`:`Acknowledge ${bP(e.pending_balance)} ${t.toUpperCase()} in your pending channel state.`;case`deposit_required`:return`Prepare a home channel with up to ${bP(e.bootstrap_amount)} ${t.toUpperCase()} from your wallet.`;case`funds_required`:return`Add ${t.toUpperCase()} test funds to this wallet before preparing a home channel.`;case`unavailable`:return e.message||`Channel readiness could not be checked.`;default:return`Connect wallet to check channel readiness.`}}function OP(e){switch(e){case`open`:return`ready`;case`missing`:return`setup required`;case`sync_failed`:return`sync pending`;case`closed`:return`closed`;default:return e??`offline`}}function kP(e){return{application_id:e.applicationId,participants:e.participants.map(e=>({wallet_address:e.walletAddress,signature_weight:e.signatureWeight})),quorum:e.quorum,nonce:e.nonce.toString()}}function AP(e){return{app_session_id:e.appSessionId,intent:e.intent,version:e.version.toString(),allocations:e.allocations.map(e=>({participant:e.participant,asset:e.asset,amount:e.amount.toString()})),session_data:e.sessionData}}function jP(e){return{appSessionId:e.app_session_id,intent:Number(e.intent),version:BigInt(e.version),allocations:e.allocations.map(e=>({participant:e.participant,asset:e.asset,amount:new R(e.amount)})),sessionData:e.session_data}}async function MP(e,t,n){let r,i=new Promise((e,i)=>{r=window.setTimeout(()=>i(Error(n)),t)});try{return await Promise.race([e,i])}finally{r!==void 0&&window.clearTimeout(r)}}function NP({children:e,className:t}){return(0,W.jsx)(np.section,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{duration:.26,ease:`easeOut`},className:pP(`glass-panel shine-border min-w-0 rounded-lg p-5 sm:p-6`,t),children:e})}function PP({children:e,className:t,variant:n=`primary`,icon:r,...i}){return(0,W.jsxs)(np.button,{whileHover:i.disabled?void 0:{scale:1.02},whileTap:i.disabled?void 0:{scale:.97},transition:{type:`spring`,stiffness:420,damping:20},className:pP(`inline-flex min-h-11 items-center justify-center gap-2 rounded-md px-4 text-sm font-black transition disabled:cursor-not-allowed disabled:opacity-50`,n===`primary`&&`shimmer-button bg-ink text-yellow-brand shadow-glow`,n===`secondary`&&`border border-black/10 bg-white text-ink shadow-sm hover:border-black/30`,n===`ghost`&&`bg-transparent text-ink hover:bg-black/5`,t),...i,children:[r,(0,W.jsx)(`span`,{children:e})]})}function FP({value:e}){return(0,W.jsx)(od,{mode:`wait`,children:(0,W.jsx)(np.strong,{initial:{opacity:0,y:5},animate:{opacity:1,y:0},exit:{opacity:0,y:-5},transition:{duration:.18},className:`block max-w-full truncate text-xl font-black tabular-nums text-ink`,children:bP(e)},e)})}function IP({label:e,title:t,icon:n}){return(0,W.jsxs)(`div`,{className:`mb-5 flex min-w-0 items-start justify-between gap-4`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsx)(`p`,{className:`label-text`,children:e}),(0,W.jsx)(`h2`,{className:`mt-1 break-words text-xl font-black tracking-normal text-ink sm:text-2xl`,children:t})]}),(0,W.jsx)(`div`,{className:`grid size-10 shrink-0 place-items-center rounded-lg border border-black/10 bg-yellow-brand text-ink shadow-sm`,children:n})]})}function LP(){let[e,t]=(0,N.useState)(null),[n,r]=(0,N.useState)(null),[i,a]=(0,N.useState)(null),[o,s]=(0,N.useState)(hP),[c,l]=(0,N.useState)(null),[u,d]=(0,N.useState)(`1.00`),[f,p]=(0,N.useState)(`0.50`),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(null),[v,y]=(0,N.useState)(null),[b,x]=(0,N.useState)([]),S=(0,N.useMemo)(()=>new Set((c?.library??[]).map(e=>e.id)),[c]),C=(0,N.useMemo)(()=>{let e=new Set(c?.supported_assets??oP);return oP.filter(t=>e.has(t))},[c]),w=!!(c?.session.app_session_id&&c.session.status===`open`),T=c?.session.status===`missing`||c?.session.status===`sync_failed`,E=c?.pending_action?.type===`user_deposit`?c.pending_action:null,D=c?.channel_readiness,ee=D?.status===`ready`,te=D?.status===`ack_required`||D?.status===`deposit_required`,ne=(0,N.useMemo)(()=>xP(c?.available_balance??`0`)??new R(0),[c?.available_balance]),O=(0,N.useMemo)(()=>xP(D?.pending_balance??c?.available_balance??`0`)??new R(0),[c?.available_balance,D?.pending_balance]),k=(0,N.useMemo)(()=>{let e=O.minus(ne);return e.greaterThan(0)?e:new R(0)},[ne,O]),A=(0,N.useMemo)(()=>xP(D?.pending_amount??k.toFixed())??k,[D?.pending_amount,k]),j=!!(D?.status===`ack_required`&&O.greaterThan(ne)),re=!!D?.requires_channel_creation,M=!!(D?.status===`ack_required`&&D.pending_transition===`release`&&A.greaterThan(0)),ie=(0,N.useMemo)(()=>xP(u),[u]),ae=(0,N.useMemo)(()=>E?xP(E.amount):null,[E]),oe=!!(c&&ie?.greaterThan(0)&&ie.greaterThan(ne)),se=!!(c&&ae?.greaterThan(0)&&ae.greaterThan(ne)),ce=!!(e&&i&&c&&g===null&&te),le=!!(e&&w&&ee&&g===null&&SP(u)&&!oe),ue=!!(e&&w&&ee&&g===null&&SP(f)),de=!!(e&&i&&E&&g===null&&!se),fe=!!(T&&e&&n&&g===null&&ee);function pe(e){let t=`${new Date().toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})} ${e}`;x(e=>[t,...e].slice(0,40))}async function me(e){if(await e.request({method:`eth_chainId`})!==`0xaa36a7`)try{await e.request({method:`wallet_switchEthereumChain`,params:[{chainId:`0xaa36a7`}]})}catch(e){throw Error(`Switch MetaMask to Sepolia and try again. ${String(e)}`)}}async function he(e,n,i,o){await me(e);let{client:s,nitrolite:c}=await _P(e,n);t(n),r(s),a(c),pe(`${o} ${yP(n)}`),await ge(i,n)}(0,N.useEffect)(()=>{let e=mP();if(!e)return;let n=!1,i=async t=>{_(`restore`),y(null);try{await he(e,t,hP(),`wallet restored`)}catch(e){n||y(e instanceof Error?e.message:`Failed to restore wallet`)}finally{n||_(null)}};e.request({method:`eth_accounts`}).then(e=>{if(!(n||!Array.isArray(e)||typeof e[0]!=`string`))return i(e[0])}).catch(()=>void 0);let o=e=>{let n=Array.isArray(e)&&typeof e[0]==`string`?e[0]:null;if(!n){t(null),r(null),a(null),l(null),h(null),pe(`wallet disconnected`);return}i(n)},s=()=>{e.request({method:`eth_accounts`}).then(e=>{if(!(!Array.isArray(e)||typeof e[0]!=`string`))return i(e[0])}).catch(()=>void 0)};return e.on?.(`accountsChanged`,o),e.on?.(`chainChanged`,s),()=>{n=!0,e.removeListener?.(`accountsChanged`,o),e.removeListener?.(`chainChanged`,s)}},[]);async function ge(t,n){let r=n??e;if(!r)throw Error(`Connect a wallet before bootstrapping the store.`);let i=await vP(`/api/store/bootstrap?asset=${encodeURIComponent(t)}&wallet_address=${encodeURIComponent(r)}`);l(i),s(i.selected_asset),gP(i.selected_asset),pe(`bootstrap ${t.toUpperCase()} -> ${OP(i.session.status)}`)}async function _e(){_(`connect`),y(null);try{let e=mP();if(!e)throw Error(`MetaMask extension was not found in this browser.`);await me(e);let t=(await e.request({method:`eth_requestAccounts`}))[0];if(!t)throw Error(`MetaMask did not return an account.`);await he(e,t,o,`wallet connected`)}catch(e){y(e instanceof Error?e.message:`Failed to connect wallet`)}finally{_(null)}}async function ve(e,t,n){let r=new PM(new fP(t,n)),i=JSON.stringify({intent:`init`}),a={applicationId:e.app_id,participants:[{walletAddress:n,signatureWeight:1},{walletAddress:e.app_signer,signatureWeight:1}],quorum:2,nonce:BigInt(Date.now()*1e6)},o=qA(a,i),s=await r.signMessage(o);return vP(`/api/store/init`,{method:`POST`,body:JSON.stringify({wallet_address:n,asset:e.selected_asset,definition:kP(a),session_data:i,user_signature:s})})}async function ye(){if(!(!c||!n||!e)&&T){_(`create-session`),y(null);try{let t=await ve(c,n,e);l(t),pe(`session created ${yP(t.session.app_session_id??``)}`)}catch(e){y(e instanceof Error?e.message:`Failed to create store session`)}finally{_(null)}}}async function be(t){if(!i||!e||!c)throw Error(`Connect a wallet before preparing a channel.`);try{return await i.checkpoint(t)}catch(n){if(!wP(n)){if((n instanceof Error?n.message:String(n)).toLowerCase().includes(`does not require a blockchain operation`))return null;throw n}let r=(await i.getLatestState(e,t,!0)).homeLedger.blockchainId||BigInt(c.channel_readiness.home_blockchain_id);return pe(`approve ${t.toUpperCase()} channel spend`),await i.approveToken(r,t,lP),await i.checkpoint(t)}}async function xe(){if(!c||!e||!i)return;let t=c.channel_readiness,n=c.selected_asset;if(!(t.status!==`ack_required`&&t.status!==`deposit_required`)){_(`prepare-channel`),y(null);try{if(t.status===`ack_required`){pe(`acknowledge ${n.toUpperCase()} channel state`);try{await i.acknowledge(n)}catch(e){if(!(e instanceof Error?e.message:String(e)).toLowerCase().includes(`already acknowledged`))throw e}}else{let r=BigInt(t.home_blockchain_id),a=CP(xP(t.bootstrap_amount)??new R(10),await i.getOnChainBalance(r,n,e));if(!a.greaterThan(0))throw Error(`Add ${n.toUpperCase()} test funds to this wallet before preparing a home channel.`);pe(`prepare ${n.toUpperCase()} channel ${a.toFixed()}`);try{await i.deposit(r,n,a)}catch(e){if(!wP(e))throw e;pe(`approve ${n.toUpperCase()} channel spend`),await i.approveToken(r,n,lP),await i.deposit(r,n,a)}}let r=await be(n);pe(r?`channel checkpoint ${yP(r)}`:`channel state synced`),await ge(n)}catch(e){y(e instanceof Error?e.message:`Failed to prepare channel`);try{await ge(n)}catch{}}finally{_(null)}}}async function Se(t){if(!(!c||!e||!n)){if(!w){y(`Store session is not ready yet.`);return}_(`purchase:${t.id}`),y(null);try{let r=c.session.version+1,i=new R(c.session.user_allocation),a=new R(c.session.app_allocation),o=new R(t.prices[c.selected_asset]),s=i.minus(o),u=a.plus(o);if(s.isNegative())throw Error(`Add funds before purchasing this item.`);let d=JSON.stringify({intent:`purchase`,item_id:Number.isFinite(Number(t.id))?Number(t.id):t.id,item_price:o.toFixed()}),f={appSessionId:c.session.app_session_id,intent:GA.Operate,version:BigInt(r),allocations:[{participant:e,asset:c.selected_asset,amount:s},{participant:c.app_signer,asset:c.selected_asset,amount:u}],sessionData:d},p=JA(f),m=await new PM(new fP(n,e)).signMessage(p),h=await vP(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:c.selected_asset,app_state_update:AP(f),user_signature:m})});if(!h.bootstrap)throw Error(`Purchase succeeded but bootstrap was not returned.`);l(h.bootstrap),pe(`purchase ${t.id}`)}catch(e){y(e instanceof Error?e.message:`Failed to buy item`)}finally{_(null)}}}async function Ce(){if(!(!c||!e||!n)){if(!w){y(`Store session is not ready yet.`);return}_(`withdraw`),y(null);try{let t=new R(f);if(!t.greaterThan(0))throw Error(`Withdraw amount must be greater than zero.`);let r=c.session.version+1,i=new R(c.session.user_allocation),a=new R(c.session.app_allocation),o=i.minus(t);if(o.isNegative())throw Error(`Withdraw amount exceeds your store balance.`);let s=JSON.stringify({intent:`user_withdraw`}),u={appSessionId:c.session.app_session_id,intent:GA.Withdraw,version:BigInt(r),allocations:[{participant:e,asset:c.selected_asset,amount:o},{participant:c.app_signer,asset:c.selected_asset,amount:a}],sessionData:s},d=JA(u),p=await new PM(new fP(n,e)).signMessage(d),m=await vP(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:c.selected_asset,app_state_update:AP(u),user_signature:p})});if(!m.bootstrap)throw Error(`Withdraw succeeded but bootstrap was not returned.`);l(m.bootstrap),pe(`withdraw ${t.toFixed()}`)}catch(e){let t=e instanceof Error?e.message:`Failed to withdraw`;y(t.startsWith(`failed to submit app state: `)?`Nitronode rejected the withdraw state: ${t.slice(28)}`:t);try{await ge(c.selected_asset)}catch{}}finally{_(null)}}}async function we(e,t,n,r,a){if(!i)throw Error(`Connect a wallet before submitting the deposit.`);pe(`deposit signed ${a.toFixed()} ${r.toUpperCase()}; submitting`),await Te(r,a),await MP(i.submitAppSessionDeposit(e,[t,n],r,a),cP,`Deposit is signed, but the Nitronode submit did not finish yet. Use Resume deposit after refresh.`),await ge(r),pe(`deposit ${a.toFixed()} ${r.toUpperCase()} submitted`)}async function Te(t,n){if(!i||!e)throw Error(`Connect a wallet before submitting the deposit.`);let r;try{r=await i.getLatestState(e,t,!0)}catch{throw Error(`Open and fund a ${t.toUpperCase()} home channel before using this store.`)}if(new R(r.homeLedger.userBalance).lessThan(n))throw Error(`Deposit amount exceeds your available ${t.toUpperCase()} channel funds.`)}async function Ee(){if(E){_(`resume-deposit`),y(null);try{let e=new R(E.amount);await we(jP(E.app_state_update),E.user_signature,E.app_signature,E.asset,e)}catch(e){y(e instanceof Error?e.message:`Failed to resume deposit`);try{await ge(E.asset)}catch{}}finally{_(null)}}}async function De(){if(!(!c||!e||!n||!i)){if(!w){y(`Store session is not ready yet.`);return}_(`deposit`),y(null);try{let t=new R(u);if(!t.greaterThan(0))throw Error(`Deposit amount must be greater than zero.`);let r=new R(c.available_balance||`0`);if(t.greaterThan(r))throw r.greaterThan(0)?Error(`Deposit amount exceeds your available ${c.selected_asset.toUpperCase()} channel funds.`):Error(`Open and fund a ${c.selected_asset.toUpperCase()} home channel before depositing.`);let i=c.session.version+1,a=new R(c.session.user_allocation),o=new R(c.session.app_allocation),s=a.plus(t),l=JSON.stringify({intent:`user_deposit`,amount:t.toFixed()}),d={appSessionId:c.session.app_session_id,intent:GA.Deposit,version:BigInt(i),allocations:[{participant:e,asset:c.selected_asset,amount:s},{participant:c.app_signer,asset:c.selected_asset,amount:o}],sessionData:l},f=JA(d),p=await new PM(new fP(n,e)).signMessage(f),m=await vP(`/api/store/update`,{method:`POST`,body:JSON.stringify({asset:c.selected_asset,app_state_update:AP(d),user_signature:p})});if(!m.app_signature)throw Error(`Backend did not return an app signature for deposit.`);await we(d,p,m.app_signature,c.selected_asset,t)}catch(e){y(e instanceof Error?e.message:`Failed to add funds`);try{await ge(c.selected_asset)}catch{}}finally{_(null)}}}async function Oe(t){if(!(!c||!e)){if(!c.session.app_session_id){y(`Store session is not ready yet.`);return}_(`content:${t}`),y(null);try{let n=new URLSearchParams({wallet_address:e,asset:c.selected_asset});h(await vP(`/api/store/content/${encodeURIComponent(t)}?${n.toString()}`)),pe(`open content ${t}`)}catch(e){y(e instanceof Error?e.message:`Failed to open content`)}finally{_(null)}}}async function ke(){try{await navigator.clipboard.writeText(b.join(` +`)),pe(`copied activity log`)}catch(e){y(e instanceof Error?e.message:`Failed to copy activity log`)}}function Ae(t){h(null),gP(t),e?(_(`asset:${t}`),y(null),ge(t).catch(e=>{y(e instanceof Error?e.message:`Failed to refresh store`)}).finally(()=>{_(null)})):s(t)}function je(){if(g===`prepare-channel`)return`Preparing`;switch(D?.status){case`ack_required`:return`Make available`;case`deposit_required`:return`Prepare channel`;case`funds_required`:return`Funds needed`;case`unavailable`:return`Reconnect`;default:return`Prepare channel`}}function Me(){if(!c||ee)return null;let e=M?`Make withdrawn balance available`:re?`Make received funds available`:D?.status===`ack_required`?`Make pending balance available`:EP(D?.status),t=M?`${bP(A.toFixed())} ${o.toUpperCase()} from your store withdrawal is pending. Sign once to add it back to your available channel balance.`:re?`${bP(O.toFixed())} ${o.toUpperCase()} was received off-chain. Sign once, then checkpoint to open your home channel and make it available.`:D?.status===`ack_required`?`${bP(O.toFixed())} ${o.toUpperCase()} is pending in your channel. Sign once to make it available.`:DP(D,o);return(0,W.jsxs)(`div`,{className:`mt-4 flex flex-col gap-3 rounded-lg border border-black/10 bg-white/90 p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsxs)(`p`,{className:`flex items-center gap-2 text-sm font-black uppercase tracking-normal text-ink`,children:[(0,W.jsx)(xp,{className:`size-4 shrink-0`}),e]}),(0,W.jsx)(`p`,{className:`mt-1 text-sm font-semibold leading-5 text-black/60`,children:t}),j?(0,W.jsxs)(`div`,{className:`mt-3 grid gap-2 text-xs font-black text-black/60 sm:grid-cols-2`,children:[(0,W.jsxs)(`span`,{className:`rounded-md border border-black/10 bg-white px-3 py-2`,children:[`Available now: `,bP(ne.toFixed()),` `,o.toUpperCase()]}),(0,W.jsxs)(`span`,{className:`rounded-md border border-yellow-line bg-yellow-brand/20 px-3 py-2 text-ink`,children:[`After signing: `,bP(O.toFixed()),` `,o.toUpperCase()]})]}):null]}),(0,W.jsx)(PP,{className:`shrink-0`,disabled:!ce,onClick:xe,icon:g===`prepare-channel`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(bp,{className:`size-4`}),children:je()})]})}return(0,W.jsxs)(`main`,{className:`mx-auto flex w-full min-w-0 max-w-[1180px] flex-col gap-5 overflow-x-hidden px-4 py-5 sm:px-6 lg:px-8`,children:[(0,W.jsxs)(np.header,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{duration:.26,ease:`easeOut`},className:`glass-panel grid gap-5 rounded-lg p-5 sm:grid-cols-[1fr_auto] sm:p-6`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsx)(`p`,{className:`label-text`,children:`Content store`}),(0,W.jsx)(`h1`,{className:`mt-2 break-words text-2xl font-black leading-tight tracking-normal text-ink sm:text-4xl`,children:`Nitrolite App Session Store`}),(0,W.jsx)(`p`,{className:`mt-3 max-w-2xl text-sm leading-6 text-black/70 sm:text-base`,children:`YUSD-first content purchases with Yellow as a second testnet asset lane.`}),(0,W.jsxs)(`div`,{className:`mt-4 flex flex-wrap items-center gap-2`,children:[(0,W.jsxs)(`span`,{className:`status-pill`,children:[(0,W.jsx)(xp,{className:`size-3.5`}),`Sepolia`]}),(0,W.jsxs)(`span`,{className:`status-pill`,children:[(0,W.jsx)(hp,{className:`size-3.5 text-emerald-700`}),OP(c?.session.status)]})]})]}),(0,W.jsxs)(`div`,{className:`flex min-w-[260px] flex-col gap-3`,children:[(0,W.jsx)(PP,{className:`w-full`,onClick:_e,disabled:g!==null,icon:g===`connect`||g===`restore`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(wp,{className:`size-4`}),children:g===`restore`?`Restoring`:g===`connect`?`Connecting`:e?`Reconnect`:`Connect`}),(0,W.jsxs)(`div`,{className:`rounded-lg border border-black/10 bg-white/90 p-4 shadow-sm`,children:[(0,W.jsx)(`p`,{className:`label-text`,children:`Wallet`}),(0,W.jsx)(`p`,{className:`mt-1 truncate text-lg font-black text-ink`,children:yP(e)})]})]})]}),(0,W.jsx)(od,{children:v?(0,W.jsx)(np.div,{initial:{opacity:0,y:-8},animate:{opacity:1,y:0},exit:{opacity:0,y:-8},className:`rounded-lg border border-black bg-ink px-4 py-3 text-sm font-semibold text-yellow-surface shadow-card`,role:`alert`,"aria-live":`assertive`,children:v}):null}),(0,W.jsxs)(`div`,{className:`grid gap-5 lg:grid-cols-[1.05fr_0.95fr]`,children:[(0,W.jsxs)(NP,{children:[(0,W.jsx)(IP,{label:`Session`,title:c?.store_name??`Store`,icon:(0,W.jsx)(_p,{className:`size-5`})}),(0,W.jsx)(`div`,{className:`mb-5 grid grid-cols-1 gap-2 rounded-lg border border-black/10 bg-black/[0.03] p-1 sm:grid-cols-2`,children:C.map(t=>(0,W.jsx)(`button`,{className:pP(`min-h-10 rounded-md px-3 text-sm font-black uppercase transition`,o===t?`bg-ink text-yellow-brand shadow-sm`:`text-black/60 hover:bg-white/80 hover:text-ink`),onClick:()=>Ae(t),disabled:!e||g!==null,children:t},t))}),(0,W.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-3`,children:[(0,W.jsxs)(`div`,{className:`metric-card`,children:[(0,W.jsx)(`p`,{className:`label-text`,children:`Available`}),(0,W.jsx)(FP,{value:c?.available_balance??`0`}),(0,W.jsx)(`p`,{className:`mt-1 text-xs font-bold uppercase text-black/50`,children:o}),j?(0,W.jsxs)(`p`,{className:`mt-1 text-xs font-bold text-amber-700`,children:[`Pending: `,bP(O.toFixed()),` `,o.toUpperCase()]}):null]}),(0,W.jsxs)(`div`,{className:`metric-card`,children:[(0,W.jsx)(`p`,{className:`label-text`,children:`Store balance`}),(0,W.jsx)(FP,{value:c?.session.user_allocation??`0`}),(0,W.jsx)(`p`,{className:`mt-1 text-xs font-bold uppercase text-black/50`,children:o})]}),(0,W.jsxs)(`div`,{className:`metric-card`,children:[(0,W.jsx)(`p`,{className:`label-text`,children:`App signer`}),(0,W.jsx)(`strong`,{className:`mt-1 block truncate text-lg font-black text-ink`,children:yP(c?.app_signer??null)}),(0,W.jsx)(`p`,{className:`mt-1 text-xs font-bold uppercase text-black/50`,children:`Quorum 2`})]})]}),(0,W.jsx)(`p`,{className:`mt-4 rounded-lg border border-black/10 bg-yellow-surface/70 px-3 py-2 text-sm font-semibold text-black/70`,"aria-live":`polite`,children:c?TP(c.session.session_data):`Connect wallet to load the store.`}),T&&ee?(0,W.jsxs)(`div`,{className:`mt-4 flex flex-col gap-3 rounded-lg border border-black/10 bg-white/90 p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between`,children:[(0,W.jsx)(`p`,{className:`text-sm font-semibold leading-5 text-black/60`,children:c?.session.status===`sync_failed`?`The previous store session is not synced. Sign once to start a fresh store session.`:`Sign once to start a store session and unlock deposits.`}),(0,W.jsx)(PP,{className:`shrink-0`,disabled:!fe,onClick:ye,icon:g===`create-session`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(_p,{className:`size-4`}),children:g===`create-session`?`Starting`:`Sign to start`})]}):null,T?Me():null,E?(0,W.jsxs)(`div`,{className:`mt-4 flex flex-col gap-3 rounded-lg border border-yellow-line bg-yellow-brand/25 p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsxs)(`p`,{className:`flex items-center gap-2 text-sm font-black text-ink`,children:[(0,W.jsx)(Cp,{className:`size-4 shrink-0`}),`Deposit checkpoint ready`]}),(0,W.jsx)(`p`,{className:`mt-1 text-sm font-semibold leading-5 text-black/60`,children:se?`${bP(E.amount)} ${E.asset.toUpperCase()} exceeds the current available balance. Enter a smaller deposit to replace it, or top up before resuming.`:`${bP(E.amount)} ${E.asset.toUpperCase()} is signed at version ${E.version}. Resume submits it to Nitronode without another MetaMask prompt.`})]}),(0,W.jsx)(PP,{className:`shrink-0`,variant:`secondary`,disabled:!de,onClick:Ee,icon:g===`resume-deposit`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(bp,{className:`size-4`}),children:g===`resume-deposit`?`Resuming`:`Resume`})]}):null,w&&!ee?Me():null,w&&ee?(0,W.jsxs)(`div`,{className:`mt-5 grid gap-3 sm:grid-cols-[minmax(0,1fr)_auto]`,children:[(0,W.jsxs)(`label`,{className:`grid gap-2 text-sm font-black text-ink`,children:[`Deposit`,(0,W.jsx)(`input`,{id:`deposit-amount`,name:`deposit_amount`,className:`min-h-11 rounded-md border border-black/10 bg-white px-3 text-base font-bold text-ink shadow-sm`,value:u,onChange:e=>d(e.target.value),type:`number`,inputMode:`decimal`,min:`0.000001`,step:`0.01`,required:!0,"aria-label":`Deposit amount in ${o.toUpperCase()}`}),oe?(0,W.jsx)(`span`,{className:`text-xs font-bold leading-5 text-red-700`,children:`Deposit amount exceeds your available ${o.toUpperCase()} channel funds.`}):E?(0,W.jsx)(`span`,{className:`text-xs font-bold leading-5 text-black/50`,children:`A new deposit replaces the pending checkpoint.`}):null]}),(0,W.jsx)(PP,{className:`self-end`,disabled:!le,onClick:De,icon:g===`deposit`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(bp,{className:`size-4`}),children:g===`deposit`?`Depositing`:`Deposit`}),(0,W.jsxs)(`label`,{className:`grid gap-2 text-sm font-black text-ink`,children:[`Withdraw`,(0,W.jsx)(`input`,{id:`withdraw-amount`,name:`withdraw_amount`,className:`min-h-11 rounded-md border border-black/10 bg-white px-3 text-base font-bold text-ink shadow-sm`,value:f,onChange:e=>p(e.target.value),type:`number`,inputMode:`decimal`,min:`0.000001`,step:`0.01`,required:!0,"aria-label":`Withdraw amount in ${o.toUpperCase()}`})]}),(0,W.jsx)(PP,{className:`self-end`,variant:`secondary`,disabled:!ue,onClick:Ce,icon:g===`withdraw`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(_p,{className:`size-4`}),children:g===`withdraw`?`Withdrawing`:`Withdraw`})]}):null]}),(0,W.jsxs)(NP,{children:[(0,W.jsx)(IP,{label:`Library`,title:`What you own`,icon:(0,W.jsx)(vp,{className:`size-5`})}),c?.library.length?(0,W.jsx)(np.div,{className:`grid gap-3`,children:c.library.map((e,t)=>(0,W.jsx)(np.div,{initial:{opacity:0,y:6},animate:{opacity:1,y:0},transition:{delay:t*.035},className:`rounded-lg border border-black/10 bg-white/90 p-4 shadow-sm`,children:(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-3 sm:flex-row sm:items-start sm:justify-between`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsx)(`p`,{className:`truncate text-base font-black text-ink`,children:e.title}),(0,W.jsx)(`p`,{className:`mt-1 line-clamp-2 text-sm leading-5 text-black/60`,children:e.description}),(0,W.jsxs)(`p`,{className:`mt-2 text-xs font-black uppercase tracking-wide text-black/50`,children:[e.type,` / `,e.price,` `,o.toUpperCase()]})]}),(0,W.jsx)(PP,{variant:`secondary`,disabled:g!==null,onClick:()=>Oe(e.id),icon:g===`content:${e.id}`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(mp,{className:`size-4`}),children:g===`content:${e.id}`?`Opening`:`Read`})]})},e.id))}):(0,W.jsx)(`div`,{className:`rounded-lg border border-dashed border-black/20 bg-white/60 p-5 text-sm font-semibold text-black/50`,children:`Your purchased items will appear here.`})]})]}),(0,W.jsxs)(`div`,{className:`grid gap-5 lg:grid-cols-[1.15fr_0.85fr]`,children:[(0,W.jsxs)(NP,{children:[(0,W.jsx)(IP,{label:`Catalog`,title:`Browse content`,icon:(0,W.jsx)(Sp,{className:`size-5`})}),c?.catalog.length?(0,W.jsx)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:c.catalog.map((t,n)=>{let r=S.has(t.id);return(0,W.jsx)(np.article,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{delay:n*.035},className:`rounded-lg border border-black/10 bg-white/90 p-4 shadow-sm transition hover:-translate-y-0.5 hover:border-yellow-line hover:shadow-card`,children:(0,W.jsxs)(`div`,{className:`flex min-h-full flex-col gap-4`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsxs)(`div`,{className:`mb-3 flex items-center justify-between gap-3`,children:[(0,W.jsxs)(`span`,{className:`rounded-md bg-yellow-brand px-2 py-1 text-xs font-black uppercase text-ink`,children:[`Item `,t.id]}),(0,W.jsxs)(`span`,{className:`text-sm font-black text-ink`,children:[t.prices[o],` `,o.toUpperCase()]})]}),(0,W.jsx)(`h3`,{className:`text-lg font-black tracking-normal text-ink`,children:t.title}),(0,W.jsx)(`p`,{className:`mt-2 line-clamp-3 text-sm leading-6 text-black/60`,children:t.description}),(0,W.jsx)(`p`,{className:`mt-3 text-xs font-black uppercase tracking-wide text-black/40`,children:t.type})]}),(0,W.jsx)(PP,{className:`mt-auto w-full`,disabled:!e||r||g!==null,onClick:()=>Se(t),icon:r?(0,W.jsx)(hp,{className:`size-4`}):g===`purchase:${t.id}`?(0,W.jsx)(yp,{className:`size-4 animate-spin`}):(0,W.jsx)(Sp,{className:`size-4`}),children:r?`Owned`:g===`purchase:${t.id}`?`Purchasing`:`Purchase`})]})},t.id)})}):(0,W.jsx)(`div`,{className:`rounded-lg border border-dashed border-black/20 bg-white/60 p-5 text-sm font-semibold text-black/50`,children:`Catalog loads after wallet connection.`})]}),(0,W.jsxs)(NP,{children:[(0,W.jsx)(IP,{label:`Reader`,title:m?.title??`Open content`,icon:(0,W.jsx)(mp,{className:`size-5`})}),m?(0,W.jsxs)(`article`,{className:`rounded-lg border border-black/10 bg-white/90 p-4 shadow-sm`,children:[(0,W.jsxs)(`p`,{className:`mb-3 text-xs font-black uppercase tracking-wide text-black/50`,children:[m.type,` / `,m.prices[o],` `,o.toUpperCase()]}),(0,W.jsx)(`pre`,{className:`whitespace-pre-wrap text-sm leading-7 text-black/75`,children:m.content})]}):(0,W.jsx)(`div`,{className:`rounded-lg border border-dashed border-black/20 bg-white/60 p-5 text-sm font-semibold text-black/50`,children:`Select a library item to read.`})]})]}),(0,W.jsxs)(NP,{children:[(0,W.jsxs)(`div`,{className:`mb-5 flex flex-col justify-between gap-3 sm:flex-row sm:items-center`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`p`,{className:`label-text`,children:`Browser activity`}),(0,W.jsx)(`h2`,{className:`mt-1 text-xl font-black text-ink sm:text-2xl`,children:`Recent actions`})]}),(0,W.jsx)(PP,{variant:`secondary`,onClick:ke,disabled:b.length===0,icon:(0,W.jsx)(gp,{className:`size-4`}),children:`Copy log`})]}),b.length?(0,W.jsx)(np.ul,{className:`grid gap-2`,children:b.map(e=>(0,W.jsxs)(np.li,{initial:{opacity:0,x:-6},animate:{opacity:1,x:0},className:`flex items-start gap-2 rounded-lg border border-black/10 bg-white/80 px-3 py-2 font-mono text-xs text-black/70`,children:[(0,W.jsx)(pp,{className:`mt-0.5 size-3.5 shrink-0 text-yellow-line`}),(0,W.jsx)(`span`,{className:`min-w-0 overflow-hidden text-ellipsis`,children:e})]},e))}):(0,W.jsx)(`div`,{className:`rounded-lg border border-dashed border-black/20 bg-white/60 p-4 text-sm font-semibold text-black/50`,children:`No activity yet.`})]})]})}(0,Oe.createRoot)(document.getElementById(`root`)).render((0,W.jsx)(N.StrictMode,{children:(0,W.jsx)(LP,{})}));export{iv as a,j_ as c,q as d,Vm as f,yb as i,Ig as l,nC as n,Z_ as o,aS as r,M_ as s,rC as t,Eg as u}; \ No newline at end of file diff --git a/internal/webui/dist/assets/index-rm6FHUcT.css b/internal/webui/dist/assets/index-rm6FHUcT.css deleted file mode 100644 index ce5103e..0000000 --- a/internal/webui/dist/assets/index-rm6FHUcT.css +++ /dev/null @@ -1 +0,0 @@ -:root{color:#1f1b17;font-synthesis:none;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:radial-gradient(circle at 0 0,#22716029,#0000 30%),radial-gradient(circle at 100% 0,#c9964624,#0000 28%),linear-gradient(#fbf7ef 0%,#f3ecdf 100%);font-family:SF Pro Text,Inter,system-ui,sans-serif}*{box-sizing:border-box}html,body,#root{min-height:100%}body{margin:0}a{color:inherit}.shell{width:min(1120px,100vw - 32px);margin:0 auto;padding:32px 0 56px}.hero,.panel{background:#fff9efeb;border:1px solid #24201a14;border-radius:28px;box-shadow:0 24px 60px #78684e24}.hero{grid-template-columns:minmax(0,1.6fr) minmax(280px,.8fr);gap:24px;margin-bottom:24px;padding:32px;display:grid}.eyebrow,.label,.meta{color:#6b6257;letter-spacing:.12em;text-transform:uppercase;font-size:.82rem}.lede,.supporting,.catalog-item p,.library-item p{color:#4a433b;line-height:1.65}.hero h1,.panel h2,.reader h3{color:#1f1b17;margin:8px 0 0;font-family:Iowan Old Style,Palatino Linotype,serif}.hero-actions{flex-direction:column;align-items:flex-start;gap:16px;display:flex}.identity-card,.stat{background:#ffffffa6;border:1px solid #24201a14;border-radius:20px;width:100%;padding:18px 20px}.grid{gap:24px;margin-bottom:24px;display:grid}.two-up{grid-template-columns:repeat(2,minmax(0,1fr))}.panel{padding:28px}.panel-head{justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:20px;display:flex}.stats{grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;margin-bottom:18px;display:grid}.form-grid{grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:16px;display:grid}.form-grid label,.asset-picker{color:#3f372f;flex-direction:column;gap:8px;font-weight:600;display:flex}input,select,button{font:inherit}input,select{color:#201c17;background:#ffffffeb;border:1px solid #24201a24;border-radius:14px;padding:13px 14px}button{cursor:pointer;border:0;border-radius:999px;padding:13px 18px;font-weight:700;transition:transform .16s,opacity .16s}button:disabled{cursor:not-allowed;opacity:.6}button:not(:disabled):hover{transform:translateY(-1px)}.primary{color:#fdfaf4;background:linear-gradient(135deg,#145f4f,#1c7f68)}.secondary{color:#145f4f;background:#ffffffd9;border:1px solid #145f4f33}.stack{gap:14px;display:grid}.catalog-item,.library-item{background:#ffffffbf;border:1px solid #24201a14;border-radius:20px;justify-content:space-between;align-items:flex-start;gap:16px;padding:18px;display:flex}.reader{background:#ffffffbf;border:1px solid #24201a14;border-radius:20px;padding:20px}.reader pre{white-space:pre-wrap;color:#2d2a26;margin:0;font-family:SF Mono,ui-monospace,monospace;line-height:1.7}.activity-list{gap:10px;margin:0;padding:0;list-style:none;display:grid}.activity-list li{color:#2e2923;background:#ffffffa6;border-radius:14px;padding:12px 14px;font-family:SF Mono,ui-monospace,monospace;font-size:.9rem}.alert{color:#fff4e6;background:#231d18;border-radius:18px;margin-bottom:24px;padding:16px 18px}@media (width<=900px){.hero,.two-up,.stats,.form-grid{grid-template-columns:1fr}.catalog-item,.library-item,.panel-head{flex-direction:column}.shell{width:min(100vw - 20px,1120px);padding-top:20px}} diff --git a/internal/webui/dist/index.html b/internal/webui/dist/index.html index 6c06fb5..b26bbef 100644 --- a/internal/webui/dist/index.html +++ b/internal/webui/dist/index.html @@ -4,10 +4,10 @@ - Simple Content Store - + Nitrolite App Session Store + - +
diff --git a/internal/webui/handler.go b/internal/webui/handler.go index 850d8dc..cb6932a 100644 --- a/internal/webui/handler.go +++ b/internal/webui/handler.go @@ -21,10 +21,6 @@ func New() (http.Handler, error) { serveIndex(w, sub) return } - if cleanPath == "/reference" || cleanPath == "/advanced" { - http.NotFound(w, r) - return - } if strings.HasPrefix(cleanPath, "/api/") { http.NotFound(w, r) return @@ -36,7 +32,7 @@ func New() (http.Handler, error) { return } - serveIndex(w, sub) + http.NotFound(w, r) }), nil } diff --git a/test/smoke/console_test.go b/test/smoke/console_test.go index f13b122..6050e88 100644 --- a/test/smoke/console_test.go +++ b/test/smoke/console_test.go @@ -10,12 +10,12 @@ import ( "strings" "testing" - "github.com/layer-3/nitrolite-go-example/internal/config" - internalhttp "github.com/layer-3/nitrolite-go-example/internal/httpapi" - "github.com/layer-3/nitrolite-go-example/internal/nitrolite" - "github.com/layer-3/nitrolite-go-example/internal/signing" - "github.com/layer-3/nitrolite-go-example/internal/store" - "github.com/layer-3/nitrolite-go-example/internal/testsupport" + "github.com/layer-3/nitrolite-store-example/internal/config" + internalhttp "github.com/layer-3/nitrolite-store-example/internal/httpapi" + "github.com/layer-3/nitrolite-store-example/internal/nitrolite" + "github.com/layer-3/nitrolite-store-example/internal/signing" + "github.com/layer-3/nitrolite-store-example/internal/store" + "github.com/layer-3/nitrolite-store-example/internal/testsupport" "github.com/layer-3/nitrolite/pkg/core" "github.com/shopspring/decimal" ) @@ -28,7 +28,6 @@ func TestScaffoldRoutes(t *testing.T) { LogLevel: "info", ClearnodeWSURL: "wss://example.invalid", DemoPrivateKey: "0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318", - ConsoleAPIKey: "12345678901234567890123456789012", BlockchainRPCURLs: map[string]string{"11155111": "https://example.invalid"}, HomeBlockchains: map[string]uint64{"yellow": 11155111, "yusd": 11155111}, SQLitePath: filepath.Join(t.TempDir(), "smoke.db"), @@ -43,8 +42,20 @@ func TestScaffoldRoutes(t *testing.T) { } client := &testsupport.FakeClient{ - GetBalancesFunc: func(context.Context, string) ([]core.BalanceEntry, error) { - return []core.BalanceEntry{{Asset: "yusd", Balance: decimal.RequireFromString("10.5")}}, nil + GetLatestStateFunc: func(_ context.Context, wallet string, asset string, _ bool) (*core.State, error) { + homeChannelID := "0xhome" + return &core.State{ + ID: "0xstate", + Asset: asset, + UserWallet: wallet, + HomeChannelID: &homeChannelID, + HomeLedger: core.Ledger{ + UserBalance: decimal.RequireFromString("10.5"), + UserNetFlow: decimal.RequireFromString("10.5"), + NodeBalance: decimal.Zero, + NodeNetFlow: decimal.Zero, + }, + }, nil }, } @@ -100,8 +111,8 @@ func TestScaffoldRoutes(t *testing.T) { } }) - t.Run("reference removed", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/reference", nil) + t.Run("unknown page removed", func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, "/missing-page", nil) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) @@ -111,25 +122,14 @@ func TestScaffoldRoutes(t *testing.T) { } }) - t.Run("advanced removed", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/advanced", nil) - rec := httptest.NewRecorder() - - handler.ServeHTTP(rec, req) - - if rec.Code != http.StatusNotFound { - t.Fatalf("status = %d, want %d", rec.Code, http.StatusNotFound) - } - }) - - t.Run("bootstrap requires auth", func(t *testing.T) { + t.Run("bootstrap requires wallet address", func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/store/bootstrap?asset=yusd", nil) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) - if rec.Code != http.StatusUnauthorized { - t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusUnauthorized, rec.Body.String()) + if rec.Code != http.StatusBadRequest { + t.Fatalf("status = %d, want %d body=%s", rec.Code, http.StatusBadRequest, rec.Body.String()) } }) } diff --git a/web/advanced.html b/web/advanced.html deleted file mode 100644 index 94f0088..0000000 --- a/web/advanced.html +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - Nitrolite Go Example | Advanced Developer - - - -
- - -
-
-
-
-

Developer mode

-

Raw surfaces, live context

-
-
-

Use this page when you need transport-level visibility, direct JSON payloads, session-key registration, or destructive operations. For the product-facing flow, stay on the store at `/`.

-
Checking unlock status…
-
- - - - -
-
- -
-

Health

Loading…
-

Wallet

Loading…
-

Node Config

Loading…
-

Supported Assets

Loading…
-

Balances

Loading…
-

Home Channel

Loading…
-

Latest Signed State

Loading…
-

Apps

Loading…
-

Sessions

Loading…
-

Channel Session Keys

Loading…
-

App Session Keys

Loading…
-
- -
-

Channel mutations

Raw channel forms

-
-
-

Approve token

- - -
Idle
-
-
-

Deposit

- - -
Idle
-
-
-

Withdraw

- - -
Idle
-
-
-

Transfer

- - - -
Idle
-
-
-

Checkpoint

-

Uses the focused asset.

- -
Idle
-
-
-

Close channel

-

Dangerous. Uses the focused asset and closes the home channel.

- -
Idle
-
-
-
- -
-

Apps and sessions

Raw session forms

-
-
-

Register app

- - - - -
Idle
-
-
-

Create session

- - - - -
Idle
-
-
-

Session deposit

- - -
Idle
-
-
-

Session operate

- - - -
Idle
-
-
-

Session close

-

Closes the focused session.

- -
Idle
-
-
-
- -
-

Session keys and destructive ops

Advanced protocol controls

-
-
-

Register channel key

- - - - -
Idle
-
-
-

Register app key

- - - - - -
Idle
-
-
-

Challenge state

-

Uses the focused asset and challenges the latest known state for that asset.

- -
Idle
-
-
-
- -
-

Transport view

Activity log

-
No activity yet.
-
-
- - - - - - - diff --git a/web/assets.go b/web/assets.go deleted file mode 100644 index 0690752..0000000 --- a/web/assets.go +++ /dev/null @@ -1,8 +0,0 @@ -package web - -import "embed" - -// FS contains the embedded web console assets. -// -//go:embed *.html *.css *.js -var FS embed.FS diff --git a/web/common.js b/web/common.js deleted file mode 100644 index 1a436d5..0000000 --- a/web/common.js +++ /dev/null @@ -1,343 +0,0 @@ -(function bootstrapCommon(global) { - const state = { - auth: { - unlocked: false, - expires_at: "", - }, - activity: [], - pendingUnlockPromise: null, - pendingUnlockResolve: null, - }; - const authListeners = new Set(); - const activityListeners = new Set(); - - function setText(selector, value) { - const element = typeof selector === "string" ? document.querySelector(selector) : selector; - if (element) { - element.textContent = value; - } - } - - function formatJSON(value) { - return JSON.stringify(value, null, 2); - } - - function shortAddress(value) { - if (!value || value.length < 12) { - return value || "Unavailable"; - } - return `${value.slice(0, 6)}…${value.slice(-4)}`; - } - - function titleCase(value) { - return String(value || "") - .replace(/[_-]+/g, " ") - .replace(/\b\w/g, (match) => match.toUpperCase()); - } - - function formatTime(value) { - if (!value) { - return "Unavailable"; - } - const parsed = new Date(value); - if (Number.isNaN(parsed.getTime())) { - return value; - } - return parsed.toLocaleString(); - } - - function notifyAuth() { - const message = state.auth.unlocked - ? state.auth.expires_at - ? `Writes unlocked until ${formatTime(state.auth.expires_at)}` - : "Writes unlocked for this browser session" - : "Writes locked. Reads are public."; - - if (state.auth.unlocked) { - closeUnlockModal(); - } - - document.querySelectorAll("[data-auth-status]").forEach((node) => { - node.textContent = message; - }); - document.querySelectorAll("[data-auth-open]").forEach((node) => { - node.hidden = state.auth.unlocked; - }); - document.querySelectorAll("[data-auth-lock]").forEach((node) => { - node.hidden = !state.auth.unlocked; - }); - authListeners.forEach((listener) => listener({ ...state.auth })); - } - - function notifyActivity(entry) { - activityListeners.forEach((listener) => listener(entry, state.activity.slice())); - } - - function logActivity(entry) { - const item = { - timestamp: new Date().toISOString(), - ...entry, - }; - state.activity.unshift(item); - state.activity = state.activity.slice(0, 30); - notifyActivity(item); - } - - async function requestJSON(url, options = {}) { - const method = options.method || "GET"; - const headers = new Headers(options.headers || {}); - let body = options.body; - - if (body !== undefined && !(body instanceof FormData)) { - headers.set("Content-Type", "application/json"); - body = JSON.stringify(body); - } - - const response = await fetch(url, { - method, - headers, - body, - credentials: "same-origin", - }); - const data = await response.json().catch(() => ({})); - - if (!options.skipLog) { - logActivity({ - method, - url, - status: response.status, - ok: response.ok, - body: options.body ?? null, - response: data, - }); - } - - if (!response.ok) { - const error = new Error(data?.error?.message || "request failed"); - error.status = response.status; - error.payload = data; - throw error; - } - - return data; - } - - async function refreshAuthStatus() { - const data = await requestJSON("/api/v1/auth/status", { skipLog: true }); - state.auth = { - unlocked: Boolean(data.unlocked), - expires_at: data.expires_at || "", - }; - notifyAuth(); - return { ...state.auth }; - } - - async function unlock(apiKey) { - const data = await requestJSON("/api/v1/auth/unlock", { - method: "POST", - body: { api_key: apiKey }, - skipLog: true, - }); - state.auth = { - unlocked: Boolean(data.unlocked), - expires_at: data.expires_at || "", - }; - notifyAuth(); - return { ...state.auth }; - } - - async function lock() { - const data = await requestJSON("/api/v1/auth/lock", { - method: "POST", - body: {}, - skipLog: true, - }); - state.auth = { - unlocked: Boolean(data.unlocked), - expires_at: data.expires_at || "", - }; - notifyAuth(); - return { ...state.auth }; - } - - function onAuthChange(listener) { - authListeners.add(listener); - listener({ ...state.auth }); - return () => authListeners.delete(listener); - } - - function onActivity(listener) { - activityListeners.add(listener); - return () => activityListeners.delete(listener); - } - - function openUnlockModal() { - const modal = document.getElementById("unlock-modal"); - const input = document.getElementById("unlock-api-key"); - const error = document.getElementById("unlock-error"); - if (!modal || state.auth.unlocked) { - return; - } - if (error) { - error.hidden = true; - error.textContent = ""; - } - setModalVisibility(modal, true); - if (input) { - input.focus(); - input.select(); - } - } - - function closeUnlockModal() { - closeUnlockModalWithOptions({}); - } - - function closeUnlockModalWithOptions(options) { - const modal = document.getElementById("unlock-modal"); - const form = document.getElementById("unlock-form"); - const error = document.getElementById("unlock-error"); - if (!modal) { - return; - } - setModalVisibility(modal, false); - if (form) { - form.reset(); - } - if (error) { - error.hidden = true; - error.textContent = ""; - } - if (options.resolvePending) { - settlePendingUnlock(false); - } - } - - function setModalVisibility(modal, isOpen) { - modal.hidden = !isOpen; - modal.setAttribute("aria-hidden", String(!isOpen)); - modal.style.display = isOpen ? "grid" : "none"; - } - - function settlePendingUnlock(value) { - if (state.pendingUnlockResolve) { - state.pendingUnlockResolve(value); - } - state.pendingUnlockResolve = null; - state.pendingUnlockPromise = null; - } - - async function ensureUnlocked() { - if (state.auth.unlocked) { - return true; - } - openUnlockModal(); - if (!state.pendingUnlockPromise) { - state.pendingUnlockPromise = new Promise((resolve) => { - state.pendingUnlockResolve = resolve; - }); - } - return state.pendingUnlockPromise; - } - - function initUnlockModal() { - document.querySelectorAll("[data-auth-open]").forEach((node) => { - node.addEventListener("click", () => openUnlockModal()); - }); - document.querySelectorAll("[data-auth-lock]").forEach((node) => { - node.addEventListener("click", async () => { - await lock(); - }); - }); - - const modal = document.getElementById("unlock-modal"); - const form = document.getElementById("unlock-form"); - const error = document.getElementById("unlock-error"); - if (!modal || !form) { - return; - } - setModalVisibility(modal, false); - - modal.addEventListener("click", (event) => { - if (event.target === modal) { - closeUnlockModalWithOptions({ resolvePending: true }); - } - }); - document.addEventListener("keydown", (event) => { - if (event.key === "Escape" && !modal.hidden) { - closeUnlockModalWithOptions({ resolvePending: true }); - } - }); - document.querySelectorAll("[data-modal-close]").forEach((node) => { - node.addEventListener("click", () => closeUnlockModalWithOptions({ resolvePending: true })); - }); - form.addEventListener("submit", async (event) => { - event.preventDefault(); - try { - await unlock(new FormData(form).get("api_key")); - settlePendingUnlock(true); - closeUnlockModal(); - } catch (err) { - if (error) { - error.hidden = false; - error.textContent = err.message; - } - } - }); - } - - function fillSelect(select, items, getValue, getLabel, preferredValue) { - if (!select) { - return; - } - const previousValue = preferredValue ?? select.value; - select.innerHTML = ""; - items.forEach((item) => { - const option = document.createElement("option"); - option.value = getValue(item); - option.textContent = getLabel(item); - select.appendChild(option); - }); - if (items.length === 0) { - const option = document.createElement("option"); - option.value = ""; - option.textContent = "Unavailable"; - select.appendChild(option); - } - if ([...select.options].some((option) => option.value === previousValue)) { - select.value = previousValue; - } - } - - function renderJSON(target, value) { - const element = typeof target === "string" ? document.querySelector(target) : target; - if (element) { - element.textContent = formatJSON(value); - } - } - - global.NitroliteUI = { - requestJSON, - refreshAuthStatus, - unlock, - lock, - ensureUnlocked, - initUnlockModal, - onAuthChange, - onActivity, - logActivity, - setText, - renderJSON, - fillSelect, - formatJSON, - formatTime, - shortAddress, - titleCase, - get auth() { - return { ...state.auth }; - }, - get activity() { - return state.activity.slice(); - }, - }; -})(window); diff --git a/web/console.js b/web/console.js deleted file mode 100644 index 9c2e939..0000000 --- a/web/console.js +++ /dev/null @@ -1,361 +0,0 @@ -(function advancedConsole(global) { - const UI = global.NitroliteUI; - const state = { - wallet: null, - assets: [], - apps: [], - sessions: [], - selectedAsset: "", - selectedSessionID: "", - }; - - function setResult(formID, value, isError) { - const node = document.querySelector(`#${formID} [data-result]`); - if (!node) { - return; - } - node.textContent = typeof value === "string" ? value : UI.formatJSON(value); - node.classList.toggle("error-text", Boolean(isError)); - } - - function parseJSONArray(raw, label) { - try { - const parsed = JSON.parse(raw); - if (!Array.isArray(parsed)) { - throw new Error("must be a JSON array"); - } - return parsed; - } catch (err) { - throw new Error(`${label}: ${err.message}`); - } - } - - function chainName(chainID) { - const blockchains = JSON.parse(document.getElementById("advanced-node-config")?.dataset.blockchains || "[]"); - const found = blockchains.find((item) => item.id === chainID); - return found ? UI.titleCase(found.name) : `Chain ${chainID}`; - } - - function currentSession() { - return state.sessions.find((session) => session.app_session_id === state.selectedSessionID) || null; - } - - function focusedAssets() { - const homeBlockchains = state.wallet?.homeBlockchains || {}; - const configured = state.assets.filter((asset) => homeBlockchains[asset.symbol]); - if (configured.length === 0) { - return state.assets; - } - return configured.sort((left, right) => { - if (left.symbol === "yusd") { - return -1; - } - if (right.symbol === "yusd") { - return 1; - } - return left.symbol.localeCompare(right.symbol); - }); - } - - function populateSelectors() { - const assetSelect = document.getElementById("advanced-asset-select"); - const chainSelect = document.getElementById("advanced-chain-select"); - const appSelect = document.getElementById("advanced-app-select"); - const sessionSelect = document.getElementById("advanced-session-select"); - const assets = focusedAssets(); - - const preferredAsset = state.selectedAsset || (assets.some((asset) => asset.symbol === "yusd") ? "yusd" : assets[0]?.symbol || ""); - UI.fillSelect(assetSelect, assets, (asset) => asset.symbol, (asset) => `${asset.symbol.toUpperCase()} • ${asset.name}`, preferredAsset); - state.selectedAsset = assetSelect?.value || state.selectedAsset; - - const asset = assets.find((item) => item.symbol === state.selectedAsset); - const chainOptions = []; - const seen = new Set(); - (asset?.tokens || []).forEach((token) => { - if (!seen.has(token.blockchainId)) { - seen.add(token.blockchainId); - chainOptions.push({ id: token.blockchainId }); - } - }); - if (chainOptions.length === 0 && asset?.suggestedBlockchainID) { - chainOptions.push({ id: asset.suggestedBlockchainID }); - } - UI.fillSelect( - chainSelect, - chainOptions, - (item) => String(item.id), - (item) => chainName(item.id), - String(state.wallet?.homeBlockchains?.[state.selectedAsset] || asset?.suggestedBlockchainID || ""), - ); - UI.fillSelect(appSelect, state.apps, (item) => item.app_id, (item) => item.app_id, appSelect?.value || "default"); - UI.fillSelect( - sessionSelect, - state.sessions, - (item) => item.app_session_id, - (item) => `${item.app_session_id.slice(0, 10)}… • ${item.status} • v${item.version}`, - state.selectedSessionID, - ); - state.selectedSessionID = sessionSelect?.value || ""; - - const createAppInput = document.querySelector('#create-session-form input[name="application_id"]'); - if (createAppInput && appSelect?.value) { - createAppInput.value = appSelect.value; - } - - const assetDefaults = { - createAllocation: `[{"asset":"${state.selectedAsset || "yusd"}","amount":"0.5"}]`, - channelKeyAssets: `["${state.selectedAsset || "yusd"}"]`, - appKeyApps: `["${appSelect?.value || "default"}"]`, - }; - const createAllocations = document.querySelector('#create-session-form textarea[name="initial_allocations"]'); - if (createAllocations && (!createAllocations.value || createAllocations.value === "[]")) { - createAllocations.value = assetDefaults.createAllocation; - } - const channelKeyAssets = document.querySelector('#channel-key-form textarea[name="assets"]'); - if (channelKeyAssets) { - channelKeyAssets.value = assetDefaults.channelKeyAssets; - } - const appKeyApps = document.querySelector('#app-key-form textarea[name="application_ids"]'); - if (appKeyApps) { - appKeyApps.value = assetDefaults.appKeyApps; - } - - hydrateSessionDefaults(); - } - - function hydrateSessionDefaults() { - const session = currentSession(); - const allocations = document.querySelector('#session-state-form textarea[name="allocations"]'); - const sessionData = document.querySelector('#session-state-form textarea[name="session_data"]'); - if (session && allocations) { - allocations.value = UI.formatJSON(session.allocations || []); - } - if (session && sessionData && (!sessionData.value || sessionData.value === "{}")) { - sessionData.value = session.session_data || "{}"; - } - } - - async function refreshAll() { - const asset = state.selectedAsset || ""; - const [health, wallet, nodeConfig, assets, balances, channel, latestState, apps, sessions, channelKeys, appKeys] = await Promise.all([ - UI.requestJSON("/healthz"), - UI.requestJSON("/api/v1/wallet"), - UI.requestJSON("/api/v1/node/config"), - UI.requestJSON("/api/v1/node/assets"), - UI.requestJSON("/api/v1/balances"), - asset ? UI.requestJSON(`/api/v1/channel?asset=${encodeURIComponent(asset)}`).catch((error) => ({ error: error.message })) : Promise.resolve({ error: "select an asset" }), - asset ? UI.requestJSON(`/api/v1/channel/state?asset=${encodeURIComponent(asset)}&only_signed=true`).catch((error) => ({ error: error.message })) : Promise.resolve({ error: "select an asset" }), - UI.requestJSON("/api/v1/apps?page=1&per_page=20").catch((error) => ({ apps: [], error: error.message })), - UI.requestJSON("/api/v1/sessions?status=all&page=1&per_page=20").catch((error) => ({ sessions: [], error: error.message })), - UI.requestJSON("/api/v1/session-keys/channel").catch((error) => ({ states: [], error: error.message })), - UI.requestJSON("/api/v1/session-keys/app").catch((error) => ({ states: [], error: error.message })), - UI.refreshAuthStatus(), - ]); - - state.wallet = { - address: wallet.address, - homeBlockchains: wallet.homeBlockchains || wallet.home_blockchains || {}, - }; - state.assets = assets.assets || []; - state.apps = apps.apps || []; - state.sessions = sessions.sessions || []; - - document.getElementById("advanced-node-config").dataset.blockchains = UI.formatJSON(nodeConfig.blockchains || []); - UI.renderJSON("#advanced-health", health); - UI.renderJSON("#advanced-wallet", wallet); - UI.renderJSON("#advanced-node-config", nodeConfig); - UI.renderJSON("#advanced-assets", assets); - UI.renderJSON("#advanced-balances", balances); - UI.renderJSON("#advanced-channel", channel); - UI.renderJSON("#advanced-latest-state", latestState); - UI.renderJSON("#advanced-apps", apps); - UI.renderJSON("#advanced-sessions", sessions); - UI.renderJSON("#advanced-channel-keys", channelKeys); - UI.renderJSON("#advanced-app-keys", appKeys); - populateSelectors(); - } - - async function runWrite(formID, action) { - try { - if (!(await UI.ensureUnlocked())) { - setResult(formID, "Unlock write actions to continue.", false); - return; - } - const result = await action(); - setResult(formID, result, false); - await refreshAll(); - } catch (err) { - setResult(formID, err.message, true); - } - } - - function bindForm(formID, handler) { - document.getElementById(formID)?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite(formID, () => handler(formData)); - }); - } - - function bindEvents() { - document.getElementById("advanced-refresh")?.addEventListener("click", () => { - void refreshAll(); - }); - document.getElementById("advanced-asset-select")?.addEventListener("change", (event) => { - state.selectedAsset = event.target.value; - void refreshAll(); - }); - document.getElementById("advanced-app-select")?.addEventListener("change", () => populateSelectors()); - document.getElementById("advanced-session-select")?.addEventListener("change", (event) => { - state.selectedSessionID = event.target.value; - hydrateSessionDefaults(); - }); - - bindForm("approve-form", async (formData) => { - return UI.requestJSON("/api/v1/approve", { - method: "POST", - body: { - blockchain_id: Number(document.getElementById("advanced-chain-select")?.value), - asset: state.selectedAsset, - amount: String(formData.get("amount") || "").trim(), - }, - }); - }); - bindForm("deposit-form", async (formData) => { - return UI.requestJSON("/api/v1/deposit", { - method: "POST", - body: { - blockchain_id: Number(document.getElementById("advanced-chain-select")?.value), - asset: state.selectedAsset, - amount: String(formData.get("amount") || "").trim(), - }, - }); - }); - bindForm("withdraw-form", async (formData) => { - return UI.requestJSON("/api/v1/withdraw", { - method: "POST", - body: { - blockchain_id: Number(document.getElementById("advanced-chain-select")?.value), - asset: state.selectedAsset, - amount: String(formData.get("amount") || "").trim(), - }, - }); - }); - bindForm("transfer-form", async (formData) => { - return UI.requestJSON("/api/v1/transfer", { - method: "POST", - body: { - recipient: String(formData.get("recipient") || "").trim(), - asset: state.selectedAsset, - amount: String(formData.get("amount") || "").trim(), - }, - }); - }); - bindForm("checkpoint-form", async () => { - return UI.requestJSON("/api/v1/checkpoint", { - method: "POST", - body: { asset: state.selectedAsset }, - }); - }); - bindForm("close-channel-form", async () => { - return UI.requestJSON("/api/v1/channel/close", { - method: "POST", - body: { asset: state.selectedAsset }, - }); - }); - bindForm("register-app-form", async (formData) => { - return UI.requestJSON("/api/v1/apps/register", { - method: "POST", - body: { - app_id: String(formData.get("app_id") || "").trim(), - metadata: String(formData.get("metadata") || "").trim(), - creation_approval_not_required: formData.get("creation_approval_not_required") === "on", - }, - }); - }); - bindForm("create-session-form", async (formData) => { - return UI.requestJSON("/api/v1/sessions", { - method: "POST", - body: { - application_id: String(formData.get("application_id") || "").trim(), - initial_allocations: parseJSONArray(String(formData.get("initial_allocations") || "[]"), "initial_allocations"), - session_data: String(formData.get("session_data") || "{}"), - }, - }); - }); - bindForm("session-deposit-form", async (formData) => { - return UI.requestJSON(`/api/v1/sessions/${encodeURIComponent(state.selectedSessionID)}/deposit`, { - method: "POST", - body: { - asset: state.selectedAsset, - amount: String(formData.get("amount") || "").trim(), - }, - }); - }); - bindForm("session-state-form", async (formData) => { - return UI.requestJSON(`/api/v1/sessions/${encodeURIComponent(state.selectedSessionID)}/state`, { - method: "POST", - body: { - allocations: parseJSONArray(String(formData.get("allocations") || "[]"), "allocations"), - session_data: String(formData.get("session_data") || "{}"), - }, - }); - }); - bindForm("session-close-form", async () => { - return UI.requestJSON(`/api/v1/sessions/${encodeURIComponent(state.selectedSessionID)}/close`, { - method: "POST", - body: {}, - }); - }); - bindForm("channel-key-form", async (formData) => { - return UI.requestJSON("/api/v1/session-keys/channel", { - method: "POST", - body: { - session_key: String(formData.get("session_key") || "").trim(), - assets: parseJSONArray(String(formData.get("assets") || "[]"), "assets"), - expires_at: String(formData.get("expires_at") || "").trim(), - }, - }); - }); - bindForm("app-key-form", async (formData) => { - return UI.requestJSON("/api/v1/session-keys/app", { - method: "POST", - body: { - session_key: String(formData.get("session_key") || "").trim(), - application_ids: parseJSONArray(String(formData.get("application_ids") || "[]"), "application_ids"), - app_session_ids: parseJSONArray(String(formData.get("app_session_ids") || "[]"), "app_session_ids"), - expires_at: String(formData.get("expires_at") || "").trim(), - }, - }); - }); - bindForm("challenge-form", async (formData) => { - return UI.requestJSON("/api/v1/challenge", { - method: "POST", - body: { - asset: state.selectedAsset, - }, - }); - }); - } - - function initActivityLog() { - const target = document.getElementById("advanced-activity-log"); - if (!target) { - return; - } - UI.onActivity(() => { - target.textContent = UI.formatJSON(UI.activity); - }); - } - - async function init() { - UI.initUnlockModal(); - initActivityLog(); - bindEvents(); - await refreshAll(); - } - - document.addEventListener("DOMContentLoaded", () => { - void init(); - }); -})(window); diff --git a/web/guided.js b/web/guided.js deleted file mode 100644 index 4198e73..0000000 --- a/web/guided.js +++ /dev/null @@ -1,674 +0,0 @@ -(function guidedDemo(global) { - const UI = global.NitroliteUI; - const state = { - overview: null, - blockchains: [], - selectedAsset: "", - history: [], - pendingApproval: null, - pendingCheckpoint: null, - }; - - function numberValue(raw) { - const value = Number(raw); - return Number.isFinite(value) ? value : 0; - } - - function findAsset(symbol) { - return state.overview?.assets?.find((asset) => asset.symbol === symbol) || null; - } - - function homeChainForAsset(symbol) { - return state.overview?.wallet?.home_blockchains?.[symbol] || 0; - } - - function demoAssets() { - if (!state.overview) { - return []; - } - const homeBlockchains = state.overview.wallet.home_blockchains || {}; - return (state.overview.assets || []).filter((asset) => { - const chainID = homeBlockchains[asset.symbol]; - if (!chainID) { - return false; - } - return (asset.tokens || []).some((token) => token.blockchainId === chainID); - }); - } - - function demoNetworkIDs() { - const homeBlockchains = state.overview?.wallet?.home_blockchains || {}; - return [...new Set(Object.values(homeBlockchains))].sort((left, right) => left - right); - } - - function tokenForHomeChain(asset) { - const chainID = homeChainForAsset(asset.symbol); - return (asset.tokens || []).find((token) => token.blockchainId === chainID) || null; - } - - function gasAssetForChain(chainID) { - return (state.overview?.assets || []).find((asset) => - (asset.tokens || []).some((token) => token.blockchainId === chainID && /^0x0+$/.test(token.address)), - ) || null; - } - - function findSession(sessionID) { - return state.overview?.sessions?.find((session) => session.app_session_id === sessionID) || null; - } - - function chainName(chainID) { - const blockchain = state.blockchains.find((item) => item.id === chainID); - return blockchain ? UI.titleCase(blockchain.name) : `Chain ${chainID}`; - } - - function pushHistory(message) { - state.history.unshift({ - timestamp: new Date().toISOString(), - message, - }); - state.history = state.history.slice(0, 10); - renderHistory(); - } - - function rememberApproval(asset, chainID, amount, txHash) { - state.pendingApproval = { - asset, - chainID, - amount, - txHash, - createdAt: new Date().toISOString(), - }; - } - - function clearPendingApproval() { - state.pendingApproval = null; - } - - function rememberCheckpoint(asset, version, txHash) { - state.pendingCheckpoint = { - asset, - version, - txHash, - createdAt: new Date().toISOString(), - }; - } - - function clearPendingCheckpoint() { - state.pendingCheckpoint = null; - } - - function approvalStillRelevant() { - return Boolean( - state.pendingApproval && - state.pendingApproval.asset === state.selectedAsset && - state.pendingApproval.chainID === homeChainForAsset(state.selectedAsset), - ); - } - - function checkpointStillRelevant() { - return Boolean( - state.pendingCheckpoint && - state.pendingCheckpoint.asset === state.selectedAsset && - state.pendingCheckpoint.version === (state.overview?.latest_state?.version || 0), - ); - } - - function checkpointAllowanceHint() { - if (!approvalStillRelevant()) { - return ""; - } - return `The latest approval tx ${UI.shortAddress(state.pendingApproval.txHash)} may still be confirming on-chain. If checkpoint fails on allowance, wait for confirmation and retry.`; - } - - function reconcilePendingMutations() { - const channelVersion = state.overview?.channel?.stateVersion || 0; - const latestVersion = state.overview?.latest_state?.version || 0; - - if (state.pendingCheckpoint) { - if ( - state.pendingCheckpoint.asset !== state.selectedAsset || - channelVersion >= state.pendingCheckpoint.version || - latestVersion > state.pendingCheckpoint.version - ) { - clearPendingCheckpoint(); - } - } - - if (state.pendingApproval && state.pendingApproval.asset !== state.selectedAsset) { - clearPendingApproval(); - } - } - - function renderHistory() { - const list = document.getElementById("guided-history"); - if (!list) { - return; - } - if (state.history.length === 0) { - list.innerHTML = '
  • No guided actions yet.
  • '; - return; - } - list.innerHTML = state.history - .map((entry) => `
  • ${UI.formatTime(entry.timestamp)}${entry.message}
  • `) - .join(""); - } - - function renderStatus() { - const overview = state.overview; - if (!overview) { - return; - } - UI.setText("#status-clearnode", overview.status.connected ? "Connected" : "Disconnected"); - UI.setText("#status-ready", overview.status.ready ? "Ready" : "Not ready"); - UI.setText("#status-signer", UI.shortAddress(overview.wallet.address)); - UI.setText("#status-next-action", UI.titleCase(overview.channel_guidance.next_action || "review_supported_assets")); - } - - function renderAssets() { - const assetRoot = document.getElementById("asset-cards"); - const networkRoot = document.getElementById("network-cards"); - if (!assetRoot || !networkRoot || !state.overview) { - return; - } - - const networkCards = demoNetworkIDs().map((chainID) => { - const gasAsset = gasAssetForChain(chainID); - const tokens = demoAssets() - .filter((asset) => homeChainForAsset(asset.symbol) === chainID) - .map((asset) => asset.symbol.toUpperCase()) - .join(", "); - return ` -
    -
    -
    - ${chainName(chainID)} -

    Configured demo network

    -
    - Chain ${chainID} -
    -

    Demo tokens on this network: ${tokens || "None"}.

    -

    Gas asset: ${gasAsset ? gasAsset.symbol.toUpperCase() : "Native token not exposed"}.

    -
    - `; - }); - - const cards = demoAssets().map((asset) => { - const homeChain = homeChainForAsset(asset.symbol); - const token = tokenForHomeChain(asset); - return ` -
    -
    -
    - ${asset.symbol.toUpperCase()} -

    ${asset.name}

    -
    - ${chainName(homeChain)} -
    -

    Configured home chain: ${chainName(homeChain)}

    -
      -
    • ERC-20 address: ${token ? UI.shortAddress(token.address) : "Unavailable"}
    • -
    • Decimals: ${token ? token.decimals : asset.decimals}
    • -
    -
    - `; - }); - networkRoot.innerHTML = networkCards.join("") || '
    No configured demo networks.
    '; - assetRoot.innerHTML = cards.join("") || '
    No configured demo tokens.
    '; - } - - function renderBalances() { - const root = document.getElementById("balance-list"); - if (!root || !state.overview) { - return; - } - const balances = state.overview.balances || []; - if (balances.length === 0) { - root.innerHTML = '
    No channel balances reported yet.
    '; - return; - } - root.innerHTML = balances - .map((balance) => ` -
    - ${balance.balance} - ${balance.asset.toUpperCase()} -
    - `) - .join(""); - } - - function renderChannelSummary() { - const root = document.getElementById("channel-summary"); - const overview = state.overview; - if (!root || !overview) { - return; - } - if (!overview.channel) { - root.innerHTML = `

    ${overview.channel_guidance.description}

    `; - return; - } - root.innerHTML = ` -
    Status${UI.titleCase(overview.channel.status)}
    -
    Version${overview.channel.stateVersion}
    -
    Asset${overview.channel.asset.toUpperCase()}
    -
    Home chain${chainName(overview.channel.blockchainID)}
    -

    ${overview.channel_guidance.description}

    - `; - } - - function renderLatestState() { - const root = document.getElementById("latest-state-summary"); - const overview = state.overview; - if (!root || !overview) { - return; - } - if (!overview.latest_state) { - root.innerHTML = '

    No signed state returned yet for the selected asset.

    '; - return; - } - root.innerHTML = ` -
    Version${overview.latest_state.version}
    -
    Transition${UI.titleCase(overview.latest_state.transition.type)}
    -
    Amount${overview.latest_state.transition.amount}
    -
    Channel${UI.shortAddress(overview.latest_state.homeChannelID)}
    -

    ${overview.latest_state.userSig && overview.latest_state.nodeSig ? "Both signatures are present on the latest state." : "Waiting for both signatures on the latest state."}

    - `; - } - - function renderLatestActivity() { - const root = document.getElementById("activity-summary"); - const overview = state.overview; - if (!root || !overview) { - return; - } - if (!overview.latest_activity) { - root.innerHTML = '

    No recent activity returned by the node yet.

    '; - return; - } - root.innerHTML = ` -
    Type${UI.titleCase(overview.latest_activity.type)}
    -
    Asset${overview.latest_activity.asset.toUpperCase()}
    -
    Amount${overview.latest_activity.amount}
    -
    When${UI.formatTime(overview.latest_activity.timestamp)}
    -

    Latest transaction id: ${UI.shortAddress(overview.latest_activity.id)}

    - `; - } - - function renderSelectors() { - if (!state.overview) { - return; - } - const assetSelect = document.getElementById("guided-asset-select"); - const chainSelect = document.getElementById("guided-chain-select"); - const appSelect = document.getElementById("guided-app-select"); - const sessionSelect = document.getElementById("guided-session-select"); - const availableDemoAssets = demoAssets(); - - UI.fillSelect(assetSelect, availableDemoAssets, (asset) => asset.symbol, (asset) => `${asset.symbol.toUpperCase()} • ${asset.name}`, state.selectedAsset); - state.selectedAsset = assetSelect?.value || state.selectedAsset; - - const selectedAsset = findAsset(state.selectedAsset); - const configuredChainID = selectedAsset ? homeChainForAsset(selectedAsset.symbol) : 0; - const chainOptions = configuredChainID ? [{ id: configuredChainID }] : []; - UI.fillSelect(chainSelect, chainOptions, (item) => String(item.id), (item) => chainName(item.id), String(configuredChainID || "")); - - UI.fillSelect(appSelect, state.overview.apps || [], (item) => item.app_id, (item) => `${item.app_id}${item.creation_approval_not_required ? " • no owner approval" : ""}`, "default"); - UI.fillSelect( - sessionSelect, - state.overview.sessions || [], - (item) => item.app_session_id, - (item) => `${item.app_session_id.slice(0, 10)}… • ${item.status} • v${item.version}`, - sessionSelect?.value || "", - ); - } - - function renderGuidance() { - const overview = state.overview; - if (!overview) { - return; - } - const channelBanner = document.getElementById("channel-guidance-banner"); - const appBanner = document.getElementById("app-guidance-banner"); - if (checkpointStillRelevant()) { - UI.setText( - channelBanner, - `Checkpoint submitted for the current signed home state (${UI.shortAddress(state.pendingCheckpoint.txHash)}). Wait for chain confirmation and clearnode sync before retrying other channel transitions.`, - ); - } else { - const extraCheckpointHint = - overview.channel_guidance.next_action === "checkpoint" ? checkpointAllowanceHint() : ""; - UI.setText(channelBanner, [overview.channel_guidance.description, extraCheckpointHint].filter(Boolean).join(" ")); - } - UI.setText(appBanner, overview.app_guidance.description); - channelBanner?.classList.toggle("warning", Boolean(overview.channel_guidance.sync_pending)); - appBanner?.classList.remove("warning"); - } - - function setStepResult(formID, message, isError) { - const node = document.querySelector(`#${formID} [data-result]`); - if (!node) { - return; - } - node.textContent = message; - node.classList.toggle("error-text", Boolean(isError)); - } - - function setStepNote(formID, message, isWarning) { - const node = document.querySelector(`#${formID} [data-note]`); - if (!node) { - return; - } - node.textContent = message || ""; - node.classList.toggle("warning", Boolean(isWarning)); - } - - function friendlyWriteError(formID, err) { - const message = err?.message || "request failed"; - if (formID === "guided-checkpoint-form" && message.includes("allowance is not sufficient to cover the deposit amount")) { - return "Checkpoint failed because the approval is not usable on-chain yet. Wait for the approval transaction to confirm, or approve again with enough allowance, then retry checkpoint."; - } - if ( - (formID === "guided-deposit-form" || formID === "guided-withdraw-form" || formID === "guided-transfer-form") && - message.includes("ongoing state transitions check failed") - ) { - return "Clearnode is still reconciling the previous signed state. Wait for sync to finish before submitting the next channel transition."; - } - return message; - } - - function currentBalance(asset) { - const entry = state.overview?.balances?.find((balance) => balance.asset === asset); - return entry ? Number(entry.balance) : 0; - } - - function checkpointableTransition(overview) { - const transitionType = overview?.latest_state?.transition?.type || ""; - return transitionType === "home_deposit" || transitionType === "home_withdrawal"; - } - - function updateActionState() { - const overview = state.overview; - if (!overview) { - return; - } - const syncPending = overview.channel_guidance.sync_pending; - const currentSession = findSession(document.getElementById("guided-session-select")?.value); - const openSession = currentSession && currentSession.status === "open"; - const selectedAsset = state.selectedAsset; - const canCheckpoint = Boolean( - overview.channel && - overview.latest_state && - overview.latest_state.version > overview.channel.stateVersion && - checkpointableTransition(overview) && - !checkpointStillRelevant(), - ); - const hasBalance = currentBalance(selectedAsset) > 0; - - document.querySelector("#guided-approve-form button").disabled = !selectedAsset; - document.querySelector("#guided-deposit-form button").disabled = !selectedAsset || syncPending; - document.querySelector("#guided-checkpoint-form button").disabled = !selectedAsset || !canCheckpoint; - document.querySelector("#guided-transfer-form button").disabled = !selectedAsset || syncPending || !hasBalance; - document.querySelector("#guided-withdraw-form button").disabled = !selectedAsset || syncPending || !hasBalance; - - document.querySelector("#guided-session-create-form button").disabled = !document.getElementById("guided-app-select")?.value || !hasBalance; - document.querySelector("#guided-session-deposit-form button").disabled = !openSession; - document.querySelector("#guided-session-operate-form button").disabled = !openSession; - document.querySelector("#guided-session-close-form button").disabled = !openSession; - - setStepNote( - "guided-approve-form", - approvalStillRelevant() - ? `Latest approval tx ${UI.shortAddress(state.pendingApproval.txHash)} was submitted. If the next checkpoint fails on allowance, wait for confirmation and retry.` - : "Approve before the next deposit when you need fresh allowance.", - approvalStillRelevant(), - ); - setStepNote( - "guided-deposit-form", - syncPending - ? "Deposit is disabled until the pending home state is checkpointed and clearnode sync completes." - : "Deposit creates a new signed home state that must be checkpointed before transfer or withdraw.", - syncPending, - ); - setStepNote( - "guided-checkpoint-form", - checkpointStillRelevant() - ? "Checkpoint already submitted for this signed state. Wait for chain confirmation and clearnode sync." - : canCheckpoint - ? checkpointAllowanceHint() || "Checkpoint is the next protocol step for the current pending home deposit or withdrawal." - : overview.channel_guidance.sync_pending - ? "Checkpoint is unavailable here because the pending signed state is not a checkpointable home deposit or withdrawal." - : "No pending home deposit or withdrawal needs a checkpoint right now.", - checkpointStillRelevant() || Boolean(checkpointAllowanceHint()) || Boolean(overview.channel_guidance.sync_pending && !canCheckpoint), - ); - setStepNote( - "guided-transfer-form", - syncPending - ? "Transfer is disabled until the current home state is checkpointed and clearnode sync completes." - : !hasBalance - ? "Transfer needs a positive channel balance." - : "Transfer becomes available once the home channel is fully synced.", - syncPending || !hasBalance, - ); - setStepNote( - "guided-withdraw-form", - syncPending - ? "Withdraw is disabled until the current home state is checkpointed and clearnode sync completes." - : !hasBalance - ? "Withdraw needs a positive channel balance." - : "Withdraw creates a new signed state that must be checkpointed afterward.", - syncPending || !hasBalance, - ); - } - - async function refreshAll(preservedAsset) { - const asset = preservedAsset || state.selectedAsset; - const [overview, blockchains] = await Promise.all([ - UI.requestJSON(asset ? `/api/v1/demo/overview?asset=${encodeURIComponent(asset)}` : "/api/v1/demo/overview"), - UI.requestJSON("/api/v1/node/blockchains").catch(() => ({ blockchains: [] })), - UI.refreshAuthStatus(), - ]); - state.overview = overview; - state.blockchains = blockchains.blockchains || []; - state.selectedAsset = overview.selected_asset || state.selectedAsset; - reconcilePendingMutations(); - renderStatus(); - renderAssets(); - renderBalances(); - renderChannelSummary(); - renderLatestState(); - renderLatestActivity(); - renderSelectors(); - renderGuidance(); - updateActionState(); - } - - async function runWrite(formID, action) { - try { - if (!(await UI.ensureUnlocked())) { - setStepResult(formID, "Unlock write actions to continue.", false); - return; - } - const message = await action(); - setStepResult(formID, message, false); - await refreshAll(state.selectedAsset); - pushHistory(message); - } catch (err) { - setStepResult(formID, friendlyWriteError(formID, err), true); - } - } - - function bindEvents() { - document.getElementById("guided-refresh")?.addEventListener("click", () => { - void refreshAll(state.selectedAsset); - }); - - document.getElementById("guided-asset-select")?.addEventListener("change", (event) => { - state.selectedAsset = event.target.value; - void refreshAll(state.selectedAsset); - }); - - document.getElementById("guided-session-select")?.addEventListener("change", () => { - updateActionState(); - }); - - document.getElementById("guided-approve-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-approve-form", async () => { - const chainID = Number(document.getElementById("guided-chain-select")?.value); - const amount = String(formData.get("amount") || "").trim(); - const response = await UI.requestJSON("/api/v1/approve", { - method: "POST", - body: { blockchain_id: chainID, asset: state.selectedAsset, amount }, - }); - rememberApproval(state.selectedAsset, chainID, amount, response.tx_hash); - setStepResult( - "guided-checkpoint-form", - `Approval tx submitted: ${response.tx_hash}. Wait for chain confirmation if the next checkpoint fails on allowance.`, - false, - ); - return `Approval transaction submitted for ${amount} ${state.selectedAsset.toUpperCase()} on ${chainName(chainID)}: ${response.tx_hash}.`; - }); - }); - - document.getElementById("guided-deposit-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-deposit-form", async () => { - const chainID = Number(document.getElementById("guided-chain-select")?.value); - const amount = String(formData.get("amount") || "").trim(); - const response = await UI.requestJSON("/api/v1/deposit", { - method: "POST", - body: { blockchain_id: chainID, asset: state.selectedAsset, amount }, - }); - return response.ready_for_checkpoint - ? approvalStillRelevant() - ? `Deposited ${amount} ${state.selectedAsset.toUpperCase()} into the home channel. Checkpoint is the next protocol step, but the approval tx may still need on-chain confirmation.` - : `Deposited ${amount} ${state.selectedAsset.toUpperCase()} into the home channel. Checkpoint is ready next.` - : `Deposited ${amount} ${state.selectedAsset.toUpperCase()} into the home channel.`; - }); - }); - - document.getElementById("guided-checkpoint-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - void runWrite("guided-checkpoint-form", async () => { - const response = await UI.requestJSON("/api/v1/checkpoint", { - method: "POST", - body: { asset: state.selectedAsset }, - }); - clearPendingApproval(); - rememberCheckpoint(state.selectedAsset, state.overview?.latest_state?.version || 0, response.tx_hash); - return `Checkpoint submitted for ${state.selectedAsset.toUpperCase()}: ${response.tx_hash}. Waiting for clearnode sync.`; - }); - }); - - document.getElementById("guided-transfer-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-transfer-form", async () => { - const recipient = String(formData.get("recipient") || "").trim(); - const amount = String(formData.get("amount") || "").trim(); - await UI.requestJSON("/api/v1/transfer", { - method: "POST", - body: { recipient, asset: state.selectedAsset, amount }, - }); - return `Transferred ${amount} ${state.selectedAsset.toUpperCase()} to ${UI.shortAddress(recipient)}.`; - }); - }); - - document.getElementById("guided-withdraw-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-withdraw-form", async () => { - const chainID = Number(document.getElementById("guided-chain-select")?.value); - const amount = String(formData.get("amount") || "").trim(); - const response = await UI.requestJSON("/api/v1/withdraw", { - method: "POST", - body: { blockchain_id: chainID, asset: state.selectedAsset, amount }, - }); - return response.ready_for_checkpoint - ? `Prepared a ${amount} ${state.selectedAsset.toUpperCase()} withdrawal. Checkpoint it after review.` - : `Prepared a ${amount} ${state.selectedAsset.toUpperCase()} withdrawal.`; - }); - }); - - document.getElementById("guided-session-create-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-session-create-form", async () => { - const appID = document.getElementById("guided-app-select")?.value; - const amount = String(formData.get("amount") || "").trim(); - const response = await UI.requestJSON("/api/v1/sessions", { - method: "POST", - body: { - application_id: appID, - initial_allocations: [{ asset: state.selectedAsset, amount }], - session_data: "{}", - }, - }); - return `Created session ${response.session_id} with ${amount} ${state.selectedAsset.toUpperCase()}.`; - }); - }); - - document.getElementById("guided-session-deposit-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-session-deposit-form", async () => { - const sessionID = document.getElementById("guided-session-select")?.value; - const amount = String(formData.get("amount") || "").trim(); - const response = await UI.requestJSON(`/api/v1/sessions/${encodeURIComponent(sessionID)}/deposit`, { - method: "POST", - body: { asset: state.selectedAsset, amount }, - }); - return `Deposited ${amount} ${state.selectedAsset.toUpperCase()} into session ${response.session_id}.`; - }); - }); - - document.getElementById("guided-session-operate-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - const formData = new FormData(event.currentTarget); - void runWrite("guided-session-operate-form", async () => { - const sessionID = document.getElementById("guided-session-select")?.value; - const session = findSession(sessionID); - const turn = numberValue(formData.get("turn")); - if (!session) { - throw new Error("Select an open session first."); - } - const allocations = (session.allocations || []).map((allocation) => ({ - participant: allocation.participant, - asset: allocation.asset, - amount: allocation.amount, - })); - const response = await UI.requestJSON(`/api/v1/sessions/${encodeURIComponent(sessionID)}/state`, { - method: "POST", - body: { - allocations, - session_data: JSON.stringify({ turn }), - }, - }); - return `Session ${response.session_id} advanced to version ${response.version} with turn=${turn}.`; - }); - }); - - document.getElementById("guided-session-close-form")?.addEventListener("submit", (event) => { - event.preventDefault(); - void runWrite("guided-session-close-form", async () => { - const sessionID = document.getElementById("guided-session-select")?.value; - const response = await UI.requestJSON(`/api/v1/sessions/${encodeURIComponent(sessionID)}/close`, { - method: "POST", - body: {}, - }); - return `Closed session ${response.session_id}.`; - }); - }); - } - - async function init() { - UI.initUnlockModal(); - bindEvents(); - await refreshAll(""); - } - - document.addEventListener("DOMContentLoaded", () => { - void init(); - }); -})(window); diff --git a/web/index.html b/web/index.html deleted file mode 100644 index 1aea659..0000000 --- a/web/index.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - Nitrolite Go Example | App Session Micropayment Store - - - -
    - - -
    -
    -
    -

    Store session

    -

    One app session. Instant item access.

    -

    Every deposit, purchase, and withdrawal is expressed as an app-session update. The Go backend co-signs, validates catalog pricing, and gates purchased content.

    -
    -
    -
    - Selected asset - Loading… -

    One store session per asset. Switch assets to browse separate balances and purchases.

    -
    -
    - Session status - Checking session… -

    Create a store session first, then deposit and purchase content.

    -
    -
    -
    - -
    -
    - Available balance - Loading… -
    -
    - User allocation - Loading… -
    -
    - Store revenue - Loading… -
    -
    - Owned items - Loading… -
    -
    - -
    Loading store state…
    - -
    -
    -
    -
    -

    Store config

    -

    Browser store identity

    -
    -
    -
    -
    - -
    -
    -
    -

    Current session

    -

    App session position

    -
    -
    -
    -
    - -
    -
    -
    -

    Actions

    -

    Open, deposit, withdraw

    -
    -
    - - - -

    Waiting for input.

    -
    - -
    -
    -
    -

    Purchased content

    -

    Your library

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -

    Catalog

    -

    Books, magazines, and articles

    -
    -
    -
    -
    - -
    -
    -
    -

    Reader

    -

    Item access

    -
    -
    -
    -

    Purchase an item, then open it here from the catalog or your library.

    -
    -
    -
    - -
    -
    -
    -

    Transport view

    -

    Browser activity log

    -
    - -
    -
    No activity yet.
    -
    -
    - - - - - diff --git a/web/merchant.js b/web/merchant.js deleted file mode 100644 index cc64f53..0000000 --- a/web/merchant.js +++ /dev/null @@ -1,430 +0,0 @@ -(function merchantDashboard(global) { - const UI = global.NitroliteUI; - const state = { - health: null, - overview: null, - lease: null, - heartbeatTimer: null, - }; - - function currentAsset() { - return state.overview?.selected_asset || "yusd"; - } - - function demoAssets() { - if (!state.overview) { - return []; - } - const homeBlockchains = state.overview.wallet?.home_blockchains || {}; - return (state.overview.assets || []).filter((asset) => homeBlockchains[asset.symbol]); - } - - function leaseOwned() { - return Boolean(state.lease?.held && state.lease?.owned_by_current_session); - } - - function updateBanner(message, isError) { - const banner = document.getElementById("dashboard-banner"); - if (!banner) { - return; - } - banner.textContent = message; - banner.classList.toggle("warning", Boolean(isError)); - } - - async function fetchHealth() { - try { - state.health = await UI.requestJSON("/healthz"); - } catch (err) { - state.health = { status: "error", clearnode: "disconnected", signer: "", error: err.message }; - } - } - - async function refreshAll() { - await fetchHealth(); - try { - const [overview, lease] = await Promise.all([ - UI.requestJSON(`/api/v1/dashboard/overview?asset=${encodeURIComponent(currentAsset())}`), - UI.requestJSON("/api/v1/operator/lease/status"), - ]); - state.overview = overview; - state.lease = lease; - render(); - } catch (err) { - state.overview = null; - try { - state.lease = await UI.requestJSON("/api/v1/operator/lease/status"); - } catch (leaseErr) { - state.lease = null; - } - render(); - updateBanner(`Dashboard overview unavailable: ${err.message}. Health remains visible above.`, true); - return; - } - updateBanner("Merchant dashboard is live. Create a pay link, watch the order reserve, then settle, refund, or pay out.", false); - } - - function renderStatusCards() { - UI.setText("#dashboard-health", state.health?.clearnode === "connected" ? "Connected" : "Disconnected"); - UI.setText("#dashboard-signer", UI.shortAddress(state.overview?.wallet?.address || state.health?.signer || "Unavailable")); - UI.setText("#dashboard-available", `${state.overview?.summary?.available_balance || "0"} ${(currentAsset() || "").toUpperCase()}`); - UI.setText("#dashboard-reserved", `${state.overview?.summary?.reserved_balance || "0"} ${(currentAsset() || "").toUpperCase()}`); - } - - function renderLease() { - const text = document.getElementById("lease-status-text"); - const hint = document.getElementById("lease-status-hint"); - const acquire = document.getElementById("lease-acquire"); - const release = document.getElementById("lease-release"); - if (!text || !hint || !acquire || !release) { - return; - } - if (!state.lease?.held) { - text.textContent = UI.auth.unlocked ? "Available to acquire" : "Unlock writes first"; - hint.textContent = UI.auth.unlocked - ? "Acquire the operator lease to create pay links and queue merchant mutations." - : "The operator lease only matters after you unlock writes for this browser session."; - acquire.hidden = !UI.auth.unlocked; - release.hidden = true; - return; - } - if (leaseOwned()) { - text.textContent = `Held by this browser until ${UI.formatTime(state.lease.expires_at)}`; - hint.textContent = "The dashboard will heartbeat the lease while this tab stays active."; - acquire.hidden = true; - release.hidden = false; - } else { - text.textContent = `Held by another browser until ${UI.formatTime(state.lease.expires_at)}`; - hint.textContent = "This dashboard stays read-only until the active operator releases the lease or it expires."; - acquire.hidden = true; - release.hidden = true; - } - } - - function renderSummaries() { - UI.setText("#dashboard-balance-summary", ""); - const balanceRoot = document.getElementById("dashboard-balance-summary"); - const channelRoot = document.getElementById("dashboard-channel-summary"); - const stateRoot = document.getElementById("dashboard-state-summary"); - const workRoot = document.getElementById("dashboard-work-summary"); - if (!balanceRoot || !channelRoot || !stateRoot || !workRoot) { - return; - } - - if (!state.overview) { - balanceRoot.innerHTML = '

    Dashboard overview unavailable.

    '; - channelRoot.innerHTML = '

    Dashboard overview unavailable.

    '; - stateRoot.innerHTML = '

    Dashboard overview unavailable.

    '; - workRoot.innerHTML = '

    Dashboard overview unavailable.

    '; - return; - } - - balanceRoot.innerHTML = ` -
    Selected asset${state.overview.selected_asset.toUpperCase()}
    -
    Available${state.overview.summary.available_balance}
    -
    Reserved${state.overview.summary.reserved_balance}
    -
    Merchant${state.overview.merchant_name}
    - `; - - if (state.overview.channel) { - channelRoot.innerHTML = ` -
    Status${UI.titleCase(state.overview.channel.status)}
    -
    Version${state.overview.channel.stateVersion}
    -
    Asset${state.overview.channel.asset.toUpperCase()}
    -
    Chain${state.overview.channel.blockchainID}
    - `; - } else { - channelRoot.innerHTML = '

    No home channel returned for the selected asset.

    '; - } - - if (state.overview.latest_state) { - stateRoot.innerHTML = ` -
    Version${state.overview.latest_state.version}
    -
    Transition${UI.titleCase(state.overview.latest_state.transition.type)}
    -
    Amount${state.overview.latest_state.transition.amount}
    -
    Channel${UI.shortAddress(state.overview.latest_state.homeChannelID)}
    - `; - } else { - stateRoot.innerHTML = '

    No latest signed state available for the selected asset.

    '; - } - - workRoot.innerHTML = ` -
    Pending operations${state.overview.summary.pending_count}
    -
    Open orders${state.overview.summary.open_orders}
    -
    Lease${leaseOwned() ? "Owned here" : state.lease?.held ? "Held elsewhere" : "Not held"}
    -
    Latest activity${state.overview.latest_activity ? UI.titleCase(state.overview.latest_activity.type) : "Unavailable"}
    - `; - } - - function renderSelectors() { - const assets = demoAssets(); - UI.fillSelect(document.getElementById("payment-asset"), assets, (asset) => asset.symbol, (asset) => `${asset.symbol.toUpperCase()} • ${asset.name}`, currentAsset()); - UI.fillSelect(document.getElementById("payout-asset"), assets, (asset) => asset.symbol, (asset) => `${asset.symbol.toUpperCase()} • ${asset.name}`, currentAsset()); - } - - function renderPaymentRequests() { - const root = document.getElementById("payment-request-list"); - if (!root) { - return; - } - const items = state.overview?.payment_requests || []; - if (items.length === 0) { - root.innerHTML = '
    No hosted pay links yet.
    '; - return; - } - root.innerHTML = items.map((item) => ` -
    -
    - ${item.title} - ${UI.titleCase(item.status)} -
    - ${item.amount} ${item.asset.toUpperCase()} - Open hosted pay page -
    - `).join(""); - } - - function renderOrders() { - const root = document.getElementById("orders-list"); - if (!root) { - return; - } - const orders = state.overview?.orders || []; - if (orders.length === 0) { - root.innerHTML = '
    No orders have been captured yet.
    '; - return; - } - root.innerHTML = ` -
    - Order - Status - Amount - Action -
    - ${orders.map((order) => ` -
    -
    - ${order.title} -

    ${UI.shortAddress(order.order_id)}

    -
    - ${UI.titleCase(order.status)} - ${order.amount} ${order.asset.toUpperCase()} -
    - - -
    -
    - `).join("")} - `; - } - - function renderPayouts() { - const root = document.getElementById("payout-list"); - if (!root) { - return; - } - const payouts = state.overview?.payouts || []; - if (payouts.length === 0) { - root.innerHTML = '
    No payouts queued yet.
    '; - return; - } - root.innerHTML = payouts.map((payout) => ` -
    -
    - ${payout.amount} ${payout.asset.toUpperCase()} - ${UI.titleCase(payout.status)} -
    - Destination: ${UI.shortAddress(payout.destination_wallet)} -
    - `).join(""); - } - - function renderOperations() { - const root = document.getElementById("operations-list"); - if (!root) { - return; - } - const operations = state.overview?.operations || []; - if (operations.length === 0) { - root.innerHTML = '
    No operations queued yet.
    '; - return; - } - root.innerHTML = operations.map((operation) => ` -
    -
    - ${UI.titleCase(operation.type)} - ${UI.titleCase(operation.status)} -
    - Resource: ${UI.shortAddress(operation.resource_id)} - ${operation.error_message || `Queued at ${UI.formatTime(operation.queued_at)}`} -
    - `).join(""); - } - - function renderActivity() { - const root = document.getElementById("dashboard-activity-log"); - if (!root) { - return; - } - if (UI.activity.length === 0) { - root.textContent = "No activity yet."; - return; - } - root.textContent = UI.formatJSON(UI.activity); - } - - function updateControlState() { - const canMutate = UI.auth.unlocked && leaseOwned(); - document.querySelectorAll("#payment-request-form button[type='submit'], #payout-form button[type='submit']").forEach((node) => { - node.disabled = !canMutate; - }); - document.querySelectorAll(".order-action").forEach((node) => { - node.disabled = !canMutate || node.closest(".table-row")?.dataset.orderStatus !== "reserved"; - }); - } - - async function acquireLease() { - if (!(await UI.ensureUnlocked())) { - return; - } - await UI.requestJSON("/api/v1/operator/lease/acquire", { method: "POST", body: {} }); - await refreshAll(); - } - - async function releaseLease() { - await UI.requestJSON("/api/v1/operator/lease/release", { method: "POST", body: {} }); - await refreshAll(); - } - - async function heartbeat() { - if (!leaseOwned()) { - return; - } - try { - state.lease = await UI.requestJSON("/api/v1/operator/lease/heartbeat", { method: "POST", body: {} }); - renderLease(); - } catch (err) { - clearHeartbeat(); - await refreshAll(); - updateBanner(`Operator lease lost: ${err.message}`, true); - } - } - - function clearHeartbeat() { - if (state.heartbeatTimer) { - global.clearInterval(state.heartbeatTimer); - state.heartbeatTimer = null; - } - } - - function syncHeartbeat() { - clearHeartbeat(); - if (leaseOwned()) { - state.heartbeatTimer = global.setInterval(heartbeat, 30000); - } - } - - async function handlePaymentRequestSubmit(event) { - event.preventDefault(); - if (!(await UI.ensureUnlocked())) { - return; - } - if (!leaseOwned()) { - updateBanner("Acquire the operator lease before creating pay links.", true); - return; - } - const form = new FormData(event.currentTarget); - const response = await UI.requestJSON("/api/v1/payment-requests", { - method: "POST", - body: { - title: form.get("title"), - description: form.get("description"), - asset: form.get("asset"), - amount: form.get("amount"), - }, - }); - document.getElementById("payment-request-result").textContent = `Created pay link ${response.pay_url}`; - await refreshAll(); - } - - async function handlePayoutSubmit(event) { - event.preventDefault(); - if (!(await UI.ensureUnlocked())) { - return; - } - if (!leaseOwned()) { - updateBanner("Acquire the operator lease before queuing payouts.", true); - return; - } - const form = new FormData(event.currentTarget); - const response = await UI.requestJSON("/api/v1/payouts", { - method: "POST", - body: { - asset: form.get("asset"), - amount: form.get("amount"), - destination_wallet: form.get("destination_wallet"), - }, - }); - document.getElementById("payout-result").textContent = `Queued payout operation ${response.operation_id}`; - await refreshAll(); - } - - async function handleOrderAction(event) { - const button = event.target.closest(".order-action"); - if (!button) { - return; - } - if (!(await UI.ensureUnlocked())) { - return; - } - if (!leaseOwned()) { - updateBanner("Acquire the operator lease before settling or refunding orders.", true); - return; - } - const action = button.dataset.orderAction; - const orderID = button.dataset.orderId; - await UI.requestJSON(`/api/v1/orders/${orderID}/${action}`, { method: "POST", body: {} }); - await refreshAll(); - } - - function render() { - renderStatusCards(); - renderLease(); - renderSummaries(); - renderSelectors(); - renderPaymentRequests(); - renderOrders(); - renderPayouts(); - renderOperations(); - renderActivity(); - syncHeartbeat(); - updateControlState(); - } - - function bind() { - document.getElementById("dashboard-refresh")?.addEventListener("click", refreshAll); - document.getElementById("lease-acquire")?.addEventListener("click", acquireLease); - document.getElementById("lease-release")?.addEventListener("click", releaseLease); - document.getElementById("payment-request-form")?.addEventListener("submit", handlePaymentRequestSubmit); - document.getElementById("payout-form")?.addEventListener("submit", handlePayoutSubmit); - document.getElementById("orders-list")?.addEventListener("click", handleOrderAction); - - UI.onAuthChange(() => { - renderLease(); - updateControlState(); - if (!UI.auth.unlocked) { - clearHeartbeat(); - } - }); - UI.onActivity(renderActivity); - } - - async function boot() { - UI.initUnlockModal(); - bind(); - await UI.refreshAuthStatus(); - await refreshAll(); - } - - global.addEventListener("DOMContentLoaded", boot); -})(window); diff --git a/web/pay.html b/web/pay.html deleted file mode 100644 index 0fd6a98..0000000 --- a/web/pay.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - Nitrolite Go Example | Hosted Payment - - - -
    -
    -
    -

    Sandbox payment request

    -

    Loading payment request…

    -

    Hosted sandbox payment powered by the Go backend signer.

    -
    Loading request state…
    - -
    -
    - Amount due - Loading… -
    -
    - Asset - Loading… -
    -
    - Request status - Loading… -
    -
    - Order - Not created -
    -
    - -

    -

    No customer wallet is involved in this sandbox flow. Clicking pay triggers a backend capture simulation using the demo signer.

    - -
    - - Open operator dashboard -
    - -
    Waiting for input.
    -
    -
    - - - - - diff --git a/web/pay.js b/web/pay.js deleted file mode 100644 index d8bf36d..0000000 --- a/web/pay.js +++ /dev/null @@ -1,103 +0,0 @@ -(function payPage(global) { - const UI = global.NitroliteUI; - - function slugFromPath() { - const parts = global.location.pathname.split("/").filter(Boolean); - return parts.length >= 2 && parts[0] === "pay" ? parts[1] : ""; - } - - function paymentStatus(page) { - return page?.payment_request?.status || "unknown"; - } - - function orderStatus(page) { - return page?.order?.status || "not_created"; - } - - function renderBanner(page) { - const banner = document.getElementById("pay-status"); - if (!banner) { - return; - } - banner.classList.remove("warning"); - switch (paymentStatus(page)) { - case "pending": - banner.textContent = "This is a sandbox payment request. Clicking pay triggers a backend capture simulation; no customer wallet is required."; - break; - case "processing": - banner.textContent = "Payment already submitted. The backend is reserving the order funds and waiting for chain confirmation or clearnode sync."; - break; - case "completed": - banner.textContent = "Payment already captured. The operator dashboard can now settle or refund the reserved order."; - break; - case "expired": - banner.textContent = "This payment request has expired."; - banner.classList.add("warning"); - break; - case "failed": - banner.textContent = "The previous capture attempt failed. The operator needs to inspect the dashboard and retry if appropriate."; - banner.classList.add("warning"); - break; - default: - banner.textContent = `Request status: ${UI.titleCase(paymentStatus(page))}`; - break; - } - } - - function render(page) { - const request = page?.payment_request; - UI.setText("#pay-title", request?.title || "Payment request unavailable"); - UI.setText("#pay-merchant", page?.merchant_name ? `${page.merchant_name} hosted sandbox payment` : "Hosted sandbox payment powered by the Go backend signer."); - UI.setText("#pay-amount", request?.amount || "Unavailable"); - UI.setText("#pay-asset", (request?.asset || "Unavailable").toUpperCase()); - UI.setText("#pay-request-status", UI.titleCase(paymentStatus(page))); - UI.setText("#pay-order-status", UI.titleCase(orderStatus(page))); - UI.setText("#pay-description", request?.description || "This hosted page simulates a customer payment against the backend-owned signer."); - renderBanner(page); - - const payButton = document.getElementById("pay-submit"); - if (payButton) { - payButton.disabled = paymentStatus(page) !== "pending"; - payButton.textContent = paymentStatus(page) === "pending" ? "Pay now" : "Payment unavailable"; - } - } - - async function loadPage() { - const slug = slugFromPath(); - if (!slug) { - throw new Error("missing payment request slug"); - } - const page = await UI.requestJSON(`/api/v1/payment-requests/${encodeURIComponent(slug)}`); - render(page); - return page; - } - - async function submitPayment() { - const slug = slugFromPath(); - const result = await UI.requestJSON(`/api/v1/payment-requests/${encodeURIComponent(slug)}/pay`, { - method: "POST", - body: {}, - }); - document.getElementById("pay-result").textContent = UI.formatJSON(result); - await loadPage(); - } - - async function boot() { - document.getElementById("pay-submit")?.addEventListener("click", async () => { - try { - await submitPayment(); - } catch (err) { - document.getElementById("pay-result").textContent = UI.formatJSON(err.payload || { error: err.message }); - } - }); - - try { - await loadPage(); - } catch (err) { - document.getElementById("pay-result").textContent = UI.formatJSON(err.payload || { error: err.message }); - render({ payment_request: { status: "failed" } }); - } - } - - global.addEventListener("DOMContentLoaded", boot); -})(window); diff --git a/web/reference.html b/web/reference.html deleted file mode 100644 index a92646c..0000000 --- a/web/reference.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - Nitrolite Go Example | API Reference - - - - -
    - - -
    -
    -
    -
    -

    Developer view

    -

    Interactive reference

    -
    -
    -

    Reads are public. Write endpoints can be tried directly from this page after you unlock sandbox mutations for the current browser session.

    -
    Checking unlock status…
    -
    - -
    - -
    -
    - - - - - - - diff --git a/web/reference.js b/web/reference.js deleted file mode 100644 index 503947c..0000000 --- a/web/reference.js +++ /dev/null @@ -1,12 +0,0 @@ -(function referencePage(global) { - const UI = global.NitroliteUI; - - async function init() { - UI.initUnlockModal(); - await UI.refreshAuthStatus(); - } - - document.addEventListener("DOMContentLoaded", () => { - void init(); - }); -})(window); diff --git a/web/store.js b/web/store.js deleted file mode 100644 index 3e257b7..0000000 --- a/web/store.js +++ /dev/null @@ -1,345 +0,0 @@ -(function storeApp(global) { - const UI = global.NitroliteUI; - const state = { - config: null, - asset: "", - session: null, - catalog: [], - }; - - function formatAmount(value, asset) { - const amount = value || "0"; - return `${amount} ${String(asset || "").toUpperCase()}`.trim(); - } - - function setBanner(message) { - const node = document.getElementById("store-banner"); - if (node) { - node.textContent = message; - } - } - - function selectedAsset() { - return state.asset || state.config?.store?.default_asset || "yusd"; - } - - async function loadConfig() { - const payload = await UI.requestJSON("/api/v1/store/config"); - state.config = payload; - const assets = payload.store?.supported_assets || []; - const select = document.getElementById("store-asset-select"); - if (select) { - select.innerHTML = ""; - assets.forEach((asset) => { - const option = document.createElement("option"); - option.value = asset; - option.textContent = String(asset).toUpperCase(); - select.appendChild(option); - }); - state.asset = state.asset || payload.store?.default_asset || assets[0] || "yusd"; - select.value = state.asset; - } - - UI.setText("#selected-asset-text", String(selectedAsset()).toUpperCase()); - renderConfigSummary(); - } - - async function loadSession() { - const asset = selectedAsset(); - const summary = await UI.requestJSON(`/api/v1/store/session?asset=${encodeURIComponent(asset)}`); - state.session = summary.session || null; - renderSession(); - return state.session; - } - - async function loadCatalog() { - const asset = selectedAsset(); - const payload = await UI.requestJSON(`/api/v1/catalog?asset=${encodeURIComponent(asset)}`); - state.catalog = payload.items || []; - renderCatalog(state.catalog); - } - - async function refresh() { - await loadConfig(); - await Promise.all([loadSession(), loadCatalog()]); - } - - function renderConfigSummary() { - const container = document.getElementById("store-config-summary"); - if (!container || !state.config?.store) { - return; - } - const store = state.config.store; - container.innerHTML = ` -
    Store${store.store_name}
    -
    App ID${store.app_id}
    -
    User signer${UI.shortAddress(store.user_signer)}
    -
    App signer${UI.shortAddress(store.app_signer)}
    - `; - } - - function renderSession() { - const session = state.session || {}; - const asset = selectedAsset(); - UI.setText("#store-available-balance", formatAmount(session.available_balance, asset)); - UI.setText("#store-user-balance", formatAmount(session.user_allocation, asset)); - UI.setText("#store-app-balance", formatAmount(session.app_allocation, asset)); - UI.setText("#store-purchase-count", String((session.purchases || []).length)); - UI.setText("#selected-asset-text", String(asset).toUpperCase()); - - const status = session.status || "missing"; - UI.setText("#store-status-text", UI.titleCase(status)); - UI.setText( - "#store-status-hint", - status === "missing" - ? "Create a store session for this asset before you deposit or purchase." - : `Session ${UI.shortAddress(session.app_session_id || "")} is ready for deposit, purchase, and withdrawal.`, - ); - - const summary = document.getElementById("store-session-summary"); - if (summary) { - summary.innerHTML = ` -
    Session${session.app_session_id ? UI.shortAddress(session.app_session_id) : "Not created"}
    -
    Status${UI.titleCase(status)}
    -
    Version${session.version ?? 0}
    -
    Latest session data${session.session_data || "Unavailable"}
    - `; - } - - const library = document.getElementById("store-library-list"); - if (library) { - const purchases = session.purchases || []; - if (!purchases.length) { - library.innerHTML = `

    No purchased content yet for ${String(asset).toUpperCase()}.

    `; - } else { - library.innerHTML = purchases - .map((purchase) => { - const item = state.catalog.find((entry) => entry.id === purchase.item_id); - const title = item?.title || purchase.item_id || "Purchased item"; - const version = purchase.version ?? "Unavailable"; - const itemID = purchase.item_id || ""; - return ` -
    -
    - ${title} -

    Purchased at version ${version}

    -
    - -
    - `; - }) - .join(""); - } - } - - setBanner( - status === "missing" - ? "No store session exists for this asset yet. Create one, then deposit balance from the current channel." - : `Store session ${UI.shortAddress(session.app_session_id || "")} is open. Deposit, purchase items, or withdraw remaining balance.`, - ); - } - - function renderCatalog(items) { - const container = document.getElementById("store-catalog-list"); - if (!container) { - return; - } - - if (!items.length) { - container.innerHTML = `

    No catalog items available for ${String(selectedAsset()).toUpperCase()}.

    `; - return; - } - - container.innerHTML = items - .map((item) => { - const price = item.prices?.[selectedAsset()] || "0"; - return ` -
    -

    ${UI.titleCase(item.type)}

    -

    ${item.title}

    -

    ${item.description}

    -

    ${formatAmount(price, selectedAsset())}

    -
    - - -
    -
    - `; - }) - .join(""); - } - - async function createOrLoadSession() { - const payload = await UI.requestJSON("/api/v1/store/session/create", { - method: "POST", - body: { asset: selectedAsset() }, - }); - state.session = payload.session; - UI.setText("#store-action-result", `Session ready for ${String(selectedAsset()).toUpperCase()}.`); - renderSession(); - } - - async function submitAction(action, extras = {}) { - const payload = await UI.requestJSON("/api/v1/app-session/submit-state", { - method: "POST", - body: { - session_id: state.session?.app_session_id || "", - asset: selectedAsset(), - session_data: JSON.stringify({ - action, - ...extras, - }), - }, - }); - state.session = payload.session; - renderSession(); - return payload.session; - } - - async function readContent(itemID) { - const payload = await UI.requestJSON(`/api/v1/content/${encodeURIComponent(itemID)}?asset=${encodeURIComponent(selectedAsset())}`); - const item = payload.item; - const reader = document.getElementById("store-reader"); - if (reader) { - reader.innerHTML = ` -
    -

    ${UI.titleCase(item.type)}

    -

    ${item.title}

    -

    ${item.description}

    -
    ${item.content}
    -
    - `; - } - } - - function bindForms() { - const select = document.getElementById("store-asset-select"); - if (select) { - select.addEventListener("change", async (event) => { - state.asset = event.target.value; - await Promise.all([loadSession(), loadCatalog()]); - }); - } - - const createForm = document.getElementById("store-create-form"); - if (createForm) { - createForm.addEventListener("submit", async (event) => { - event.preventDefault(); - try { - await createOrLoadSession(); - } catch (error) { - UI.setText("#store-action-result", error.message || "Failed to create session."); - } - }); - } - - const depositForm = document.getElementById("store-deposit-form"); - if (depositForm) { - depositForm.addEventListener("submit", async (event) => { - event.preventDefault(); - const amount = new FormData(depositForm).get("amount"); - try { - await submitAction("deposit", { amount }); - UI.setText("#store-action-result", `Deposited ${amount} ${String(selectedAsset()).toUpperCase()} into the store session.`); - } catch (error) { - UI.setText("#store-action-result", error.message || "Deposit failed."); - } - }); - } - - const withdrawForm = document.getElementById("store-withdraw-form"); - if (withdrawForm) { - withdrawForm.addEventListener("submit", async (event) => { - event.preventDefault(); - const amount = new FormData(withdrawForm).get("amount"); - try { - await submitAction("user_withdraw", { amount }); - UI.setText("#store-action-result", `Withdrew ${amount} ${String(selectedAsset()).toUpperCase()} from the store session.`); - } catch (error) { - UI.setText("#store-action-result", error.message || "Withdraw failed."); - } - }); - } - - const refreshButton = document.getElementById("store-refresh"); - if (refreshButton) { - refreshButton.addEventListener("click", async () => { - await refresh(); - }); - } - - document.addEventListener("click", async (event) => { - const buyButton = event.target.closest("[data-buy-item]"); - if (buyButton) { - const itemID = buyButton.getAttribute("data-buy-item"); - const price = buyButton.getAttribute("data-price"); - try { - await submitAction("purchase", { item_id: itemID, price }); - UI.setText("#store-action-result", `Purchased ${itemID}. Access is now unlocked in the reader.`); - } catch (error) { - UI.setText("#store-action-result", error.message || "Purchase failed."); - } - return; - } - - const readButton = event.target.closest("[data-read-item]"); - if (readButton) { - const itemID = readButton.getAttribute("data-read-item"); - try { - await readContent(itemID); - } catch (error) { - const reader = document.getElementById("store-reader"); - if (reader) { - reader.innerHTML = `

    ${error.message || "Unable to open content."}

    `; - } - } - } - }); - } - - function initActivityLog() { - const log = document.getElementById("store-activity-log"); - if (!log) { - return; - } - UI.onActivity((entry, entries) => { - log.textContent = JSON.stringify(entries, null, 2); - }); - } - - function bindCopyLog() { - const button = document.getElementById("store-copy-log"); - const log = document.getElementById("store-activity-log"); - if (!button || !log) { - return; - } - button.addEventListener("click", async () => { - const originalLabel = button.textContent; - try { - await navigator.clipboard.writeText(log.textContent || ""); - button.textContent = "Copied"; - } catch (error) { - button.textContent = "Copy failed"; - } - global.setTimeout(() => { - button.textContent = originalLabel; - }, 1600); - }); - } - - async function init() { - UI.initUnlockModal(); - await UI.refreshAuthStatus(); - bindForms(); - initActivityLog(); - bindCopyLog(); - await refresh(); - } - - global.addEventListener("DOMContentLoaded", () => { - init().catch((error) => { - setBanner(error.message || "Failed to initialize store."); - UI.setText("#store-action-result", error.message || "Initialization failed."); - }); - }); -})(window); diff --git a/web/style.css b/web/style.css deleted file mode 100644 index 294f0cd..0000000 --- a/web/style.css +++ /dev/null @@ -1,796 +0,0 @@ -:root { - --bg: #f5efe3; - --bg-strong: #ece3d1; - --panel: rgba(255, 250, 241, 0.9); - --panel-border: rgba(30, 49, 42, 0.12); - --text: #1f1a17; - --muted: #645a52; - --accent: #0d6b57; - --accent-strong: #084f41; - --accent-soft: rgba(13, 107, 87, 0.12); - --danger: #8b2e1d; - --danger-soft: rgba(139, 46, 29, 0.1); - --warning: #8a5a00; - --shadow: 0 20px 60px rgba(54, 38, 22, 0.12); - --radius-lg: 28px; - --radius-md: 18px; - --radius-sm: 12px; -} - -* { - box-sizing: border-box; -} - -html { - color-scheme: light; -} - -body { - margin: 0; - min-height: 100vh; - color: var(--text); - font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif; - background: - radial-gradient(circle at top left, rgba(13, 107, 87, 0.08), transparent 32%), - radial-gradient(circle at top right, rgba(219, 138, 76, 0.08), transparent 24%), - linear-gradient(180deg, #faf5eb 0%, var(--bg) 100%); -} - -.backdrop { - position: fixed; - inset: 0; - pointer-events: none; - background: - radial-gradient(circle at 15% 15%, rgba(16, 92, 74, 0.06), transparent 18%), - radial-gradient(circle at 85% 0%, rgba(210, 126, 61, 0.08), transparent 20%); -} - -a { - color: inherit; -} - -button, -input, -select, -textarea { - font: inherit; -} - -pre, -code { - font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, "Liberation Mono", monospace; -} - -.page-shell { - position: relative; - z-index: 1; - max-width: 1320px; - margin: 0 auto; - padding: 0 24px 48px; -} - -.site-header { - position: relative; - z-index: 1; - max-width: 1320px; - margin: 0 auto; - padding: 28px 24px 12px; - display: grid; - gap: 16px; -} - -.site-header h1, -.hero h2, -.section-header h2, -.metric-card strong, -.step-card h3 { - margin: 0; -} - -.eyebrow { - margin: 0 0 8px; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - text-transform: uppercase; - letter-spacing: 0.18em; - font-size: 0.78rem; - color: var(--accent-strong); -} - -.lede, -.muted, -.hint { - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.lede { - max-width: 72ch; - line-height: 1.6; - color: var(--muted); -} - -.site-nav { - display: flex; - flex-wrap: wrap; - gap: 10px; -} - -.nav-link { - padding: 10px 16px; - border-radius: 999px; - text-decoration: none; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - border: 1px solid transparent; - color: var(--muted); -} - -.nav-link.active { - color: #fff; - background: linear-gradient(135deg, var(--accent), var(--accent-strong)); - box-shadow: 0 10px 26px rgba(13, 107, 87, 0.18); -} - -.nav-link:not(.active):hover { - border-color: var(--panel-border); - background: rgba(255, 255, 255, 0.5); -} - -.site-actions { - display: flex; - flex-wrap: wrap; - gap: 12px; - align-items: center; -} - -.primary-button, -.ghost-button, -.danger-button, -.secondary-link { - border: 0; - border-radius: 999px; - padding: 12px 18px; - cursor: pointer; - text-decoration: none; - transition: transform 120ms ease, box-shadow 120ms ease, opacity 120ms ease; -} - -.primary-button { - color: #fff; - background: linear-gradient(135deg, var(--accent), var(--accent-strong)); - box-shadow: 0 12px 28px rgba(13, 107, 87, 0.2); -} - -.ghost-button, -.secondary-link { - color: var(--accent-strong); - background: rgba(255, 255, 255, 0.55); - border: 1px solid var(--panel-border); -} - -.danger-button { - color: #fff; - background: linear-gradient(135deg, #b04b32, var(--danger)); -} - -.primary-button:hover, -.ghost-button:hover, -.danger-button:hover, -.secondary-link:hover { - transform: translateY(-1px); -} - -.primary-button:disabled, -.ghost-button:disabled, -.danger-button:disabled { - cursor: not-allowed; - opacity: 0.45; - transform: none; - box-shadow: none; -} - -.panel { - background: var(--panel); - border: 1px solid var(--panel-border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow); - padding: 24px; - backdrop-filter: blur(14px); -} - -.hero { - display: grid; - gap: 24px; - grid-template-columns: 1.7fr 1fr; - margin-bottom: 20px; -} - -.hero-status { - display: grid; - gap: 16px; -} - -.hero-callout { - padding: 18px; - border-radius: var(--radius-md); - background: linear-gradient(180deg, rgba(13, 107, 87, 0.08), rgba(13, 107, 87, 0.03)); -} - -.hero-callout strong, -.metric-card strong { - font-size: 1.1rem; -} - -.hero-links { - display: flex; - flex-wrap: wrap; - gap: 10px; -} - -.metrics-grid, -.overview-grid, -.step-grid { - display: grid; - gap: 18px; -} - -.metrics-grid { - grid-template-columns: repeat(4, minmax(0, 1fr)); - margin-bottom: 20px; -} - -.metric-card { - padding: 18px; - border-radius: var(--radius-md); - background: rgba(255, 255, 255, 0.55); - border: 1px solid var(--panel-border); -} - -.label { - display: block; - margin-bottom: 8px; - color: var(--muted); - font-size: 0.85rem; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - text-transform: uppercase; - letter-spacing: 0.08em; -} - -.section-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 12px; - margin-bottom: 18px; -} - -.section-header h2 { - font-size: clamp(1.5rem, 2.1vw, 2rem); -} - -.asset-card-grid { - display: grid; - gap: 16px; - grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); -} - -.scope-grid { - display: grid; - gap: 24px; - grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr); -} - -.scope-column { - display: grid; - gap: 14px; -} - -.scope-title { - margin: 0; - font-size: 1rem; - color: var(--accent-strong); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - text-transform: uppercase; - letter-spacing: 0.08em; -} - -.asset-card { - padding: 18px; - border-radius: var(--radius-md); - border: 1px solid var(--panel-border); - background: rgba(255, 255, 255, 0.62); -} - -.asset-card.selected, -.stack-item.selected { - border-color: rgba(13, 107, 87, 0.28); - background: linear-gradient(180deg, rgba(13, 107, 87, 0.12), rgba(255, 255, 255, 0.72)); -} - -.asset-card-header { - display: flex; - justify-content: space-between; - gap: 12px; - align-items: flex-start; -} - -.chip { - display: inline-flex; - align-items: center; - border-radius: 999px; - padding: 6px 10px; - background: var(--accent-soft); - color: var(--accent-strong); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - font-size: 0.8rem; -} - -.detail-list, -.history-list { - margin: 0; - padding-left: 18px; - color: var(--muted); -} - -.overview-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - margin: 20px 0; -} - -.stack-list { - display: grid; - gap: 12px; -} - -.dashboard-grid { - display: grid; - gap: 18px; - grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); - margin: 20px 0; -} - -.stack-item, -.summary-line, -.flow-banner { - border-radius: var(--radius-md); - border: 1px solid var(--panel-border); - background: rgba(255, 255, 255, 0.58); -} - -.stack-item { - display: grid; - gap: 8px; - padding: 14px 16px; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.stack-item-row { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 12px; -} - -.compact-header { - margin-top: 18px; -} - -.summary-stack { - display: grid; - gap: 12px; -} - -.summary-line { - display: flex; - justify-content: space-between; - gap: 12px; - padding: 14px 16px; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.summary-line span { - color: var(--muted); -} - -.summary-row { - display: flex; - justify-content: space-between; - gap: 12px; - align-items: flex-start; - padding: 14px 16px; - border-radius: var(--radius-md); - border: 1px solid var(--panel-border); - background: rgba(255, 255, 255, 0.58); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.summary-row strong { - text-align: right; -} - -.hint { - margin: 0; - line-height: 1.6; - color: var(--muted); -} - -.hint.warning, -.flow-banner.warning { - color: var(--warning); - background: rgba(253, 235, 193, 0.7); - border-color: rgba(138, 90, 0, 0.22); -} - -.flow-toolbar { - display: flex; - flex-wrap: wrap; - gap: 14px; - margin-bottom: 16px; -} - -.field { - display: grid; - gap: 8px; - min-width: min(100%, 240px); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.field span { - color: var(--muted); - font-size: 0.92rem; -} - -.field input, -.field select, -.field textarea { - width: 100%; - padding: 12px 14px; - border-radius: var(--radius-sm); - border: 1px solid rgba(46, 52, 49, 0.15); - background: rgba(255, 255, 255, 0.82); - color: var(--text); -} - -.field textarea { - min-height: 110px; - resize: vertical; -} - -.flow-banner { - padding: 14px 16px; - margin-bottom: 18px; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.table-shell { - display: grid; - gap: 10px; -} - -.table-head, -.table-row { - display: grid; - grid-template-columns: minmax(0, 1.6fr) minmax(120px, 0.7fr) minmax(120px, 0.7fr) minmax(190px, 0.9fr); - gap: 14px; - align-items: center; - padding: 14px 16px; - border-radius: var(--radius-md); - border: 1px solid var(--panel-border); - background: rgba(255, 255, 255, 0.58); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.table-head { - color: var(--muted); - text-transform: uppercase; - letter-spacing: 0.08em; - font-size: 0.78rem; -} - -.table-row p { - margin: 4px 0 0; -} - -.table-actions { - display: flex; - flex-wrap: wrap; - gap: 10px; - justify-content: flex-end; -} - -.catalog-grid { - display: grid; - gap: 16px; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); -} - -.catalog-card, -.reader-shell { - border-radius: var(--radius-md); - border: 1px solid var(--panel-border); - background: rgba(255, 255, 255, 0.58); -} - -.catalog-card { - display: grid; - gap: 12px; - padding: 18px; -} - -.catalog-card h3, -.reader-content h3 { - margin: 0; -} - -.catalog-card .eyebrow, -.reader-content .eyebrow { - margin-bottom: 0; -} - -.catalog-actions { - display: flex; - flex-wrap: wrap; - gap: 10px; -} - -.price-tag { - margin: 0; - font-size: 1.05rem; - color: var(--accent-strong); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.reader-shell { - min-height: 320px; - padding: 18px; -} - -.reader-content { - display: grid; - gap: 12px; -} - -.reader-content pre { - margin-top: 6px; - max-height: 520px; -} - -.inline-link { - color: var(--accent-strong); - text-decoration-thickness: 1px; - text-underline-offset: 0.15em; -} - -.pay-shell { - position: relative; - z-index: 1; - min-height: 100vh; - display: grid; - place-items: center; - padding: 32px 16px; -} - -.pay-panel { - width: min(960px, 100%); -} - -.page-pay .overview-grid { - margin: 24px 0; -} - -.step-grid { - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); -} - -.step-card { - position: relative; - padding: 20px; - border-radius: var(--radius-md); - border: 1px solid var(--panel-border); - background: rgba(255, 255, 255, 0.58); - display: grid; - gap: 12px; - align-content: start; -} - -.step-index { - display: inline-flex; - align-items: center; - justify-content: center; - width: 34px; - height: 34px; - border-radius: 999px; - color: #fff; - background: linear-gradient(135deg, var(--accent), var(--accent-strong)); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - font-size: 0.92rem; -} - -.step-result, -pre { - margin: 0; - padding: 14px; - border-radius: var(--radius-sm); - background: #1b1816; - color: #eef3ef; - overflow: auto; - line-height: 1.55; -} - -.step-note { - margin: -2px 0 0; - min-height: 2.8em; - color: var(--muted); - line-height: 1.45; - font-size: 0.92rem; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.step-note.warning { - color: var(--warning); -} - -.step-card > .primary-button, -.step-card > .ghost-button, -.step-card > .danger-button, -.step-card > .secondary-link { - justify-self: start; - align-self: start; - width: auto; - max-width: 100%; -} - -.step-card pre, -.step-card .step-result { - max-height: 260px; -} - -.page-advanced .overview-grid { - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); -} - -.page-advanced .step-grid { - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - align-items: start; -} - -.danger-card { - border-color: rgba(139, 46, 29, 0.22); - background: linear-gradient(180deg, rgba(139, 46, 29, 0.06), rgba(255, 255, 255, 0.64)); -} - -.checkbox-row { - display: inline-flex; - gap: 10px; - align-items: center; - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; - color: var(--muted); -} - -.history-list { - display: grid; - gap: 10px; - padding-left: 0; - list-style: none; -} - -.history-list li { - display: flex; - flex-direction: column; - gap: 4px; - padding: 12px 14px; - border-radius: var(--radius-sm); - background: rgba(255, 255, 255, 0.55); - border: 1px solid var(--panel-border); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.reference-shell { - padding: 0; - overflow: hidden; -} - -rapi-doc { - width: 100%; - min-height: 78vh; - --bg: #fffefb; - --fg: #1f1a17; - --primary-color: #0d6b57; - --primary-color-invert: #ffffff; - --nav-bg-color: #f9f3e6; - --nav-text-color: #3b322c; - --nav-hover-bg-color: #efe4cd; -} - -.modal { - position: fixed; - inset: 0; - z-index: 10; - display: grid; - place-items: center; - padding: 24px; - background: rgba(24, 19, 15, 0.38); -} - -.modal[hidden] { - display: none !important; -} - -.modal-card { - width: min(100%, 480px); - padding: 24px; - border-radius: var(--radius-lg); - background: #fffaf0; - border: 1px solid rgba(31, 26, 23, 0.12); - box-shadow: 0 28px 80px rgba(21, 16, 14, 0.24); -} - -.modal-form { - display: grid; - gap: 16px; -} - -.modal-actions { - display: flex; - justify-content: flex-end; - gap: 12px; -} - -.error-text { - color: var(--danger); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -.empty-state { - padding: 18px; - border-radius: var(--radius-md); - background: rgba(255, 255, 255, 0.55); - border: 1px dashed var(--panel-border); - color: var(--muted); - font-family: "IBM Plex Sans", "Segoe UI", sans-serif; -} - -@media (max-width: 980px) { - .hero, - .overview-grid, - .metrics-grid, - .scope-grid, - .dashboard-grid { - grid-template-columns: 1fr; - } - - .table-head, - .table-row { - grid-template-columns: 1fr; - } - - .table-actions { - justify-content: flex-start; - } -} - -@media (max-width: 720px) { - .site-header, - .page-shell { - padding-left: 16px; - padding-right: 16px; - } - - .panel { - padding: 18px; - } - - .site-actions, - .flow-toolbar, - .hero-links, - .modal-actions { - flex-direction: column; - align-items: stretch; - } - - .primary-button, - .ghost-button, - .danger-button, - .secondary-link { - width: 100%; - text-align: center; - } -}