From 2038f75184a30cc8c43a10780cf15430134652ae Mon Sep 17 00:00:00 2001 From: azzahamdani Date: Mon, 9 Mar 2026 15:11:44 +0100 Subject: [PATCH 1/9] Add deploy worker workflow (#28) * chore: add the workers deploy workflow + wrangler.toml file * delete wranger.jsonc to avoid pipeline conflict --- .github/workflows/deploy.yml | 44 ++++++++++++++++++++++++++++++++++++ wrangler.jsonc | 9 -------- wrangler.toml | 32 ++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/deploy.yml delete mode 100644 wrangler.jsonc create mode 100644 wrangler.toml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..056159b --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,44 @@ +name: Deploy to Cloudflare Workers + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened, closed] + workflow_dispatch: + +jobs: + deploy-production: + if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + uses: lifinance/github-actions/.github/workflows/cloudflare-worker-deploy.yaml@main + with: + environment: production + build-command: "bun run build" + node-version: "20" + secrets: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + deploy-preview: + if: github.event_name == 'pull_request' && github.event.action != 'closed' + uses: lifinance/github-actions/.github/workflows/cloudflare-worker-deploy.yaml@main + with: + environment: preview + build-command: "bun run build" + node-version: "20" + preview-name: lintent-pr-${{ github.event.pull_request.number }} + secrets: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + cleanup-preview: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + uses: lifinance/github-actions/.github/workflows/cloudflare-worker-deploy.yaml@main + with: + delete-preview: true + preview-name: lintent-pr-${{ github.event.pull_request.number }} + node-version: "20" + secrets: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} diff --git a/wrangler.jsonc b/wrangler.jsonc deleted file mode 100644 index e787b50..0000000 --- a/wrangler.jsonc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "intent", - "main": ".svelte-kit/cloudflare/_worker.js", - "compatibility_date": "2025-01-01", - "assets": { - "binding": "ASSETS", - "directory": ".svelte-kit/cloudflare" - } -} diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..73bbe8e --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,32 @@ +name = "lintent-worker" +main = ".svelte-kit/cloudflare/_worker.js" +compatibility_date = "2024-03-06" +compatibility_flags = ["nodejs_compat"] + +# account_id is NOT set here — passed via CLOUDFLARE_ACCOUNT_ID in CI + +[assets] +binding = "ASSETS" +directory = ".svelte-kit/cloudflare" + +[build] +command = "bun run build" + +[env.production] +name = "lintent-worker" +vars = { ENVIRONMENT = "production" } + +[observability] +enabled = true +head_sampling_rate = 1 + +[observability.logs] +enabled = true +invocation_logs = true + +[tags] +lifi = "true" +lintent = "true" + +[placement] +mode = "smart" From f3103de257b55f6a86b8c8d50f9f520a59e6724c Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 9 Mar 2026 18:22:51 +0400 Subject: [PATCH 2/9] Fix view on mobile and enhance uuid generation --- src/lib/components/ui/FlowProgressList.svelte | 42 +++++++-- src/lib/config.ts | 18 +++- src/lib/libraries/intentFactory.ts | 50 +++++++++- src/lib/screens/FillIntent.svelte | 92 +++++++++++++++---- src/lib/screens/ReceiveMessage.svelte | 17 +--- src/lib/state.svelte.ts | 13 ++- src/routes/+page.svelte | 12 ++- 7 files changed, 192 insertions(+), 52 deletions(-) diff --git a/src/lib/components/ui/FlowProgressList.svelte b/src/lib/components/ui/FlowProgressList.svelte index 6d9f76a..773f022 100644 --- a/src/lib/components/ui/FlowProgressList.svelte +++ b/src/lib/components/ui/FlowProgressList.svelte @@ -46,17 +46,24 @@ }; -
-
+
+
-
+
{#each steps as step, i (step.id)}
+ + diff --git a/src/lib/config.ts b/src/lib/config.ts index d9bb9b0..e4dd34f 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -10,7 +10,8 @@ import { polygon, bsc, katana, - megaeth + megaeth, + optimism } from "viem/chains"; export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" as const; @@ -55,6 +56,7 @@ export const chainMap = { ethereum, base, arbitrum, + optimism, sepolia, arbitrumSepolia, optimismSepolia, @@ -139,6 +141,12 @@ export const coinList = (mainnet: boolean) => { chainId: base.id, decimals: 18 }, + { + address: `0x4200000000000000000000000000000000000006`, + name: "weth", + chainId: optimism.id, + decimals: 18 + }, { address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`, name: "weth", @@ -305,6 +313,7 @@ export const polymerChainIds = { arbitrumSepolia: arbitrumSepolia.id, baseSepolia: baseSepolia.id, optimismSepolia: optimismSepolia.id, + optimism: optimism.id, megaeth: megaeth.id, katana: katana.id, bsc: bsc.id, @@ -418,6 +427,13 @@ export const clients = { ...base.rpcUrls.default.http.map((v) => http(v)) ]) }), + optimism: createPublicClient({ + chain: optimism, + transport: fallback([ + http("https://optimism-rpc.publicnode.com"), + ...optimism.rpcUrls.default.http.map((v) => http(v)) + ]) + }), bsc: createPublicClient({ chain: bsc, transport: fallback([ diff --git a/src/lib/libraries/intentFactory.ts b/src/lib/libraries/intentFactory.ts index 5b1b7a1..68ef7cf 100644 --- a/src/lib/libraries/intentFactory.ts +++ b/src/lib/libraries/intentFactory.ts @@ -6,7 +6,7 @@ import { MULTICHAIN_INPUT_SETTLER_ESCROW, type WC } from "$lib/config"; -import { maxUint256 } from "viem"; +import { encodePacked, maxUint256 } from "viem"; import type { CreateIntentOptions, TokenContext, @@ -24,6 +24,36 @@ import { store } from "$lib/state.svelte"; import { depositAndRegisterCompact, openEscrowIntent, signIntentCompact } from "./intentExecution"; import { intentDeps } from "./coreDeps"; +const SAME_CHAIN_DURATION_SECONDS = 10 * 60; // 10 minutes +const SAME_CHAIN_EXCLUSIVITY_SECONDS = 12 * 3; // 36 seconds + +function applySameChainTimings(intent: Intent): void { + if (!intent.isSameChain()) return; + (intent as any).expiry = SAME_CHAIN_DURATION_SECONDS; + (intent as any).fillDeadline = SAME_CHAIN_DURATION_SECONDS; +} + +function applyExclusivityOverride( + orderIntent: ReturnType, + exclusiveFor: string | undefined, + isSameChain: boolean +): void { + if (!isSameChain || !exclusiveFor) return; + const order = orderIntent.asOrder() as StandardOrder; + const currentTime = Math.floor(Date.now() / 1000); + const paddedExclusiveFor = + `0x${exclusiveFor.replace("0x", "").padStart(64, "0")}` as `0x${string}`; + const newContext = encodePacked( + ["bytes1", "bytes32", "uint32"], + ["0xe0", paddedExclusiveFor, currentTime + SAME_CHAIN_EXCLUSIVITY_SECONDS] + ); + for (const output of order.outputs) { + if (output.context !== "0x") { + (output as any).context = newContext; + } + } +} + function toCoreTokenContext(input: AppTokenContext): TokenContext { return { token: { @@ -126,7 +156,11 @@ export class IntentFactory { const { account, inputTokens } = opts; const inputChain = inputTokens[0].token.chainId; if (this.preHook) await this.preHook(inputChain); - const intent = new Intent(toCoreCreateIntentOptions(opts), intentDeps).order(); + const intentInstance = new Intent(toCoreCreateIntentOptions(opts), intentDeps); + applySameChainTimings(intentInstance); + const sameChain = intentInstance.isSameChain(); + const intent = intentInstance.order(); + applyExclusivityOverride(intent, opts.exclusiveFor, sameChain); const sponsorSignature = await signIntentCompact(intent, account(), this.walletClient); @@ -164,7 +198,11 @@ export class IntentFactory { compactDepositAndRegister(opts: AppCreateIntentOptions) { return async () => { const { inputTokens, account } = opts; - const intent = new Intent(toCoreCreateIntentOptions(opts), intentDeps).singlechain(); + const intentInstance2 = new Intent(toCoreCreateIntentOptions(opts), intentDeps); + applySameChainTimings(intentInstance2); + const sameChain2 = intentInstance2.isSameChain(); + const intent = intentInstance2.singlechain(); + applyExclusivityOverride(intent, opts.exclusiveFor, sameChain2); if (this.preHook) await this.preHook(inputTokens[0].token.chainId); @@ -199,7 +237,11 @@ export class IntentFactory { openIntent(opts: AppCreateIntentOptions) { return async () => { const { inputTokens, account } = opts; - const intent = new Intent(toCoreCreateIntentOptions(opts), intentDeps).order(); + const intentInstance3 = new Intent(toCoreCreateIntentOptions(opts), intentDeps); + applySameChainTimings(intentInstance3); + const sameChain3 = intentInstance3.isSameChain(); + const intent = intentInstance3.order(); + applyExclusivityOverride(intent, opts.exclusiveFor, sameChain3); const inputChain = inputTokens[0].token.chainId; if (this.preHook) await this.preHook(inputChain); diff --git a/src/lib/screens/FillIntent.svelte b/src/lib/screens/FillIntent.svelte index 2147aa1..de5f4cd 100644 --- a/src/lib/screens/FillIntent.svelte +++ b/src/lib/screens/FillIntent.svelte @@ -33,6 +33,10 @@ let autoScrolledOrderId = $state<`0x${string}` | null>(null); let fillRun = 0; let fillStatuses = $state>({}); + let manualFillTxInputs = $state>({}); + let manualFillTxSaving = $state>({}); + let manualFillTxSaved = $state>({}); + let manualFillTxErrors = $state>({}); const postHookScroll = async () => { await postHook(); refreshValidation += 1; @@ -73,6 +77,35 @@ types: compactTypes, primaryType: "MandateOutput" }); + const isValidFillTxHash = (value: string): value is `0x${string}` => + value.startsWith("0x") && value.length === 66; + const getManualFillTxInputValue = (output: MandateOutput) => { + const key = outputKey(output); + return manualFillTxInputs[key] ?? store.fillTransactions[key] ?? ""; + }; + const saveManualFillTransaction = async (output: MandateOutput) => { + const key = outputKey(output); + const txHash = getManualFillTxInputValue(output).trim(); + if (!isValidFillTxHash(txHash)) { + manualFillTxErrors[key] = "Use a 0x-prefixed 66-char tx hash."; + manualFillTxSaved[key] = false; + return; + } + manualFillTxSaving[key] = true; + manualFillTxErrors[key] = ""; + try { + store.fillTransactions[key] = txHash; + await store.saveFillTransaction(key, txHash); + manualFillTxSaved[key] = true; + refreshValidation += 1; + } catch (error) { + console.warn("saveFillTransaction error", error); + manualFillTxErrors[key] = "Failed to save tx hash."; + manualFillTxSaved[key] = false; + } finally { + manualFillTxSaving[key] = false; + } + }; $effect(() => { refreshValidation; @@ -123,6 +156,49 @@ description="Fill each chain once and continue to the right. If you refreshed the page provide your fill tx hash in the input box." >
+ +
+ {#each orderContainer.order.outputs as output} + {@const key = outputKey(output)} + {@const currentHash = store.fillTransactions[key]} +
+ + { + const value = (event.currentTarget as HTMLInputElement).value; + manualFillTxInputs[key] = value; + manualFillTxSaved[key] = false; + manualFillTxErrors[key] = ""; + }} + /> + + {#if manualFillTxErrors[key]} +
{manualFillTxErrors[key]}
+ {:else if manualFillTxSaved[key]} +
Saved
+ {/if} +
+ {/each} +
+
{#each sortOutputsByChain(orderContainer) as chainIdAndOutputs} @@ -190,22 +266,6 @@ {/snippet} - {/each}
diff --git a/src/lib/screens/ReceiveMessage.svelte b/src/lib/screens/ReceiveMessage.svelte index a721f0f..d19ecf7 100644 --- a/src/lib/screens/ReceiveMessage.svelte +++ b/src/lib/screens/ReceiveMessage.svelte @@ -117,13 +117,7 @@ const inputChains = intent.inputChains(); const outputs = orderContainer.order.outputs; const fillTxHashes = outputs.map((output) => { - return store.fillTransactions[ - hashStruct({ - data: output, - types: compactTypes, - primaryType: "MandateOutput" - }) - ]; + return store.fillTransactions[outputKey(output)]; }); if ( @@ -197,14 +191,7 @@ { output, orderContainer, - fillTransactionHash: - store.fillTransactions[ - hashStruct({ - data: output, - types: compactTypes, - primaryType: "MandateOutput" - }) - ], + fillTransactionHash: store.fillTransactions[outputKey(output)], sourceChainId: Number(inputChain), mainnet: store.mainnet }, diff --git a/src/lib/state.svelte.ts b/src/lib/state.svelte.ts index 145bc99..7c71b1e 100644 --- a/src/lib/state.svelte.ts +++ b/src/lib/state.svelte.ts @@ -34,6 +34,14 @@ import { } from "./utils/wagmi"; import { switchWalletChain } from "./utils/walletClientRuntime"; +function generateUUID(): string { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + class Store { mainnet = $state(true); orders = $state([]); @@ -51,8 +59,7 @@ class Store { if (!db) await initDb(); const orderId = orderToIntent(order).orderId(); const now = Math.floor(Date.now() / 1000); - const id = - (order as any).id ?? (typeof crypto !== "undefined" ? crypto.randomUUID() : String(now)); + const id = (order as any).id ?? generateUUID(); const intentType = (order as any).intentType ?? "escrow"; const data = JSON.stringify(order); if (db) { @@ -127,7 +134,7 @@ class Store { .where(eq(fillTransactionsTable.outputHash, outputHash)); } else { await db!.insert(fillTransactionsTable).values({ - id: typeof crypto !== "undefined" ? crypto.randomUUID() : String(Date.now()), + id: generateUUID(), outputHash, txHash }); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 2b98745..3695214 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -173,12 +173,14 @@ class="mx-auto flex flex-col-reverse items-center px-4 pt-2 md:max-w-[80rem] md:flex-row md:items-start md:px-10 md:pt-3" > -
-
+
+
@@ -193,7 +195,7 @@ {#if !(!store.connectedAccount || !store.walletClient)}
Date: Tue, 10 Mar 2026 12:17:24 +0400 Subject: [PATCH 3/9] Allow directly adding tokens --- drizzle/0004_hesitant_quasimodo.sql | 21 ++ drizzle/meta/0004_snapshot.json | 227 +++++++++++++++++++++ drizzle/meta/_journal.json | 7 + src/lib/components/InputTokenModal.svelte | 10 +- src/lib/components/OutputTokenModal.svelte | 8 +- src/lib/config.ts | 6 + src/lib/migrations.json | 10 +- src/lib/schema.ts | 18 +- src/lib/screens/ManageDeposit.svelte | 104 ++++++++-- src/lib/state.svelte.ts | 135 +++++++++++- src/routes/+page.svelte | 9 +- 11 files changed, 516 insertions(+), 39 deletions(-) create mode 100644 drizzle/0004_hesitant_quasimodo.sql create mode 100644 drizzle/meta/0004_snapshot.json diff --git a/drizzle/0004_hesitant_quasimodo.sql b/drizzle/0004_hesitant_quasimodo.sql new file mode 100644 index 0000000..b636d66 --- /dev/null +++ b/drizzle/0004_hesitant_quasimodo.sql @@ -0,0 +1,21 @@ +CREATE TABLE "tokens" ( + "id" text PRIMARY KEY NOT NULL, + "address" text NOT NULL, + "name" text NOT NULL, + "chain_id" bigint NOT NULL, + "decimals" bigint NOT NULL, + "is_manual" boolean DEFAULT false NOT NULL, + "is_testnet" boolean DEFAULT false NOT NULL +); +--> statement-breakpoint +CREATE TABLE "transaction_receipts" ( + "id" text PRIMARY KEY NOT NULL, + "chain_id" bigint NOT NULL, + "tx_hash" text NOT NULL, + "receipt" text NOT NULL, + "created_at" bigint NOT NULL +); +--> statement-breakpoint +ALTER TABLE "intents" ALTER COLUMN "created_at" SET DATA TYPE bigint;--> statement-breakpoint +CREATE UNIQUE INDEX "tokens_address_chain_idx" ON "tokens" USING btree ("address","chain_id");--> statement-breakpoint +ALTER TABLE "intents" ADD CONSTRAINT "intents_order_id_unique" UNIQUE("order_id"); \ No newline at end of file diff --git a/drizzle/meta/0004_snapshot.json b/drizzle/meta/0004_snapshot.json new file mode 100644 index 0000000..c752c2b --- /dev/null +++ b/drizzle/meta/0004_snapshot.json @@ -0,0 +1,227 @@ +{ + "id": "89d339b9-626a-4944-9de0-259fa3e6bbf0", + "prevId": "9f78f425-71cd-4f66-b756-5c8433118a62", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.fill_transactions": { + "name": "fill_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "output_hash": { + "name": "output_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tx_hash": { + "name": "tx_hash", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "fill_transactions_output_hash_unique": { + "name": "fill_transactions_output_hash_unique", + "nullsNotDistinct": false, + "columns": ["output_hash"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.intents": { + "name": "intents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "order_id": { + "name": "order_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "intent_type": { + "name": "intent_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "intents_order_id_unique": { + "name": "intents_order_id_unique", + "nullsNotDistinct": false, + "columns": ["order_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tokens": { + "name": "tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chain_id": { + "name": "chain_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "decimals": { + "name": "decimals", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "is_manual": { + "name": "is_manual", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_testnet": { + "name": "is_testnet", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "tokens_address_chain_idx": { + "name": "tokens_address_chain_idx", + "columns": [ + { + "expression": "address", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chain_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transaction_receipts": { + "name": "transaction_receipts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "chain_id": { + "name": "chain_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tx_hash": { + "name": "tx_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "receipt": { + "name": "receipt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 6af4e86..8c2c418 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -29,6 +29,13 @@ "when": 1770810000000, "tag": "0003_unique_intent_order_id", "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1773066106972, + "tag": "0004_hesitant_quasimodo", + "breakpoints": true } ] } diff --git a/src/lib/components/InputTokenModal.svelte b/src/lib/components/InputTokenModal.svelte index ea7bcf3..a559ebf 100644 --- a/src/lib/components/InputTokenModal.svelte +++ b/src/lib/components/InputTokenModal.svelte @@ -1,5 +1,5 @@ {#await buttonPromise} - + {:then} - + {:catch} - + {/await} diff --git a/src/lib/components/BalanceField.svelte b/src/lib/components/BalanceField.svelte index 701bc3d..7e33d51 100644 --- a/src/lib/components/BalanceField.svelte +++ b/src/lib/components/BalanceField.svelte @@ -1,34 +1,34 @@ {#await value} - + {:then value} - + {:catch error} - + {/await} diff --git a/src/lib/components/GetQuote.svelte b/src/lib/components/GetQuote.svelte index bf78c89..d304356 100644 --- a/src/lib/components/GetQuote.svelte +++ b/src/lib/components/GetQuote.svelte @@ -1,156 +1,156 @@
- {#await quoteRequest} -
- Quote -
- {:then _} - - {#if quoteExpires !== 0} -
- - {:else} -
- - {/if} - {/await} + {#await quoteRequest} +
+ Quote +
+ {:then _} + + {#if quoteExpires !== 0} +
+ + {:else} +
+ + {/if} + {/await}
diff --git a/src/lib/components/InputTokenModal.svelte b/src/lib/components/InputTokenModal.svelte index a559ebf..6014a13 100644 --- a/src/lib/components/InputTokenModal.svelte +++ b/src/lib/components/InputTokenModal.svelte @@ -1,251 +1,251 @@
-
-
-
-

Select Input

-

Choose token amount distribution across chains.

-
- -
- -
-
- - - - - - - {#each uniqueInputTokens as token} - - {/each} - -
- -
- -
Chain
-
Amount / Balance
-
Use
-
-
- {#each tokenSet as tkn, rowIndex} - {@const iaddr = iaddrFor(tkn)} -
- -
- {getChainName(tkn.chainId)} -
- {#await (store.intentType === "compact" ? store.compactBalances : store.balances)[tkn.chainId][tkn.address]} - - {:then balance} - - {:catch _} - - {/await} -
- -
-
-
- {/each} -
-
- - -
-
+
+
+
+

Select Input

+

Choose token amount distribution across chains.

+
+ +
+ +
+
+ + + + + + + {#each uniqueInputTokens as token} + + {/each} + +
+ +
+ +
Chain
+
Amount / Balance
+
Use
+
+
+ {#each tokenSet as tkn, rowIndex} + {@const iaddr = iaddrFor(tkn)} +
+ +
+ {getChainName(tkn.chainId)} +
+ {#await (store.intentType === "compact" ? store.compactBalances : store.balances)[tkn.chainId][tkn.address]} + + {:then balance} + + {:catch _} + + {/await} +
+ +
+
+
+ {/each} +
+
+ + +
+
diff --git a/src/lib/components/IntentListDetailRow.svelte b/src/lib/components/IntentListDetailRow.svelte index 8763ada..24cda4f 100644 --- a/src/lib/components/IntentListDetailRow.svelte +++ b/src/lib/components/IntentListDetailRow.svelte @@ -1,74 +1,74 @@
-
-
- IN - {#each row.inputChips as chip (chip.key)} - {chip.text} - {/each} - {#if row.inputOverflow > 0} - +{row.inputOverflow} - {/if} - -
-
- OUT - {#each row.outputChips as chip (chip.key)} - {chip.text} - {/each} - {#if row.outputOverflow > 0} - +{row.outputOverflow} - {/if} -
-
-
- {rightBadge} - {rightText} -
+
+
+ IN + {#each row.inputChips as chip (chip.key)} + {chip.text} + {/each} + {#if row.inputOverflow > 0} + +{row.inputOverflow} + {/if} + +
+
+ OUT + {#each row.outputChips as chip (chip.key)} + {chip.text} + {/each} + {#if row.outputOverflow > 0} + +{row.outputOverflow} + {/if} +
+
+
+ {rightBadge} + {rightText} +
- {row.chainScopeBadge} - {#if row.inputSchemeBadge} - {row.inputSchemeBadge} - {/if} - {#each row.protocolBadges as badge (badge)} - {badge} - {/each} - Order {row.orderIdShort} - User {row.userShort} - {row.inputCount} inputs • {row.outputCount} outputs - - {row.validationPassed ? "Validation Pass" : `Invalid: ${row.validationReason}`} - + {row.chainScopeBadge} + {#if row.inputSchemeBadge} + {row.inputSchemeBadge} + {/if} + {#each row.protocolBadges as badge (badge)} + {badge} + {/each} + Order {row.orderIdShort} + User {row.userShort} + {row.inputCount} inputs • {row.outputCount} outputs + + {row.validationPassed ? "Validation Pass" : `Invalid: ${row.validationReason}`} +
diff --git a/src/lib/components/Introduction.svelte b/src/lib/components/Introduction.svelte index ea22fea..623630a 100644 --- a/src/lib/components/Introduction.svelte +++ b/src/lib/components/Introduction.svelte @@ -1,82 +1,82 @@
-

- This webapp demonstrates chain abstraction using the - Open Intents Framework. It currently support a seamless resource lock flow using - The Compact and a traditional escrow flow, along with a work in progress multichain flow. -

+

+ This webapp demonstrates chain abstraction using the + Open Intents Framework. It currently support a seamless resource lock flow using + The Compact and a traditional escrow flow, along with a work in progress multichain flow. +

-
+
-

Multichain

-

- A multichain intent is an intent that collects inputs on multiple chains, providing the result - on one or more chains. In other words, a multichain intent is an any to any intent. - Multichain intents are currently work in progress and will break in the future. If you are using - this interface for testing, ensure the multichain flag is not shown. -

+

Multichain

+

+ A multichain intent is an intent that collects inputs on multiple chains, providing the result + on one or more chains. In other words, a multichain intent is an any to any intent. + Multichain intents are currently work in progress and will break in the future. If you are using + this interface for testing, ensure the multichain flag is not shown. +

-
+
-

Why Resource Locks?

-

- Resource Locks improve asset availability guarantees in cross-chain contexts and asynchronous - environments, offering several key advantages: -

+

Why Resource Locks?

+

+ Resource Locks improve asset availability guarantees in cross-chain contexts and asynchronous + environments, offering several key advantages: +

-
    -
  • Funds are only debited after successful delivery has been proven.
  • -
  • - Enables efficient short-lived interactions—intents can expire within seconds without - consequence. -
  • -
  • No upfront deposit or initiation transaction are required.
  • -
  • Fully composable with other protocols and settlement layers.
  • -
+
    +
  • Funds are only debited after successful delivery has been proven.
  • +
  • + Enables efficient short-lived interactions—intents can expire within seconds without + consequence. +
  • +
  • No upfront deposit or initiation transaction are required.
  • +
  • Fully composable with other protocols and settlement layers.
  • +
-

- Learn more about - Resource Locks. -

+

+ Learn more about + Resource Locks. +

-
+
-

Why the Open Intents Framework?

-

- The Open Intents Framework (OIF) is an open coordination layer for standardizing and scaling - intent-based workflows across chains. The goal is to: -

+

Why the Open Intents Framework?

+

+ The Open Intents Framework (OIF) is an open coordination layer for standardizing and scaling + intent-based workflows across chains. The goal is to: +

-
    -
  • Standardise cross-chain interactions.
  • -
  • Define a permissionless intent implementation that can scale across all chains.
  • -
  • Create a reference implementation for cross-chain solvers & searchers.
  • -
  • Provide tooling for wallet and app developers.
  • -
-

- Learn more about - Open Intents Framework. -

+
    +
  • Standardise cross-chain interactions.
  • +
  • Define a permissionless intent implementation that can scale across all chains.
  • +
  • Create a reference implementation for cross-chain solvers & searchers.
  • +
  • Provide tooling for wallet and app developers.
  • +
+

+ Learn more about + Open Intents Framework. +

-
+
-

Same Chain

-

- A same chain intent is an intent that only has inputs and outputs on the same chain. The oracle - is configured different to a cross-chain intent. SetAttestation has to be called on the output - settler to expose the filled output. Learm more about same chain intents or explore a demo of how to collect inputs before delivering outputs. -

+

Same Chain

+

+ A same chain intent is an intent that only has inputs and outputs on the same chain. The oracle + is configured different to a cross-chain intent. SetAttestation has to be called on the output + settler to expose the filled output. Learm more about same chain intents or explore a demo of how to collect inputs before delivering outputs. +

diff --git a/src/lib/components/OutputTokenModal.svelte b/src/lib/components/OutputTokenModal.svelte index 26d03dc..43802ce 100644 --- a/src/lib/components/OutputTokenModal.svelte +++ b/src/lib/components/OutputTokenModal.svelte @@ -1,138 +1,138 @@
-
-
-
-

Select Output

-

Configure one or more destination token outputs.

-
- -
+
+
+
+

Select Output

+

Configure one or more destination token outputs.

+
+ +
-
-
- -
Chain
-
Amount
-
Token
-
-
- {#each outputs as output, rowIndex} - - - {#each chainIdList(store.mainnet) as chainId} - - {/each} - - - - {#each getTokensForChain(output.chainId) as token} - - {/each} - - - {/each} -
-
+
+
+ +
Chain
+
Amount
+
Token
+
+
+ {#each outputs as output, rowIndex} + + + {#each chainIdList(store.mainnet) as chainId} + + {/each} + + + + {#each getTokensForChain(output.chainId) as token} + + {/each} + + + {/each} +
+
-
- - - -
-
-
+
+ + + +
+
+
diff --git a/src/lib/components/ui/ChainActionRow.svelte b/src/lib/components/ui/ChainActionRow.svelte index 4350a30..b0f7ef9 100644 --- a/src/lib/components/ui/ChainActionRow.svelte +++ b/src/lib/components/ui/ChainActionRow.svelte @@ -1,40 +1,40 @@
-
- {chainLabel} -
-
-
- {@render action?.()} -
-
-
- {@render chips?.()} -
-
-
+
+ {chainLabel} +
+
+
+ {@render action?.()} +
+
+
+ {@render chips?.()} +
+
+
diff --git a/src/lib/components/ui/FieldRow.svelte b/src/lib/components/ui/FieldRow.svelte index 413d829..77000ee 100644 --- a/src/lib/components/ui/FieldRow.svelte +++ b/src/lib/components/ui/FieldRow.svelte @@ -1,33 +1,33 @@
- {@render children?.()} + {@render children?.()}
diff --git a/src/lib/components/ui/FlowProgressList.svelte b/src/lib/components/ui/FlowProgressList.svelte index 773f022..e6f14ca 100644 --- a/src/lib/components/ui/FlowProgressList.svelte +++ b/src/lib/components/ui/FlowProgressList.svelte @@ -1,108 +1,108 @@
- -
-
- {#each steps as step, i (step.id)} - - {#if i < steps.length - 1} -
-
-
-
- {/if} - {/each} -
-
+ +
+
+ {#each steps as step, i (step.id)} + + {#if i < steps.length - 1} +
+
+
+
+ {/if} + {/each} +
+
diff --git a/src/lib/components/ui/FlowStepTracker.svelte b/src/lib/components/ui/FlowStepTracker.svelte index 9034160..434ed6b 100644 --- a/src/lib/components/ui/FlowStepTracker.svelte +++ b/src/lib/components/ui/FlowStepTracker.svelte @@ -1,230 +1,230 @@ diff --git a/src/lib/components/ui/FormControl.svelte b/src/lib/components/ui/FormControl.svelte index 1553054..bc4e34a 100644 --- a/src/lib/components/ui/FormControl.svelte +++ b/src/lib/components/ui/FormControl.svelte @@ -1,60 +1,60 @@ {#if as === "select"} - + {:else} - + {/if} diff --git a/src/lib/components/ui/InlineMetaField.svelte b/src/lib/components/ui/InlineMetaField.svelte index c1adac7..95e2eb4 100644 --- a/src/lib/components/ui/InlineMetaField.svelte +++ b/src/lib/components/ui/InlineMetaField.svelte @@ -1,27 +1,27 @@
- -
- {metaPrefix} - {metaText} -
+ +
+ {metaPrefix} + {metaText} +
diff --git a/src/lib/components/ui/ScreenFrame.svelte b/src/lib/components/ui/ScreenFrame.svelte index b9b30ed..af421a3 100644 --- a/src/lib/components/ui/ScreenFrame.svelte +++ b/src/lib/components/ui/ScreenFrame.svelte @@ -1,29 +1,29 @@
- {#if title} -

{title}

- {/if} - {#if description} -

{description}

- {/if} -
- {@render children?.()} -
+ {#if title} +

{title}

+ {/if} + {#if description} +

{description}

+ {/if} +
+ {@render children?.()} +
diff --git a/src/lib/components/ui/SectionCard.svelte b/src/lib/components/ui/SectionCard.svelte index ed08b64..d03bffc 100644 --- a/src/lib/components/ui/SectionCard.svelte +++ b/src/lib/components/ui/SectionCard.svelte @@ -1,40 +1,40 @@
- {#if title || headerRight} -
- {#if title} -

{title}

- {/if} - {#if headerRight} -
- {@render headerRight()} -
- {/if} -
- {/if} -
- {@render children?.()} -
+ {#if title || headerRight} +
+ {#if title} +

{title}

+ {/if} + {#if headerRight} +
+ {@render headerRight()} +
+ {/if} +
+ {/if} +
+ {@render children?.()} +
diff --git a/src/lib/components/ui/SegmentedControl.svelte b/src/lib/components/ui/SegmentedControl.svelte index 959d745..2812812 100644 --- a/src/lib/components/ui/SegmentedControl.svelte +++ b/src/lib/components/ui/SegmentedControl.svelte @@ -1,45 +1,45 @@
- {#each options as option, i (option.value)} - - {/each} + {#each options as option, i (option.value)} + + {/each}
diff --git a/src/lib/components/ui/TokenAmountChip.svelte b/src/lib/components/ui/TokenAmountChip.svelte index bf953f2..efeafbc 100644 --- a/src/lib/components/ui/TokenAmountChip.svelte +++ b/src/lib/components/ui/TokenAmountChip.svelte @@ -1,34 +1,34 @@
- {amountText} - {symbol.toUpperCase()} + {amountText} + {symbol.toUpperCase()}
diff --git a/src/lib/config.ts b/src/lib/config.ts index f1e4250..7495ebc 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,81 +1,81 @@ import { createPublicClient, createWalletClient, custom, fallback, http } from "viem"; import { - arbitrum, - arbitrumSepolia, - base, - baseSepolia, - mainnet as ethereum, - optimismSepolia, - sepolia, - polygon, - bsc, - katana, - megaeth, - optimism + arbitrum, + arbitrumSepolia, + base, + baseSepolia, + mainnet as ethereum, + optimismSepolia, + sepolia, + polygon, + bsc, + katana, + megaeth, + optimism } from "viem/chains"; export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000" as const; export const BYTES32_ZERO = - "0x0000000000000000000000000000000000000000000000000000000000000000" as const; + "0x0000000000000000000000000000000000000000000000000000000000000000" as const; export const COMPACT = "0x00000000000000171ede64904551eeDF3C6C9788" as const; export const INPUT_SETTLER_COMPACT_LIFI = "0x0000000000cd5f7fDEc90a03a31F79E5Fbc6A9Cf" as const; export const INPUT_SETTLER_ESCROW_LIFI = "0x000025c3226C00B2Cdc200005a1600509f4e00C0" as const; export const MULTICHAIN_INPUT_SETTLER_ESCROW = - "0xb912b4c38ab54b94D45Ac001484dEBcbb519Bc2B" as const; + "0xb912b4c38ab54b94D45Ac001484dEBcbb519Bc2B" as const; export const MULTICHAIN_INPUT_SETTLER_COMPACT = - "0x1fccC0807F25A58eB531a0B5b4bf3dCE88808Ed7" as const; + "0x1fccC0807F25A58eB531a0B5b4bf3dCE88808Ed7" as const; export const ALWAYS_OK_ALLOCATOR = "281773970620737143753120258" as const; export const POLYMER_ALLOCATOR = "116450367070547927622991121" as const; // 0x02ecC89C25A5DCB1206053530c58E002a737BD11 signing by 0x934244C8cd6BeBDBd0696A659D77C9BDfE86Efe6 export const COIN_FILLER = "0x0000000000eC36B683C2E6AC89e9A75989C22a2e" as const; export const WORMHOLE_ORACLE: Partial> = { - [ethereum.id]: "0x0000000000000000000000000000000000000000", - [arbitrum.id]: "0x0000000000000000000000000000000000000000", - [base.id]: "0x0000000000000000000000000000000000000000" + [ethereum.id]: "0x0000000000000000000000000000000000000000", + [arbitrum.id]: "0x0000000000000000000000000000000000000000", + [base.id]: "0x0000000000000000000000000000000000000000" }; export const POLYMER_ORACLE: Partial> = { - [ethereum.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - [arbitrum.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - [base.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - [megaeth.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - [katana.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - [polygon.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - [bsc.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - // testnet - [sepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00", - [baseSepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00", - [arbitrumSepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00", - [optimismSepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00" + [ethereum.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + [arbitrum.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + [base.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + [megaeth.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + [katana.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + [polygon.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + [bsc.id]: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + // testnet + [sepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00", + [baseSepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00", + [arbitrumSepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00", + [optimismSepolia.id]: "0x00d5b500ECa100F7cdeDC800eC631Aca00BaAC00" }; export type availableAllocators = typeof ALWAYS_OK_ALLOCATOR | typeof POLYMER_ALLOCATOR; export type availableInputSettlers = - | typeof INPUT_SETTLER_COMPACT_LIFI - | typeof INPUT_SETTLER_ESCROW_LIFI; + | typeof INPUT_SETTLER_COMPACT_LIFI + | typeof INPUT_SETTLER_ESCROW_LIFI; export const chainMap = { - ethereum, - base, - arbitrum, - optimism, - sepolia, - arbitrumSepolia, - optimismSepolia, - baseSepolia, - katana, - megaeth, - bsc, - polygon + ethereum, + base, + arbitrum, + optimism, + sepolia, + arbitrumSepolia, + optimismSepolia, + baseSepolia, + katana, + megaeth, + bsc, + polygon } as const; type ChainName = keyof typeof chainMap; export const chains = Object.keys(chainMap) as ChainName[]; export const chainList = (mainnet: boolean) => { - if (mainnet == true) { - return ["ethereum", "base", "arbitrum", "megaeth", "katana", "polygon", "bsc"] as ChainName[]; - } else return ["sepolia", "optimismSepolia", "baseSepolia", "arbitrumSepolia"] as ChainName[]; + if (mainnet == true) { + return ["ethereum", "base", "arbitrum", "megaeth", "katana", "polygon", "bsc"] as ChainName[]; + } else return ["sepolia", "optimismSepolia", "baseSepolia", "arbitrumSepolia"] as ChainName[]; }; export const chainIdList = (mainnet: boolean) => { - return chainList(mainnet).map((name) => chainMap[name].id); + return chainList(mainnet).map((name) => chainMap[name].id); }; const chainEntries = chains.map((name) => [chainMap[name].id, chainMap[name]] as const); @@ -84,426 +84,426 @@ const chainNameEntries = chains.map((name) => [chainMap[name].id, name] as const export type balanceQuery = Record>>; export type Token = { - address: `0x${string}`; - name: string; - chainId: number; - decimals: number; + address: `0x${string}`; + name: string; + chainId: number; + decimals: number; }; export const coinList = (mainnet: boolean) => { - if (mainnet == true) - return [ - { - address: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`, - name: "usdc", - chainId: base.id, - decimals: 6 - }, - { - address: `0xaf88d065e77c8cC2239327C5EDb3A432268e5831`, - name: "usdc", - chainId: arbitrum.id, - decimals: 6 - }, - { - address: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`, - name: "usdc", - chainId: ethereum.id, - decimals: 6 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: base.id, - decimals: 18 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: arbitrum.id, - decimals: 18 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: ethereum.id, - decimals: 18 - }, - { - address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`, - name: "weth", - chainId: ethereum.id, - decimals: 18 - }, - { - address: `0x82106347dDbB23cE44Cf4cE4053Ef1adf8b9323B`, - name: "wmton", - chainId: ethereum.id, - decimals: 18 - }, - { - address: `0x4200000000000000000000000000000000000006`, - name: "weth", - chainId: base.id, - decimals: 18 - }, - { - address: `0x4200000000000000000000000000000000000006`, - name: "weth", - chainId: optimism.id, - decimals: 18 - }, - { - address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`, - name: "weth", - chainId: arbitrum.id, - decimals: 18 - }, - { - address: `0x4200000000000000000000000000000000000006`, - name: "weth", - chainId: megaeth.id, - decimals: 18 - }, - { - address: `0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7`, - name: "usdm", - chainId: megaeth.id, - decimals: 18 - }, - { - address: `0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d`, - name: "usdc-b", - chainId: bsc.id, - decimals: 18 - }, - { - address: `0x55d398326f99059ff775485246999027b3197955`, - name: "usdt-b", - chainId: bsc.id, - decimals: 18 - }, - { - address: `0x203a662b0bd271a6ed5a60edfbd04bfce608fd36`, - name: "vbUSDC", - chainId: katana.id, - decimals: 6 - }, - { - address: `0x7ceb23fd6bc0add59e62ac25578270cff1b9f619`, - name: "weth", - chainId: polygon.id, - decimals: 18 - }, - { - address: `0x3c499c542cef5e3811e1192ce70d8cc03d5c3359`, - name: "usdc", - chainId: polygon.id, - decimals: 6 - }, - { - address: `0x2791bca1f2de4661ed88a30c99a7a9449aa84174`, - name: "usdc.e", - chainId: polygon.id, - decimals: 6 - } - ] as const; - else - return [ - { - address: `0x5fd84259d66Cd46123540766Be93DFE6D43130D7`, - name: "usdc", - chainId: optimismSepolia.id, - decimals: 6 - }, - { - address: `0x036CbD53842c5426634e7929541eC2318f3dCF7e`, - name: "usdc", - chainId: baseSepolia.id, - decimals: 6 - }, - { - address: `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238`, - name: "usdc", - chainId: sepolia.id, - decimals: 6 - }, - { - address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", - name: "usdc", - chainId: arbitrumSepolia.id, - decimals: 6 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: sepolia.id, - decimals: 18 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: baseSepolia.id, - decimals: 18 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: optimismSepolia.id, - decimals: 18 - }, - { - address: ADDRESS_ZERO, - name: "eth", - chainId: arbitrumSepolia.id, - decimals: 6 - }, - { - address: `0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14`, - name: "weth", - chainId: sepolia.id, - decimals: 18 - }, - { - address: `0x4200000000000000000000000000000000000006`, - name: "weth", - chainId: baseSepolia.id, - decimals: 18 - }, - { - address: `0x4200000000000000000000000000000000000006`, - name: "weth", - chainId: optimismSepolia.id, - decimals: 18 - }, - { - address: `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73`, - name: "weth", - chainId: arbitrumSepolia.id, - decimals: 18 - } - ] as const; + if (mainnet == true) + return [ + { + address: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`, + name: "usdc", + chainId: base.id, + decimals: 6 + }, + { + address: `0xaf88d065e77c8cC2239327C5EDb3A432268e5831`, + name: "usdc", + chainId: arbitrum.id, + decimals: 6 + }, + { + address: `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`, + name: "usdc", + chainId: ethereum.id, + decimals: 6 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: base.id, + decimals: 18 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: arbitrum.id, + decimals: 18 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: ethereum.id, + decimals: 18 + }, + { + address: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`, + name: "weth", + chainId: ethereum.id, + decimals: 18 + }, + { + address: `0x82106347dDbB23cE44Cf4cE4053Ef1adf8b9323B`, + name: "wmton", + chainId: ethereum.id, + decimals: 18 + }, + { + address: `0x4200000000000000000000000000000000000006`, + name: "weth", + chainId: base.id, + decimals: 18 + }, + { + address: `0x4200000000000000000000000000000000000006`, + name: "weth", + chainId: optimism.id, + decimals: 18 + }, + { + address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`, + name: "weth", + chainId: arbitrum.id, + decimals: 18 + }, + { + address: `0x4200000000000000000000000000000000000006`, + name: "weth", + chainId: megaeth.id, + decimals: 18 + }, + { + address: `0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7`, + name: "usdm", + chainId: megaeth.id, + decimals: 18 + }, + { + address: `0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d`, + name: "usdc-b", + chainId: bsc.id, + decimals: 18 + }, + { + address: `0x55d398326f99059ff775485246999027b3197955`, + name: "usdt-b", + chainId: bsc.id, + decimals: 18 + }, + { + address: `0x203a662b0bd271a6ed5a60edfbd04bfce608fd36`, + name: "vbUSDC", + chainId: katana.id, + decimals: 6 + }, + { + address: `0x7ceb23fd6bc0add59e62ac25578270cff1b9f619`, + name: "weth", + chainId: polygon.id, + decimals: 18 + }, + { + address: `0x3c499c542cef5e3811e1192ce70d8cc03d5c3359`, + name: "usdc", + chainId: polygon.id, + decimals: 6 + }, + { + address: `0x2791bca1f2de4661ed88a30c99a7a9449aa84174`, + name: "usdc.e", + chainId: polygon.id, + decimals: 6 + } + ] as const; + else + return [ + { + address: `0x5fd84259d66Cd46123540766Be93DFE6D43130D7`, + name: "usdc", + chainId: optimismSepolia.id, + decimals: 6 + }, + { + address: `0x036CbD53842c5426634e7929541eC2318f3dCF7e`, + name: "usdc", + chainId: baseSepolia.id, + decimals: 6 + }, + { + address: `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238`, + name: "usdc", + chainId: sepolia.id, + decimals: 6 + }, + { + address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", + name: "usdc", + chainId: arbitrumSepolia.id, + decimals: 6 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: sepolia.id, + decimals: 18 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: baseSepolia.id, + decimals: 18 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: optimismSepolia.id, + decimals: 18 + }, + { + address: ADDRESS_ZERO, + name: "eth", + chainId: arbitrumSepolia.id, + decimals: 6 + }, + { + address: `0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14`, + name: "weth", + chainId: sepolia.id, + decimals: 18 + }, + { + address: `0x4200000000000000000000000000000000000006`, + name: "weth", + chainId: baseSepolia.id, + decimals: 18 + }, + { + address: `0x4200000000000000000000000000000000000006`, + name: "weth", + chainId: optimismSepolia.id, + decimals: 18 + }, + { + address: `0x980B62Da83eFf3D4576C647993b0c1D7faf17c73`, + name: "weth", + chainId: arbitrumSepolia.id, + decimals: 18 + } + ] as const; }; export function printToken(token: Token) { - return `${token.name.toUpperCase()}, ${getChainName(token.chainId)}`; + return `${token.name.toUpperCase()}, ${getChainName(token.chainId)}`; } export function formatTokenAmount(amount: bigint, tokenDecimals: number, decimals = 4) { - const formattedAmount = Number(amount) / 10 ** tokenDecimals; - return formattedAmount.toFixed(decimals); + const formattedAmount = Number(amount) / 10 ** tokenDecimals; + return formattedAmount.toFixed(decimals); } export function getIndexOf(token: Token) { - const coins = coinList(!isChainIdTestnet(token.chainId)); - for (let i = 0; i < coins.length; ++i) { - const elem = coins[i]; - if (token.chainId === elem.chainId && token.address === elem.address) return i; - } - return -1; + const coins = coinList(!isChainIdTestnet(token.chainId)); + for (let i = 0; i < coins.length; ++i) { + const elem = coins[i]; + if (token.chainId === elem.chainId && token.address === elem.address) return i; + } + return -1; } export type coin = ReturnType[number]["address"]; export const wormholeChainIds = { - sepolia: 10002, - arbitrumSepolia: 10003, - baseSepolia: 10004, - optimismSepolia: 10005 + sepolia: 10002, + arbitrumSepolia: 10003, + baseSepolia: 10004, + optimismSepolia: 10005 } as const; export const polymerChainIds = { - ethereum: ethereum.id, - base: base.id, - arbitrum: arbitrum.id, - sepolia: sepolia.id, - arbitrumSepolia: arbitrumSepolia.id, - baseSepolia: baseSepolia.id, - optimismSepolia: optimismSepolia.id, - optimism: optimism.id, - megaeth: megaeth.id, - katana: katana.id, - bsc: bsc.id, - polygon: polygon.id + ethereum: ethereum.id, + base: base.id, + arbitrum: arbitrum.id, + sepolia: sepolia.id, + arbitrumSepolia: arbitrumSepolia.id, + baseSepolia: baseSepolia.id, + optimismSepolia: optimismSepolia.id, + optimism: optimism.id, + megaeth: megaeth.id, + katana: katana.id, + bsc: bsc.id, + polygon: polygon.id } as const; export type Verifier = "wormhole" | "polymer"; export function getCoin( - args: - | { name: string; chainId: number | bigint | string; address?: undefined } - | { - address: `0x${string}`; - chainId: number | bigint | string; - name?: undefined; - } + args: + | { name: string; chainId: number | bigint | string; address?: undefined } + | { + address: `0x${string}`; + chainId: number | bigint | string; + name?: undefined; + } ) { - const { name = undefined, address = undefined } = args; - const chainId = normalizeChainId(args.chainId); - // ensure the address is ERC20-sized. - const concatedAddress = - "0x" + address?.replace("0x", "")?.slice(address.length - 42, address.length); - for (const token of coinList(!isChainIdTestnet(chainId))) { - // check chain first. - if (token.chainId === chainId) { - if (name === undefined) { - if (concatedAddress?.toLowerCase() === token.address.toLowerCase()) return token; - } - if (name?.toLowerCase() === token.name.toLowerCase()) return token; - } - } - return { - name: name ?? "Unknown", - address: address ?? ADDRESS_ZERO, - chainId, - decimals: 1 - }; - // throw new Error(`No coins found for chain: ${concatedAddress} ${chain}`); + const { name = undefined, address = undefined } = args; + const chainId = normalizeChainId(args.chainId); + // ensure the address is ERC20-sized. + const concatedAddress = + "0x" + address?.replace("0x", "")?.slice(address.length - 42, address.length); + for (const token of coinList(!isChainIdTestnet(chainId))) { + // check chain first. + if (token.chainId === chainId) { + if (name === undefined) { + if (concatedAddress?.toLowerCase() === token.address.toLowerCase()) return token; + } + if (name?.toLowerCase() === token.name.toLowerCase()) return token; + } + } + return { + name: name ?? "Unknown", + address: address ?? ADDRESS_ZERO, + chainId, + decimals: 1 + }; + // throw new Error(`No coins found for chain: ${concatedAddress} ${chain}`); } function normalizeChainId(chainId: number | bigint | string) { - if (typeof chainId === "string") return Number(chainId); - if (typeof chainId === "bigint") return Number(chainId); - return chainId; + if (typeof chainId === "string") return Number(chainId); + if (typeof chainId === "bigint") return Number(chainId); + return chainId; } export function isChainIdTestnet(chainId: number | bigint | string) { - const normalized = normalizeChainId(chainId); - const chain = chainById[normalized]; - if (!chain) throw new Error(`Chain is not known: ${normalized}`); - return chain.testnet; + const normalized = normalizeChainId(chainId); + const chain = chainById[normalized]; + if (!chain) throw new Error(`Chain is not known: ${normalized}`); + return chain.testnet; } export function getChainName(chainId: number | bigint | string) { - const normalized = normalizeChainId(chainId); - const name = chainNameById[normalized]; - if (!name) throw new Error(`Chain is not known: ${normalized}`); - return name; + const normalized = normalizeChainId(chainId); + const name = chainNameById[normalized]; + if (!name) throw new Error(`Chain is not known: ${normalized}`); + return name; } export function formatTokenDecimals( - value: bigint | number, - coin: Token, - as: "number" | "string" = "string" + value: bigint | number, + coin: Token, + as: "number" | "string" = "string" ) { - const decimals = coin.decimals; - const result = Number(value) / 10 ** decimals; - return as === "string" ? result.toString() : result; + const decimals = coin.decimals; + const result = Number(value) / 10 ** decimals; + return as === "string" ? result.toString() : result; } export function getOracle(verifier: Verifier, chainId: number | bigint | string) { - const normalized = normalizeChainId(chainId); - if (verifier === "polymer") return POLYMER_ORACLE[normalized]; - if (verifier === "wormhole") return WORMHOLE_ORACLE[normalized]; - return undefined; + const normalized = normalizeChainId(chainId); + if (verifier === "polymer") return POLYMER_ORACLE[normalized]; + if (verifier === "wormhole") return WORMHOLE_ORACLE[normalized]; + return undefined; } export function getChain(chainId: number | bigint | string) { - const normalized = normalizeChainId(chainId); - const chain = chainById[normalized]; - if (!chain) throw new Error(`Could not find chain for chainId ${normalized}`); - return chain; + const normalized = normalizeChainId(chainId); + const chain = chainById[normalized]; + if (!chain) throw new Error(`Could not find chain for chainId ${normalized}`); + return chain; } export function getClient(chainId: number | bigint | string) { - const normalized = normalizeChainId(chainId); - const client = clientsById[normalized]; - if (!client) throw new Error(`Could not find client for chainId ${normalized}`); - return client; + const normalized = normalizeChainId(chainId); + const client = clientsById[normalized]; + if (!client) throw new Error(`Could not find client for chainId ${normalized}`); + return client; } export const clients = { - ethereum: createPublicClient({ - chain: ethereum, - transport: fallback([ - http("https://ethereum-rpc.publicnode.com"), - ...ethereum.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - arbitrum: createPublicClient({ - chain: arbitrum, - transport: fallback([ - http("https://arbitrum-rpc.publicnode.com"), - ...arbitrum.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - base: createPublicClient({ - chain: base, - transport: fallback([ - http("https://base-rpc.publicnode.com"), - ...base.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - optimism: createPublicClient({ - chain: optimism, - transport: fallback([ - http("https://optimism-rpc.publicnode.com"), - ...optimism.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - bsc: createPublicClient({ - chain: bsc, - transport: fallback([ - http("https://bsc-rpc.publicnode.com"), - ...bsc.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - polygon: createPublicClient({ - chain: base, - transport: fallback([ - http("https://polygon-bor-rpc.publicnode.com"), - ...polygon.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - megaeth: createPublicClient({ - chain: megaeth, - transport: fallback([...megaeth.rpcUrls.default.http.map((v) => http(v))]) - }), - katana: createPublicClient({ - chain: katana, - transport: fallback([...katana.rpcUrls.default.http.map((v) => http(v))]) - }), - // Testnet - sepolia: createPublicClient({ - chain: sepolia, - transport: fallback([ - http("https://ethereum-sepolia-rpc.publicnode.com"), - ...sepolia.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - arbitrumSepolia: createPublicClient({ - chain: arbitrumSepolia, - transport: fallback([ - http("https://arbitrum-sepolia-rpc.publicnode.com"), - ...arbitrumSepolia.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - baseSepolia: createPublicClient({ - chain: baseSepolia, - transport: fallback([ - http("https://base-sepolia-rpc.publicnode.com"), - ...baseSepolia.rpcUrls.default.http.map((v) => http(v)) - ]) - }), - optimismSepolia: createPublicClient({ - chain: optimismSepolia, - transport: fallback([ - http("https://optimism-sepolia-rpc.publicnode.com"), - ...optimismSepolia.rpcUrls.default.http.map((v) => http(v)) - ]) - }) + ethereum: createPublicClient({ + chain: ethereum, + transport: fallback([ + http("https://ethereum-rpc.publicnode.com"), + ...ethereum.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + arbitrum: createPublicClient({ + chain: arbitrum, + transport: fallback([ + http("https://arbitrum-rpc.publicnode.com"), + ...arbitrum.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + base: createPublicClient({ + chain: base, + transport: fallback([ + http("https://base-rpc.publicnode.com"), + ...base.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + optimism: createPublicClient({ + chain: optimism, + transport: fallback([ + http("https://optimism-rpc.publicnode.com"), + ...optimism.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + bsc: createPublicClient({ + chain: bsc, + transport: fallback([ + http("https://bsc-rpc.publicnode.com"), + ...bsc.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + polygon: createPublicClient({ + chain: base, + transport: fallback([ + http("https://polygon-bor-rpc.publicnode.com"), + ...polygon.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + megaeth: createPublicClient({ + chain: megaeth, + transport: fallback([...megaeth.rpcUrls.default.http.map((v) => http(v))]) + }), + katana: createPublicClient({ + chain: katana, + transport: fallback([...katana.rpcUrls.default.http.map((v) => http(v))]) + }), + // Testnet + sepolia: createPublicClient({ + chain: sepolia, + transport: fallback([ + http("https://ethereum-sepolia-rpc.publicnode.com"), + ...sepolia.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + arbitrumSepolia: createPublicClient({ + chain: arbitrumSepolia, + transport: fallback([ + http("https://arbitrum-sepolia-rpc.publicnode.com"), + ...arbitrumSepolia.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + baseSepolia: createPublicClient({ + chain: baseSepolia, + transport: fallback([ + http("https://base-sepolia-rpc.publicnode.com"), + ...baseSepolia.rpcUrls.default.http.map((v) => http(v)) + ]) + }), + optimismSepolia: createPublicClient({ + chain: optimismSepolia, + transport: fallback([ + http("https://optimism-sepolia-rpc.publicnode.com"), + ...optimismSepolia.rpcUrls.default.http.map((v) => http(v)) + ]) + }) } as const; export const chainById = Object.fromEntries(chainEntries) as Record< - number, - (typeof chainMap)[keyof typeof chainMap] + number, + (typeof chainMap)[keyof typeof chainMap] >; export const chainNameById = Object.fromEntries(chainNameEntries) as Record; export const clientsById = Object.fromEntries( - chains.map((name) => [chainMap[name].id, clients[name]]) + chains.map((name) => [chainMap[name].id, clients[name]]) ) as Record; export type WC = ReturnType< - typeof createWalletClient, undefined, undefined, undefined> + typeof createWalletClient, undefined, undefined, undefined> >; diff --git a/src/lib/db.ts b/src/lib/db.ts index 4cbcba7..2640e07 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -9,35 +9,35 @@ export let db: ReturnType | undefined; let initDbPromise: Promise | undefined> | null = null; async function migrateDb(instance: ReturnType) { - // dialect and session will appear to not exist...but they do on the pglite drizzle instance - // @ts-ignore - await instance.dialect.migrate(migrations, instance.session, { - migrationsTable: "drizzle_migrations" - } satisfies Omit); + // dialect and session will appear to not exist...but they do on the pglite drizzle instance + // @ts-ignore + await instance.dialect.migrate(migrations, instance.session, { + migrationsTable: "drizzle_migrations" + } satisfies Omit); } export async function initDb() { - if (db) return db; - if (!browser) return undefined; - if (initDbPromise) return initDbPromise; + if (db) return db; + if (!browser) return undefined; + if (initDbPromise) return initDbPromise; - initDbPromise = (async () => { - // Open a PGLite database; this will persist to IndexedDB in the browser - const pglite = new PGlite("idb://orders"); + initDbPromise = (async () => { + // Open a PGLite database; this will persist to IndexedDB in the browser + const pglite = new PGlite("idb://orders"); - // Create a Drizzle instance over the opened SQLite-compatible database - db = drizzle(pglite); + // Create a Drizzle instance over the opened SQLite-compatible database + db = drizzle(pglite); - // Run migrations so tables are created on first load - await migrateDb(db); + // Run migrations so tables are created on first load + await migrateDb(db); - return db; - })().catch((error) => { - initDbPromise = null; - throw error; - }); + return db; + })().catch((error) => { + initDbPromise = null; + throw error; + }); - return initDbPromise; + return initDbPromise; } export default initDb; diff --git a/src/lib/libraries/assetSelection.ts b/src/lib/libraries/assetSelection.ts index 810ea4b..0aad289 100644 --- a/src/lib/libraries/assetSelection.ts +++ b/src/lib/libraries/assetSelection.ts @@ -1,80 +1,80 @@ const bigIntSum = (...nums: bigint[]) => nums.reduce((a, b) => a + b, 0n); export class AssetSelection { - goal: bigint; - values: bigint[]; - weights?: bigint[]; - - sortedValues: bigint[]; - - static Sum(values: bigint[]) { - return bigIntSum(...values); - } - - static feasible(goal: bigint, values: bigint[]) { - if (bigIntSum(...values) < goal) - throw Error(`Values makes ${bigIntSum(...values)} cannot sum ${goal}`); - } - - static zip(arr: bigint[]): [bigint, number][] { - return arr.map((v, i) => [v, i]); - } - - static unzip(arr: [bigint, number][]): bigint[] { - arr.sort((a, b) => a[1] - b[1]); - return arr.map((v) => v[0]); - } - - static takeFromArray(goal: bigint, values: [bigint, T][]) { - let sum = 0n; - for (let i = 0; i < values.length; ++i) { - const value = values[i][0]; - const less = goal - sum; - const diff = less < value ? less : value; - sum += diff; - values[i][0] = diff; - } - } - - constructor(opts: { goal: bigint; values: bigint[]; weights?: bigint[] }) { - AssetSelection.feasible(opts.goal, opts.values); - this.goal = opts.goal; - this.values = opts.values; - this.weights = opts.weights; - - this.sortedValues = this.values; - } - - // --- Get sorted values as --- // - - asValues() { - return this.sortedValues; - } - - asIndices() { - const zipped = AssetSelection.zip(this.sortedValues); - return zipped.filter((v) => v[0] > 0); - } - - // --- Sorting Methods --- // - - largest() { - const values = AssetSelection.zip(this.values); - values.sort((a, b) => Number(b[0] - a[0])); - - AssetSelection.takeFromArray(this.goal, values); - - this.sortedValues = AssetSelection.unzip(values); - return this; - } - - smallest() { - const values = AssetSelection.zip(this.values); - values.sort((a, b) => Number(a[0] - b[0])); - - AssetSelection.takeFromArray(this.goal, values); - - this.sortedValues = AssetSelection.unzip(values); - return this; - } + goal: bigint; + values: bigint[]; + weights?: bigint[]; + + sortedValues: bigint[]; + + static Sum(values: bigint[]) { + return bigIntSum(...values); + } + + static feasible(goal: bigint, values: bigint[]) { + if (bigIntSum(...values) < goal) + throw Error(`Values makes ${bigIntSum(...values)} cannot sum ${goal}`); + } + + static zip(arr: bigint[]): [bigint, number][] { + return arr.map((v, i) => [v, i]); + } + + static unzip(arr: [bigint, number][]): bigint[] { + arr.sort((a, b) => a[1] - b[1]); + return arr.map((v) => v[0]); + } + + static takeFromArray(goal: bigint, values: [bigint, T][]) { + let sum = 0n; + for (let i = 0; i < values.length; ++i) { + const value = values[i][0]; + const less = goal - sum; + const diff = less < value ? less : value; + sum += diff; + values[i][0] = diff; + } + } + + constructor(opts: { goal: bigint; values: bigint[]; weights?: bigint[] }) { + AssetSelection.feasible(opts.goal, opts.values); + this.goal = opts.goal; + this.values = opts.values; + this.weights = opts.weights; + + this.sortedValues = this.values; + } + + // --- Get sorted values as --- // + + asValues() { + return this.sortedValues; + } + + asIndices() { + const zipped = AssetSelection.zip(this.sortedValues); + return zipped.filter((v) => v[0] > 0); + } + + // --- Sorting Methods --- // + + largest() { + const values = AssetSelection.zip(this.values); + values.sort((a, b) => Number(b[0] - a[0])); + + AssetSelection.takeFromArray(this.goal, values); + + this.sortedValues = AssetSelection.unzip(values); + return this; + } + + smallest() { + const values = AssetSelection.zip(this.values); + values.sort((a, b) => Number(a[0] - b[0])); + + AssetSelection.takeFromArray(this.goal, values); + + this.sortedValues = AssetSelection.unzip(values); + return this; + } } diff --git a/src/lib/libraries/compactLib.ts b/src/lib/libraries/compactLib.ts index c59d862..594f0d4 100644 --- a/src/lib/libraries/compactLib.ts +++ b/src/lib/libraries/compactLib.ts @@ -8,150 +8,150 @@ import { ERC20_ABI } from "$lib/abi/erc20"; import type { AppTokenContext } from "$lib/appTypes"; export class CompactLib { - static compactDeposit( - walletClient: WC, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - inputToken: AppTokenContext; - account: () => `0x${string}`; - allocatorId: string; - } - ) { - return async () => { - const { preHook, postHook, inputToken, account, allocatorId } = opts; - const { token, amount } = inputToken; - if (preHook) await preHook(token.chainId); - const lockTag: `0x${string}` = `0x${toHex( - toId(true, ResetPeriod.OneDay, allocatorId, ADDRESS_ZERO), - { - size: 32 - } - ) - .replace("0x", "") - .slice(0, 24)}`; - const recipient = ADDRESS_ZERO; // This means sender. + static compactDeposit( + walletClient: WC, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + inputToken: AppTokenContext; + account: () => `0x${string}`; + allocatorId: string; + } + ) { + return async () => { + const { preHook, postHook, inputToken, account, allocatorId } = opts; + const { token, amount } = inputToken; + if (preHook) await preHook(token.chainId); + const lockTag: `0x${string}` = `0x${toHex( + toId(true, ResetPeriod.OneDay, allocatorId, ADDRESS_ZERO), + { + size: 32 + } + ) + .replace("0x", "") + .slice(0, 24)}`; + const recipient = ADDRESS_ZERO; // This means sender. - let transactionHash: `0x${string}`; - if (token.address === ADDRESS_ZERO) { - transactionHash = await walletClient.writeContract({ - chain: getChain(token.chainId), - account: account(), - address: COMPACT, - abi: COMPACT_ABI, - functionName: "depositNative", - value: amount, - args: [lockTag, recipient] - }); - } else { - transactionHash = await walletClient.writeContract({ - chain: getChain(token.chainId), - account: account(), - address: COMPACT, - abi: COMPACT_ABI, - functionName: "depositERC20", - args: [token.address, lockTag, amount, recipient] - }); - } - await getClient(token.chainId).waitForTransactionReceipt({ - hash: await transactionHash - }); - if (postHook) await postHook(); - return transactionHash; - }; - } + let transactionHash: `0x${string}`; + if (token.address === ADDRESS_ZERO) { + transactionHash = await walletClient.writeContract({ + chain: getChain(token.chainId), + account: account(), + address: COMPACT, + abi: COMPACT_ABI, + functionName: "depositNative", + value: amount, + args: [lockTag, recipient] + }); + } else { + transactionHash = await walletClient.writeContract({ + chain: getChain(token.chainId), + account: account(), + address: COMPACT, + abi: COMPACT_ABI, + functionName: "depositERC20", + args: [token.address, lockTag, amount, recipient] + }); + } + await getClient(token.chainId).waitForTransactionReceipt({ + hash: await transactionHash + }); + if (postHook) await postHook(); + return transactionHash; + }; + } - static compactWithdraw( - walletClient: WC, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - inputToken: AppTokenContext; - account: () => `0x${string}`; - allocatorId: string; - } - ) { - return async () => { - const { preHook, postHook, inputToken, account, allocatorId } = opts; - const { token, amount } = inputToken; - const assetId = toId(true, ResetPeriod.OneDay, allocatorId, token.address); + static compactWithdraw( + walletClient: WC, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + inputToken: AppTokenContext; + account: () => `0x${string}`; + allocatorId: string; + } + ) { + return async () => { + const { preHook, postHook, inputToken, account, allocatorId } = opts; + const { token, amount } = inputToken; + const assetId = toId(true, ResetPeriod.OneDay, allocatorId, token.address); - const allocatedTransferStruct: { - allocatorData: `0x${string}`; - nonce: bigint; - expires: bigint; - id: bigint; - recipients: { - claimant: bigint; - amount: bigint; - }[]; - } = { - allocatorData: "0x", // TODO: Get from allocator - nonce: BigInt(Math.floor(Math.random() * 2 ** 32)), - expires: maxInt32, // TODO: - id: assetId, - recipients: [ - { - claimant: BigInt(addressToBytes32(account())), - amount: amount - } - ] - }; + const allocatedTransferStruct: { + allocatorData: `0x${string}`; + nonce: bigint; + expires: bigint; + id: bigint; + recipients: { + claimant: bigint; + amount: bigint; + }[]; + } = { + allocatorData: "0x", // TODO: Get from allocator + nonce: BigInt(Math.floor(Math.random() * 2 ** 32)), + expires: maxInt32, // TODO: + id: assetId, + recipients: [ + { + claimant: BigInt(addressToBytes32(account())), + amount: amount + } + ] + }; - if (preHook) await preHook(token.chainId); - const transactionHash = walletClient.writeContract({ - chain: getChain(token.chainId), - account: account(), - address: COMPACT, - abi: COMPACT_ABI, - functionName: "allocatedTransfer", - args: [allocatedTransferStruct] - }); - await getClient(token.chainId).waitForTransactionReceipt({ - hash: await transactionHash - }); - if (postHook) await postHook(); - return transactionHash; - }; - } + if (preHook) await preHook(token.chainId); + const transactionHash = walletClient.writeContract({ + chain: getChain(token.chainId), + account: account(), + address: COMPACT, + abi: COMPACT_ABI, + functionName: "allocatedTransfer", + args: [allocatedTransferStruct] + }); + await getClient(token.chainId).waitForTransactionReceipt({ + hash: await transactionHash + }); + if (postHook) await postHook(); + return transactionHash; + }; + } - static compactApprove( - walletClient: WC, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - inputTokens: AppTokenContext[]; - account: () => `0x${string}`; - } - ) { - return async () => { - const { preHook, postHook, inputTokens, account } = opts; - for (let i = 0; i < inputTokens.length; ++i) { - const { token: inputToken, amount } = inputTokens[i]; - if (preHook) await preHook(inputToken.chainId); - const publicClient = getClient(inputToken.chainId); - // Check if we have sufficient allowance already. - const currentAllowance = await publicClient.readContract({ - address: inputToken.address, - abi: ERC20_ABI, - functionName: "allowance", - args: [account(), COMPACT] - }); - if (currentAllowance >= amount) continue; - const transactionHash = walletClient.writeContract({ - chain: getChain(inputToken.chainId), - account: account(), - address: inputToken.address, - abi: ERC20_ABI, - functionName: "approve", - args: [COMPACT, maxUint256] - }); + static compactApprove( + walletClient: WC, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + inputTokens: AppTokenContext[]; + account: () => `0x${string}`; + } + ) { + return async () => { + const { preHook, postHook, inputTokens, account } = opts; + for (let i = 0; i < inputTokens.length; ++i) { + const { token: inputToken, amount } = inputTokens[i]; + if (preHook) await preHook(inputToken.chainId); + const publicClient = getClient(inputToken.chainId); + // Check if we have sufficient allowance already. + const currentAllowance = await publicClient.readContract({ + address: inputToken.address, + abi: ERC20_ABI, + functionName: "allowance", + args: [account(), COMPACT] + }); + if (currentAllowance >= amount) continue; + const transactionHash = walletClient.writeContract({ + chain: getChain(inputToken.chainId), + account: account(), + address: inputToken.address, + abi: ERC20_ABI, + functionName: "approve", + args: [COMPACT, maxUint256] + }); - await publicClient.waitForTransactionReceipt({ - hash: await transactionHash - }); - } - if (postHook) await postHook(); - }; - } + await publicClient.waitForTransactionReceipt({ + hash: await transactionHash + }); + } + if (postHook) await postHook(); + }; + } } diff --git a/src/lib/libraries/coreDeps.ts b/src/lib/libraries/coreDeps.ts index e2e75bb..947449d 100644 --- a/src/lib/libraries/coreDeps.ts +++ b/src/lib/libraries/coreDeps.ts @@ -1,54 +1,54 @@ import { - COIN_FILLER, - INPUT_SETTLER_COMPACT_LIFI, - MULTICHAIN_INPUT_SETTLER_COMPACT, - POLYMER_ORACLE, - WORMHOLE_ORACLE + COIN_FILLER, + INPUT_SETTLER_COMPACT_LIFI, + MULTICHAIN_INPUT_SETTLER_COMPACT, + POLYMER_ORACLE, + WORMHOLE_ORACLE } from "$lib/config"; import type { IntentDeps, OrderContainerValidationDeps } from "@lifi/intent"; function isNonZeroAddress(value: string | undefined): value is `0x${string}` { - return !!value && value.toLowerCase() !== "0x0000000000000000000000000000000000000000"; + return !!value && value.toLowerCase() !== "0x0000000000000000000000000000000000000000"; } export const intentDeps: IntentDeps = { - getOracle(verifier, chainId) { - const key = Number(chainId); - if (!Number.isFinite(key)) return undefined; - if (verifier === "polymer") return POLYMER_ORACLE[key]; - if (verifier === "wormhole") { - return WORMHOLE_ORACLE[key]; - } - return undefined; - } + getOracle(verifier, chainId) { + const key = Number(chainId); + if (!Number.isFinite(key)) return undefined; + if (verifier === "polymer") return POLYMER_ORACLE[key]; + if (verifier === "wormhole") { + return WORMHOLE_ORACLE[key]; + } + return undefined; + } }; export const orderValidationDeps: OrderContainerValidationDeps = { - inputSettlers: [INPUT_SETTLER_COMPACT_LIFI, MULTICHAIN_INPUT_SETTLER_COMPACT], - allowedInputOracles({ chainId, sameChainFill }) { - const key = Number(chainId); - if (!Number.isFinite(key)) return undefined; - const polymer = POLYMER_ORACLE[key]; - const wormhole = WORMHOLE_ORACLE[key]; - const allowed: `0x${string}`[] = []; - if (polymer) allowed.push(polymer); - if (isNonZeroAddress(wormhole)) allowed.push(wormhole); - if (allowed.length === 0) return undefined; - if (sameChainFill) allowed.push(COIN_FILLER); - return allowed; - }, - allowedOutputOracles(chainId) { - const key = Number(chainId); - if (!Number.isFinite(key)) return undefined; - const polymer = POLYMER_ORACLE[key]; - const wormhole = WORMHOLE_ORACLE[key]; - const allowed: `0x${string}`[] = []; - if (polymer) allowed.push(polymer); - if (isNonZeroAddress(wormhole)) allowed.push(wormhole); - if (allowed.length === 0) return undefined; - return allowed; - }, - allowedOutputSettlers() { - return [COIN_FILLER]; - } + inputSettlers: [INPUT_SETTLER_COMPACT_LIFI, MULTICHAIN_INPUT_SETTLER_COMPACT], + allowedInputOracles({ chainId, sameChainFill }) { + const key = Number(chainId); + if (!Number.isFinite(key)) return undefined; + const polymer = POLYMER_ORACLE[key]; + const wormhole = WORMHOLE_ORACLE[key]; + const allowed: `0x${string}`[] = []; + if (polymer) allowed.push(polymer); + if (isNonZeroAddress(wormhole)) allowed.push(wormhole); + if (allowed.length === 0) return undefined; + if (sameChainFill) allowed.push(COIN_FILLER); + return allowed; + }, + allowedOutputOracles(chainId) { + const key = Number(chainId); + if (!Number.isFinite(key)) return undefined; + const polymer = POLYMER_ORACLE[key]; + const wormhole = WORMHOLE_ORACLE[key]; + const allowed: `0x${string}`[] = []; + if (polymer) allowed.push(polymer); + if (isNonZeroAddress(wormhole)) allowed.push(wormhole); + if (allowed.length === 0) return undefined; + return allowed; + }, + allowedOutputSettlers() { + return [COIN_FILLER]; + } }; diff --git a/src/lib/libraries/flowProgress.ts b/src/lib/libraries/flowProgress.ts index 510e33f..c4e59a3 100644 --- a/src/lib/libraries/flowProgress.ts +++ b/src/lib/libraries/flowProgress.ts @@ -1,11 +1,11 @@ import { - BYTES32_ZERO, - COMPACT, - INPUT_SETTLER_COMPACT_LIFI, - INPUT_SETTLER_ESCROW_LIFI, - MULTICHAIN_INPUT_SETTLER_COMPACT, - MULTICHAIN_INPUT_SETTLER_ESCROW, - getClient + BYTES32_ZERO, + COMPACT, + INPUT_SETTLER_COMPACT_LIFI, + INPUT_SETTLER_ESCROW_LIFI, + MULTICHAIN_INPUT_SETTLER_COMPACT, + MULTICHAIN_INPUT_SETTLER_ESCROW, + getClient } from "$lib/config"; import { COIN_FILLER_ABI } from "$lib/abi/outputsettler"; import { POLYMER_ORACLE_ABI } from "$lib/abi/polymeroracle"; @@ -25,209 +25,209 @@ const OrderStatus_Claimed = 2; const OrderStatus_Refunded = 3; export type FlowCheckState = { - allFilled: boolean; - allValidated: boolean; - allFinalised: boolean; + allFilled: boolean; + allValidated: boolean; + allFinalised: boolean; }; export function getOutputStorageKey(output: MandateOutput) { - return hashStruct({ - data: output, - types: compactTypes, - primaryType: "MandateOutput" - }); + return hashStruct({ + data: output, + types: compactTypes, + primaryType: "MandateOutput" + }); } function isValidHash(hash: string | undefined): hash is `0x${string}` { - return !!hash && hash.startsWith("0x") && hash.length === 66; + return !!hash && hash.startsWith("0x") && hash.length === 66; } async function isOutputFilled(orderId: `0x${string}`, output: MandateOutput) { - const outputKey = getOutputStorageKey(output); - return getOrFetchRpc( - `progress:filled:${orderId}:${outputKey}`, - async () => { - const outputClient = getClient(output.chainId); - const outputHash = getOutputHash(output); - const result = await outputClient.readContract({ - address: bytes32ToAddress(output.settler), - abi: COIN_FILLER_ABI, - functionName: "getFillRecord", - args: [orderId, outputHash] - }); - return result !== BYTES32_ZERO; - }, - { ttlMs: PROGRESS_TTL_MS } - ); + const outputKey = getOutputStorageKey(output); + return getOrFetchRpc( + `progress:filled:${orderId}:${outputKey}`, + async () => { + const outputClient = getClient(output.chainId); + const outputHash = getOutputHash(output); + const result = await outputClient.readContract({ + address: bytes32ToAddress(output.settler), + abi: COIN_FILLER_ABI, + functionName: "getFillRecord", + args: [orderId, outputHash] + }); + return result !== BYTES32_ZERO; + }, + { ttlMs: PROGRESS_TTL_MS } + ); } async function isOutputValidatedOnChain( - orderId: `0x${string}`, - inputChain: bigint, - orderContainer: OrderContainer, - output: MandateOutput, - fillTransactionHash: `0x${string}` + orderId: `0x${string}`, + inputChain: bigint, + orderContainer: OrderContainer, + output: MandateOutput, + fillTransactionHash: `0x${string}` ) { - const outputKey = getOutputStorageKey(output); - const cachedReceipt = store.getTransactionReceipt(output.chainId, fillTransactionHash); - const receipt = ( - cachedReceipt - ? cachedReceipt - : await getOrFetchRpc( - `progress:receipt:${output.chainId.toString()}:${fillTransactionHash}`, - async () => { - const outputClient = getClient(output.chainId); - return outputClient.getTransactionReceipt({ - hash: fillTransactionHash - }); - }, - { ttlMs: PROGRESS_TTL_MS } - ) - ) as { - blockHash: `0x${string}`; - from: `0x${string}`; - }; - if (!cachedReceipt) { - store - .saveTransactionReceipt(output.chainId, fillTransactionHash, receipt) - .catch((error) => console.warn("saveTransactionReceipt error", error)); - } - - const block = await getOrFetchRpc( - `progress:block:${output.chainId.toString()}:${receipt.blockHash}`, - async () => { - const outputClient = getClient(output.chainId); - return outputClient.getBlock({ blockHash: receipt.blockHash }); - }, - { ttlMs: PROGRESS_TTL_MS } - ); - - const encodedOutput = encodeMandateOutput({ - solver: addressToBytes32(receipt.from), - orderId, - timestamp: Number(block.timestamp), - output - }); - const outputHash = keccak256(encodedOutput); - - return getOrFetchRpc( - `progress:proven:${orderId}:${inputChain.toString()}:${outputKey}:${fillTransactionHash}`, - async () => { - const sourceChainClient = getClient(inputChain); - return sourceChainClient.readContract({ - address: orderContainer.order.inputOracle, - abi: POLYMER_ORACLE_ABI, - functionName: "isProven", - args: [output.chainId, output.oracle, output.settler, outputHash] - }); - }, - { ttlMs: PROGRESS_TTL_MS } - ); + const outputKey = getOutputStorageKey(output); + const cachedReceipt = store.getTransactionReceipt(output.chainId, fillTransactionHash); + const receipt = ( + cachedReceipt + ? cachedReceipt + : await getOrFetchRpc( + `progress:receipt:${output.chainId.toString()}:${fillTransactionHash}`, + async () => { + const outputClient = getClient(output.chainId); + return outputClient.getTransactionReceipt({ + hash: fillTransactionHash + }); + }, + { ttlMs: PROGRESS_TTL_MS } + ) + ) as { + blockHash: `0x${string}`; + from: `0x${string}`; + }; + if (!cachedReceipt) { + store + .saveTransactionReceipt(output.chainId, fillTransactionHash, receipt) + .catch((error) => console.warn("saveTransactionReceipt error", error)); + } + + const block = await getOrFetchRpc( + `progress:block:${output.chainId.toString()}:${receipt.blockHash}`, + async () => { + const outputClient = getClient(output.chainId); + return outputClient.getBlock({ blockHash: receipt.blockHash }); + }, + { ttlMs: PROGRESS_TTL_MS } + ); + + const encodedOutput = encodeMandateOutput({ + solver: addressToBytes32(receipt.from), + orderId, + timestamp: Number(block.timestamp), + output + }); + const outputHash = keccak256(encodedOutput); + + return getOrFetchRpc( + `progress:proven:${orderId}:${inputChain.toString()}:${outputKey}:${fillTransactionHash}`, + async () => { + const sourceChainClient = getClient(inputChain); + return sourceChainClient.readContract({ + address: orderContainer.order.inputOracle, + abi: POLYMER_ORACLE_ABI, + functionName: "isProven", + args: [output.chainId, output.oracle, output.settler, outputHash] + }); + }, + { ttlMs: PROGRESS_TTL_MS } + ); } async function isInputChainFinalised(chainId: bigint, container: OrderContainer) { - const { order, inputSettler } = container; - const inputChainClient = getClient(chainId); - const intent = orderToIntent(container); - const orderId = intent.orderId(); - - if ( - inputSettler === INPUT_SETTLER_ESCROW_LIFI || - inputSettler === MULTICHAIN_INPUT_SETTLER_ESCROW - ) { - return getOrFetchRpc( - `progress:finalised:escrow:${orderId}:${chainId.toString()}`, - async () => { - const orderStatus = await inputChainClient.readContract({ - address: inputSettler, - abi: SETTLER_ESCROW_ABI, - functionName: "orderStatus", - args: [orderId] - }); - return orderStatus === OrderStatus_Claimed || orderStatus === OrderStatus_Refunded; - }, - { ttlMs: PROGRESS_TTL_MS } - ); - } - - if ( - inputSettler === INPUT_SETTLER_COMPACT_LIFI || - inputSettler === MULTICHAIN_INPUT_SETTLER_COMPACT - ) { - const flattenedInputs = "originChainId" in order ? order.inputs : order.inputs[0]?.inputs; - if (!flattenedInputs || flattenedInputs.length === 0) return false; - - return getOrFetchRpc( - `progress:finalised:compact:${orderId}:${chainId.toString()}`, - async () => { - const [, allocator] = await inputChainClient.readContract({ - address: COMPACT, - abi: COMPACT_ABI, - functionName: "getLockDetails", - args: [flattenedInputs[0][0]] - }); - return inputChainClient.readContract({ - address: COMPACT, - abi: COMPACT_ABI, - functionName: "hasConsumedAllocatorNonce", - args: [order.nonce, allocator] - }); - }, - { ttlMs: PROGRESS_TTL_MS } - ); - } - - return false; + const { order, inputSettler } = container; + const inputChainClient = getClient(chainId); + const intent = orderToIntent(container); + const orderId = intent.orderId(); + + if ( + inputSettler === INPUT_SETTLER_ESCROW_LIFI || + inputSettler === MULTICHAIN_INPUT_SETTLER_ESCROW + ) { + return getOrFetchRpc( + `progress:finalised:escrow:${orderId}:${chainId.toString()}`, + async () => { + const orderStatus = await inputChainClient.readContract({ + address: inputSettler, + abi: SETTLER_ESCROW_ABI, + functionName: "orderStatus", + args: [orderId] + }); + return orderStatus === OrderStatus_Claimed || orderStatus === OrderStatus_Refunded; + }, + { ttlMs: PROGRESS_TTL_MS } + ); + } + + if ( + inputSettler === INPUT_SETTLER_COMPACT_LIFI || + inputSettler === MULTICHAIN_INPUT_SETTLER_COMPACT + ) { + const flattenedInputs = "originChainId" in order ? order.inputs : order.inputs[0]?.inputs; + if (!flattenedInputs || flattenedInputs.length === 0) return false; + + return getOrFetchRpc( + `progress:finalised:compact:${orderId}:${chainId.toString()}`, + async () => { + const [, allocator] = await inputChainClient.readContract({ + address: COMPACT, + abi: COMPACT_ABI, + functionName: "getLockDetails", + args: [flattenedInputs[0][0]] + }); + return inputChainClient.readContract({ + address: COMPACT, + abi: COMPACT_ABI, + functionName: "hasConsumedAllocatorNonce", + args: [order.nonce, allocator] + }); + }, + { ttlMs: PROGRESS_TTL_MS } + ); + } + + return false; } export async function getOrderProgressChecks( - orderContainer: OrderContainer, - fillTransactions: Record + orderContainer: OrderContainer, + fillTransactions: Record ): Promise { - try { - const intent = orderToIntent(orderContainer); - const orderId = intent.orderId(); - const inputChains = intent.inputChains(); - const outputs = orderContainer.order.outputs; - - const filledStates = await Promise.all( - outputs.map((output) => isOutputFilled(orderId, output)) - ); - const allFilled = outputs.length > 0 && filledStates.every(Boolean); - - let allValidated = false; - if (allFilled && inputChains.length > 0) { - const validatedPairs = await Promise.all( - inputChains.flatMap((inputChain) => - outputs.map(async (output) => { - const fillHash = fillTransactions[getOutputStorageKey(output)]; - if (!isValidHash(fillHash)) return false; - return isOutputValidatedOnChain(orderId, inputChain, orderContainer, output, fillHash); - }) - ) - ); - allValidated = validatedPairs.length > 0 && validatedPairs.every(Boolean); - } - - let allFinalised = false; - if (allValidated && inputChains.length > 0) { - const finalisedStates = await Promise.all( - inputChains.map((chainId) => isInputChainFinalised(chainId, orderContainer)) - ); - allFinalised = finalisedStates.every(Boolean); - } - - return { - allFilled, - allValidated, - allFinalised - }; - } catch (error) { - console.warn("progress checks failed", error); - return { - allFilled: false, - allValidated: false, - allFinalised: false - }; - } + try { + const intent = orderToIntent(orderContainer); + const orderId = intent.orderId(); + const inputChains = intent.inputChains(); + const outputs = orderContainer.order.outputs; + + const filledStates = await Promise.all( + outputs.map((output) => isOutputFilled(orderId, output)) + ); + const allFilled = outputs.length > 0 && filledStates.every(Boolean); + + let allValidated = false; + if (allFilled && inputChains.length > 0) { + const validatedPairs = await Promise.all( + inputChains.flatMap((inputChain) => + outputs.map(async (output) => { + const fillHash = fillTransactions[getOutputStorageKey(output)]; + if (!isValidHash(fillHash)) return false; + return isOutputValidatedOnChain(orderId, inputChain, orderContainer, output, fillHash); + }) + ) + ); + allValidated = validatedPairs.length > 0 && validatedPairs.every(Boolean); + } + + let allFinalised = false; + if (allValidated && inputChains.length > 0) { + const finalisedStates = await Promise.all( + inputChains.map((chainId) => isInputChainFinalised(chainId, orderContainer)) + ); + allFinalised = finalisedStates.every(Boolean); + } + + return { + allFilled, + allValidated, + allFinalised + }; + } catch (error) { + console.warn("progress checks failed", error); + return { + allFilled: false, + allValidated: false, + allFinalised: false + }; + } } diff --git a/src/lib/libraries/intentExecution.ts b/src/lib/libraries/intentExecution.ts index 1c95197..c09e07f 100644 --- a/src/lib/libraries/intentExecution.ts +++ b/src/lib/libraries/intentExecution.ts @@ -5,13 +5,13 @@ import { MULTICHAIN_SETTLER_ESCROW_ABI } from "$lib/abi/multichain_escrow"; import { SETTLER_ESCROW_ABI } from "$lib/abi/escrow"; import { SETTLER_COMPACT_ABI } from "$lib/abi/settlercompact"; import { - COMPACT, - INPUT_SETTLER_COMPACT_LIFI, - INPUT_SETTLER_ESCROW_LIFI, - MULTICHAIN_INPUT_SETTLER_COMPACT, - MULTICHAIN_INPUT_SETTLER_ESCROW, - getChain, - type WC + COMPACT, + INPUT_SETTLER_COMPACT_LIFI, + INPUT_SETTLER_ESCROW_LIFI, + MULTICHAIN_INPUT_SETTLER_COMPACT, + MULTICHAIN_INPUT_SETTLER_ESCROW, + getChain, + type WC } from "$lib/config"; import { compact_type_hash } from "@lifi/intent"; import { addressToBytes32 } from "@lifi/intent"; @@ -22,172 +22,172 @@ import type { TypedDataSigner } from "@lifi/intent"; import { switchWalletChain } from "$lib/utils/walletClientRuntime"; function combineSignatures(signatures: { - sponsorSignature: Signature | NoSignature; - allocatorSignature: Signature | NoSignature; + sponsorSignature: Signature | NoSignature; + allocatorSignature: Signature | NoSignature; }) { - const { sponsorSignature, allocatorSignature } = signatures; - return encodeAbiParameters(parseAbiParameters(["bytes", "bytes"]), [ - sponsorSignature.payload ?? "0x", - allocatorSignature.payload - ]); + const { sponsorSignature, allocatorSignature } = signatures; + return encodeAbiParameters(parseAbiParameters(["bytes", "bytes"]), [ + sponsorSignature.payload ?? "0x", + allocatorSignature.payload + ]); } export function signIntentCompact( - intent: StandardOrderIntent | MultichainOrderIntent, - account: `0x${string}`, - walletClient: WC + intent: StandardOrderIntent | MultichainOrderIntent, + account: `0x${string}`, + walletClient: WC ): Promise<`0x${string}`> { - const signer = walletClient as unknown as TypedDataSigner; - if (intent instanceof StandardOrderIntent) { - const order = intent.asOrder(); - return signStandardCompact(account, signer, order.originChainId, intent.asBatchCompact()); - } - const order = intent.asOrder(); - return signMultichainCompact( - account, - signer, - order.inputs[0].chainId, - intent.asMultichainBatchCompact() - ); + const signer = walletClient as unknown as TypedDataSigner; + if (intent instanceof StandardOrderIntent) { + const order = intent.asOrder(); + return signStandardCompact(account, signer, order.originChainId, intent.asBatchCompact()); + } + const order = intent.asOrder(); + return signMultichainCompact( + account, + signer, + order.inputs[0].chainId, + intent.asMultichainBatchCompact() + ); } export async function depositAndRegisterCompact( - intent: StandardOrderIntent, - account: `0x${string}`, - walletClient: WC + intent: StandardOrderIntent, + account: `0x${string}`, + walletClient: WC ): Promise<`0x${string}`> { - const order = intent.asOrder(); - const chain = getChain(order.originChainId); - return walletClient.writeContract({ - chain, - account, - address: COMPACT, - abi: COMPACT_ABI, - functionName: "batchDepositAndRegisterMultiple", - args: [order.inputs, [[intent.compactClaimHash(), compact_type_hash]]] - }); + const order = intent.asOrder(); + const chain = getChain(order.originChainId); + return walletClient.writeContract({ + chain, + account, + address: COMPACT, + abi: COMPACT_ABI, + functionName: "batchDepositAndRegisterMultiple", + args: [order.inputs, [[intent.compactClaimHash(), compact_type_hash]]] + }); } export async function openEscrowIntent( - intent: StandardOrderIntent | MultichainOrderIntent, - account: `0x${string}`, - walletClient: WC + intent: StandardOrderIntent | MultichainOrderIntent, + account: `0x${string}`, + walletClient: WC ): Promise<`0x${string}`[]> { - if (intent instanceof StandardOrderIntent) { - const order = intent.asOrder(); - await switchWalletChain(walletClient, Number(order.originChainId)); - const chain = getChain(order.originChainId); - return [ - await walletClient.writeContract({ - chain, - account, - address: INPUT_SETTLER_ESCROW_LIFI, - abi: SETTLER_ESCROW_ABI, - functionName: "open", - args: [order] - }) - ]; - } + if (intent instanceof StandardOrderIntent) { + const order = intent.asOrder(); + await switchWalletChain(walletClient, Number(order.originChainId)); + const chain = getChain(order.originChainId); + return [ + await walletClient.writeContract({ + chain, + account, + address: INPUT_SETTLER_ESCROW_LIFI, + abi: SETTLER_ESCROW_ABI, + functionName: "open", + args: [order] + }) + ]; + } - const components = intent.asComponents(); - const results: `0x${string}`[] = []; - for (const { chainId, orderComponent } of components) { - const chain = getChain(chainId); - await switchWalletChain(walletClient, chain.id); - results.push( - await walletClient.writeContract({ - chain, - account, - address: intent.inputSettler, - abi: MULTICHAIN_SETTLER_ESCROW_ABI, - functionName: "open", - args: [orderComponent] - }) - ); - } - return results; + const components = intent.asComponents(); + const results: `0x${string}`[] = []; + for (const { chainId, orderComponent } of components) { + const chain = getChain(chainId); + await switchWalletChain(walletClient, chain.id); + results.push( + await walletClient.writeContract({ + chain, + account, + address: intent.inputSettler, + abi: MULTICHAIN_SETTLER_ESCROW_ABI, + functionName: "open", + args: [orderComponent] + }) + ); + } + return results; } export async function finaliseIntent(options: { - intent: StandardOrderIntent | MultichainOrderIntent; - sourceChainId: number | bigint; - account: `0x${string}`; - walletClient: WC; - solveParams: { timestamp: number; solver: `0x${string}` }[]; - signatures: { - sponsorSignature: Signature | NoSignature; - allocatorSignature: Signature | NoSignature; - }; + intent: StandardOrderIntent | MultichainOrderIntent; + sourceChainId: number | bigint; + account: `0x${string}`; + walletClient: WC; + solveParams: { timestamp: number; solver: `0x${string}` }[]; + signatures: { + sponsorSignature: Signature | NoSignature; + allocatorSignature: Signature | NoSignature; + }; }) { - const { intent, sourceChainId, account, walletClient, solveParams, signatures } = options; - const actionChain = getChain(sourceChainId); + const { intent, sourceChainId, account, walletClient, solveParams, signatures } = options; + const actionChain = getChain(sourceChainId); - if (intent instanceof StandardOrderIntent) { - const order = intent.asOrder(); - if (actionChain.id !== Number(order.originChainId)) { - throw new Error( - `Origin chain id and action ID does not match: ${order.originChainId}, ${actionChain.id}` - ); - } - if (intent.inputSettler.toLowerCase() === INPUT_SETTLER_ESCROW_LIFI.toLowerCase()) { - return walletClient.writeContract({ - chain: actionChain, - account, - address: intent.inputSettler, - abi: SETTLER_ESCROW_ABI, - functionName: "finalise", - args: [order, solveParams, addressToBytes32(account), "0x"] - }); - } - if (intent.inputSettler.toLowerCase() === INPUT_SETTLER_COMPACT_LIFI.toLowerCase()) { - const combinedSignatures = combineSignatures(signatures); - return walletClient.writeContract({ - chain: actionChain, - account, - address: intent.inputSettler, - abi: SETTLER_COMPACT_ABI, - functionName: "finalise", - args: [order, combinedSignatures, solveParams, addressToBytes32(account), "0x"] - }); - } - throw new Error(`Could not detect settler type ${intent.inputSettler}`); - } + if (intent instanceof StandardOrderIntent) { + const order = intent.asOrder(); + if (actionChain.id !== Number(order.originChainId)) { + throw new Error( + `Origin chain id and action ID does not match: ${order.originChainId}, ${actionChain.id}` + ); + } + if (intent.inputSettler.toLowerCase() === INPUT_SETTLER_ESCROW_LIFI.toLowerCase()) { + return walletClient.writeContract({ + chain: actionChain, + account, + address: intent.inputSettler, + abi: SETTLER_ESCROW_ABI, + functionName: "finalise", + args: [order, solveParams, addressToBytes32(account), "0x"] + }); + } + if (intent.inputSettler.toLowerCase() === INPUT_SETTLER_COMPACT_LIFI.toLowerCase()) { + const combinedSignatures = combineSignatures(signatures); + return walletClient.writeContract({ + chain: actionChain, + account, + address: intent.inputSettler, + abi: SETTLER_COMPACT_ABI, + functionName: "finalise", + args: [order, combinedSignatures, solveParams, addressToBytes32(account), "0x"] + }); + } + throw new Error(`Could not detect settler type ${intent.inputSettler}`); + } - const inputChainIds = intent.inputChains().map((v) => Number(v)); - if (!inputChainIds.includes(actionChain.id)) { - throw new Error( - `Action chain must be one of input chains for finalise: ${inputChainIds}, action=${actionChain.id}` - ); - } - const components = intent.asComponents().filter((c) => Number(c.chainId) === actionChain.id); - if (components.length === 0) { - throw new Error(`No multichain order component found for action chain ${actionChain.id}.`); - } + const inputChainIds = intent.inputChains().map((v) => Number(v)); + if (!inputChainIds.includes(actionChain.id)) { + throw new Error( + `Action chain must be one of input chains for finalise: ${inputChainIds}, action=${actionChain.id}` + ); + } + const components = intent.asComponents().filter((c) => Number(c.chainId) === actionChain.id); + if (components.length === 0) { + throw new Error(`No multichain order component found for action chain ${actionChain.id}.`); + } - for (const { orderComponent } of components) { - if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_ESCROW.toLowerCase()) { - return walletClient.writeContract({ - chain: actionChain, - account, - address: intent.inputSettler, - abi: MULTICHAIN_SETTLER_ESCROW_ABI, - functionName: "finalise", - args: [orderComponent, solveParams, addressToBytes32(account), "0x"] - }); - } - if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_COMPACT.toLowerCase()) { - const combinedSignatures = combineSignatures(signatures); - return walletClient.writeContract({ - chain: actionChain, - account, - address: intent.inputSettler, - abi: MULTICHAIN_SETTLER_COMPACT_ABI, - functionName: "finalise", - args: [orderComponent, combinedSignatures, solveParams, addressToBytes32(account), "0x"] - }); - } - throw new Error(`Could not detect settler type ${intent.inputSettler}`); - } + for (const { orderComponent } of components) { + if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_ESCROW.toLowerCase()) { + return walletClient.writeContract({ + chain: actionChain, + account, + address: intent.inputSettler, + abi: MULTICHAIN_SETTLER_ESCROW_ABI, + functionName: "finalise", + args: [orderComponent, solveParams, addressToBytes32(account), "0x"] + }); + } + if (intent.inputSettler.toLowerCase() === MULTICHAIN_INPUT_SETTLER_COMPACT.toLowerCase()) { + const combinedSignatures = combineSignatures(signatures); + return walletClient.writeContract({ + chain: actionChain, + account, + address: intent.inputSettler, + abi: MULTICHAIN_SETTLER_COMPACT_ABI, + functionName: "finalise", + args: [orderComponent, combinedSignatures, solveParams, addressToBytes32(account), "0x"] + }); + } + throw new Error(`Could not detect settler type ${intent.inputSettler}`); + } - throw new Error(`Failed to finalise multichain order on chain ${actionChain.id}.`); + throw new Error(`Failed to finalise multichain order on chain ${actionChain.id}.`); } diff --git a/src/lib/libraries/intentFactory.ts b/src/lib/libraries/intentFactory.ts index 68ef7cf..5e9ccf2 100644 --- a/src/lib/libraries/intentFactory.ts +++ b/src/lib/libraries/intentFactory.ts @@ -1,20 +1,20 @@ import { - getChain, - getClient, - INPUT_SETTLER_COMPACT_LIFI, - INPUT_SETTLER_ESCROW_LIFI, - MULTICHAIN_INPUT_SETTLER_ESCROW, - type WC + getChain, + getClient, + INPUT_SETTLER_COMPACT_LIFI, + INPUT_SETTLER_ESCROW_LIFI, + MULTICHAIN_INPUT_SETTLER_ESCROW, + type WC } from "$lib/config"; import { encodePacked, maxUint256 } from "viem"; import type { - CreateIntentOptions, - TokenContext, - MultichainOrder, - NoSignature, - OrderContainer, - Signature, - StandardOrder + CreateIntentOptions, + TokenContext, + MultichainOrder, + NoSignature, + OrderContainer, + Signature, + StandardOrder } from "@lifi/intent"; import type { AppCreateIntentOptions, AppTokenContext } from "$lib/appTypes"; import { ERC20_ABI } from "$lib/abi/erc20"; @@ -28,283 +28,283 @@ const SAME_CHAIN_DURATION_SECONDS = 10 * 60; // 10 minutes const SAME_CHAIN_EXCLUSIVITY_SECONDS = 12 * 3; // 36 seconds function applySameChainTimings(intent: Intent): void { - if (!intent.isSameChain()) return; - (intent as any).expiry = SAME_CHAIN_DURATION_SECONDS; - (intent as any).fillDeadline = SAME_CHAIN_DURATION_SECONDS; + if (!intent.isSameChain()) return; + (intent as any).expiry = SAME_CHAIN_DURATION_SECONDS; + (intent as any).fillDeadline = SAME_CHAIN_DURATION_SECONDS; } function applyExclusivityOverride( - orderIntent: ReturnType, - exclusiveFor: string | undefined, - isSameChain: boolean + orderIntent: ReturnType, + exclusiveFor: string | undefined, + isSameChain: boolean ): void { - if (!isSameChain || !exclusiveFor) return; - const order = orderIntent.asOrder() as StandardOrder; - const currentTime = Math.floor(Date.now() / 1000); - const paddedExclusiveFor = - `0x${exclusiveFor.replace("0x", "").padStart(64, "0")}` as `0x${string}`; - const newContext = encodePacked( - ["bytes1", "bytes32", "uint32"], - ["0xe0", paddedExclusiveFor, currentTime + SAME_CHAIN_EXCLUSIVITY_SECONDS] - ); - for (const output of order.outputs) { - if (output.context !== "0x") { - (output as any).context = newContext; - } - } + if (!isSameChain || !exclusiveFor) return; + const order = orderIntent.asOrder() as StandardOrder; + const currentTime = Math.floor(Date.now() / 1000); + const paddedExclusiveFor = + `0x${exclusiveFor.replace("0x", "").padStart(64, "0")}` as `0x${string}`; + const newContext = encodePacked( + ["bytes1", "bytes32", "uint32"], + ["0xe0", paddedExclusiveFor, currentTime + SAME_CHAIN_EXCLUSIVITY_SECONDS] + ); + for (const output of order.outputs) { + if (output.context !== "0x") { + (output as any).context = newContext; + } + } } function toCoreTokenContext(input: AppTokenContext): TokenContext { - return { - token: { - address: input.token.address, - name: input.token.name, - chainId: BigInt(input.token.chainId), - decimals: input.token.decimals - }, - amount: input.amount - }; + return { + token: { + address: input.token.address, + name: input.token.name, + chainId: BigInt(input.token.chainId), + decimals: input.token.decimals + }, + amount: input.amount + }; } function toCoreCreateIntentOptions(opts: AppCreateIntentOptions): CreateIntentOptions { - const account = opts.account(); - if (opts.lock.type === "compact") { - return { - exclusiveFor: opts.exclusiveFor, - inputTokens: opts.inputTokens.map(toCoreTokenContext), - outputTokens: opts.outputTokens.map(toCoreTokenContext), - verifier: opts.verifier, - account, - lock: { - type: "compact", - resetPeriod: opts.lock.resetPeriod, - allocatorId: opts.lock.allocatorId - } - }; - } - - return { - exclusiveFor: opts.exclusiveFor, - inputTokens: opts.inputTokens.map(toCoreTokenContext), - outputTokens: opts.outputTokens.map(toCoreTokenContext), - verifier: opts.verifier, - account, - lock: { - type: "escrow" - } - }; + const account = opts.account(); + if (opts.lock.type === "compact") { + return { + exclusiveFor: opts.exclusiveFor, + inputTokens: opts.inputTokens.map(toCoreTokenContext), + outputTokens: opts.outputTokens.map(toCoreTokenContext), + verifier: opts.verifier, + account, + lock: { + type: "compact", + resetPeriod: opts.lock.resetPeriod, + allocatorId: opts.lock.allocatorId + } + }; + } + + return { + exclusiveFor: opts.exclusiveFor, + inputTokens: opts.inputTokens.map(toCoreTokenContext), + outputTokens: opts.outputTokens.map(toCoreTokenContext), + verifier: opts.verifier, + account, + lock: { + type: "escrow" + } + }; } /** * @notice Factory class for creating and managing intents. Functions called by integrators. */ export class IntentFactory { - mainnet: boolean; - intentApi: IntentApi; - - walletClient: WC; - - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - - orders: OrderContainer[] = []; - - constructor(options: { - mainnet: boolean; - walletClient: WC; - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - ordersPointer?: OrderContainer[]; - }) { - const { mainnet, walletClient, preHook, postHook, ordersPointer } = options; - this.mainnet = mainnet; - this.intentApi = new IntentApi(mainnet); - this.walletClient = walletClient; - - this.preHook = preHook; - this.postHook = postHook; - - if (ordersPointer) this.orders = ordersPointer; - } - - private saveOrder(options: { - order: StandardOrder | MultichainOrder; - inputSettler: `0x${string}`; - sponsorSignature?: Signature | NoSignature; - allocatorSignature?: Signature | NoSignature; - }) { - const { order, inputSettler, sponsorSignature, allocatorSignature } = options; - - const orderContainer: OrderContainer = { - order, - inputSettler, - sponsorSignature: sponsorSignature ?? { - type: "None", - payload: "0x" - }, - allocatorSignature: allocatorSignature ?? { - type: "None", - payload: "0x" - } - }; - this.orders.push(orderContainer); - store.saveOrderToDb(orderContainer).catch((e) => console.warn("saveOrderToDb error", e)); - } - - compact(opts: AppCreateIntentOptions) { - return async () => { - const { account, inputTokens } = opts; - const inputChain = inputTokens[0].token.chainId; - if (this.preHook) await this.preHook(inputChain); - const intentInstance = new Intent(toCoreCreateIntentOptions(opts), intentDeps); - applySameChainTimings(intentInstance); - const sameChain = intentInstance.isSameChain(); - const intent = intentInstance.order(); - applyExclusivityOverride(intent, opts.exclusiveFor, sameChain); - - const sponsorSignature = await signIntentCompact(intent, account(), this.walletClient); - - console.log({ - order: intent.asOrder(), - sponsorSignature - }); - - this.saveOrder({ - order: intent.asOrder(), - inputSettler: intent.inputSettler, - sponsorSignature: { - type: "ECDSA", - payload: sponsorSignature - } - }); - - const order = intent.asOrder(); - if (!("originChainId" in order)) { - throw new Error("CatalystCompactOrder submission currently supports standard orders."); - } - const signedOrder = await this.intentApi.submitOrder({ - orderType: "CatalystCompactOrder", - order, - inputSettler: INPUT_SETTLER_COMPACT_LIFI, - sponsorSignature, - allocatorSignature: "0x" - }); - console.log("signedOrder", signedOrder); - - if (this.postHook) await this.postHook(); - }; - } - - compactDepositAndRegister(opts: AppCreateIntentOptions) { - return async () => { - const { inputTokens, account } = opts; - const intentInstance2 = new Intent(toCoreCreateIntentOptions(opts), intentDeps); - applySameChainTimings(intentInstance2); - const sameChain2 = intentInstance2.isSameChain(); - const intent = intentInstance2.singlechain(); - applyExclusivityOverride(intent, opts.exclusiveFor, sameChain2); - - if (this.preHook) await this.preHook(inputTokens[0].token.chainId); - - let transactionHash = await depositAndRegisterCompact(intent, account(), this.walletClient); - - const receipt = await getClient(inputTokens[0].token.chainId).waitForTransactionReceipt({ - hash: transactionHash - }); - - // If you use another allocator than polymer, there should be logic for potentially getting the allocator signature here. - // You may consider getting the allocator signature before you call depositAndRegisterCompact - - // Add the order to our local order list. - this.saveOrder({ - order: intent.asOrder(), - inputSettler: INPUT_SETTLER_COMPACT_LIFI - }); - - // Submit the order to the intent-api. - const unsignedOrder = await this.intentApi.submitOrder({ - orderType: "CatalystCompactOrder", - order: intent.asOrder(), - inputSettler: INPUT_SETTLER_COMPACT_LIFI, - compactRegistrationTxHash: transactionHash - }); - - console.log("unsignedOrder", unsignedOrder); - if (this.postHook) await this.postHook(); - }; - } - - openIntent(opts: AppCreateIntentOptions) { - return async () => { - const { inputTokens, account } = opts; - const intentInstance3 = new Intent(toCoreCreateIntentOptions(opts), intentDeps); - applySameChainTimings(intentInstance3); - const sameChain3 = intentInstance3.isSameChain(); - const intent = intentInstance3.order(); - applyExclusivityOverride(intent, opts.exclusiveFor, sameChain3); - - const inputChain = inputTokens[0].token.chainId; - if (this.preHook) await this.preHook(inputChain); - - // Execute the open. - const transactionHashes = await openEscrowIntent(intent, account(), this.walletClient); - console.log({ tsh: transactionHashes }); - - // for (const hash of transactionHashes) { - // await clients[inputChain].waitForTransactionReceipt({ - // hash: await hash - // }); - // } - - if (this.postHook) await this.postHook(); - - this.saveOrder({ - order: intent.asOrder(), - inputSettler: store.inputSettler - }); - - return transactionHashes; - }; - } + mainnet: boolean; + intentApi: IntentApi; + + walletClient: WC; + + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + + orders: OrderContainer[] = []; + + constructor(options: { + mainnet: boolean; + walletClient: WC; + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + ordersPointer?: OrderContainer[]; + }) { + const { mainnet, walletClient, preHook, postHook, ordersPointer } = options; + this.mainnet = mainnet; + this.intentApi = new IntentApi(mainnet); + this.walletClient = walletClient; + + this.preHook = preHook; + this.postHook = postHook; + + if (ordersPointer) this.orders = ordersPointer; + } + + private saveOrder(options: { + order: StandardOrder | MultichainOrder; + inputSettler: `0x${string}`; + sponsorSignature?: Signature | NoSignature; + allocatorSignature?: Signature | NoSignature; + }) { + const { order, inputSettler, sponsorSignature, allocatorSignature } = options; + + const orderContainer: OrderContainer = { + order, + inputSettler, + sponsorSignature: sponsorSignature ?? { + type: "None", + payload: "0x" + }, + allocatorSignature: allocatorSignature ?? { + type: "None", + payload: "0x" + } + }; + this.orders.push(orderContainer); + store.saveOrderToDb(orderContainer).catch((e) => console.warn("saveOrderToDb error", e)); + } + + compact(opts: AppCreateIntentOptions) { + return async () => { + const { account, inputTokens } = opts; + const inputChain = inputTokens[0].token.chainId; + if (this.preHook) await this.preHook(inputChain); + const intentInstance = new Intent(toCoreCreateIntentOptions(opts), intentDeps); + applySameChainTimings(intentInstance); + const sameChain = intentInstance.isSameChain(); + const intent = intentInstance.order(); + applyExclusivityOverride(intent, opts.exclusiveFor, sameChain); + + const sponsorSignature = await signIntentCompact(intent, account(), this.walletClient); + + console.log({ + order: intent.asOrder(), + sponsorSignature + }); + + this.saveOrder({ + order: intent.asOrder(), + inputSettler: intent.inputSettler, + sponsorSignature: { + type: "ECDSA", + payload: sponsorSignature + } + }); + + const order = intent.asOrder(); + if (!("originChainId" in order)) { + throw new Error("CatalystCompactOrder submission currently supports standard orders."); + } + const signedOrder = await this.intentApi.submitOrder({ + orderType: "CatalystCompactOrder", + order, + inputSettler: INPUT_SETTLER_COMPACT_LIFI, + sponsorSignature, + allocatorSignature: "0x" + }); + console.log("signedOrder", signedOrder); + + if (this.postHook) await this.postHook(); + }; + } + + compactDepositAndRegister(opts: AppCreateIntentOptions) { + return async () => { + const { inputTokens, account } = opts; + const intentInstance2 = new Intent(toCoreCreateIntentOptions(opts), intentDeps); + applySameChainTimings(intentInstance2); + const sameChain2 = intentInstance2.isSameChain(); + const intent = intentInstance2.singlechain(); + applyExclusivityOverride(intent, opts.exclusiveFor, sameChain2); + + if (this.preHook) await this.preHook(inputTokens[0].token.chainId); + + let transactionHash = await depositAndRegisterCompact(intent, account(), this.walletClient); + + const receipt = await getClient(inputTokens[0].token.chainId).waitForTransactionReceipt({ + hash: transactionHash + }); + + // If you use another allocator than polymer, there should be logic for potentially getting the allocator signature here. + // You may consider getting the allocator signature before you call depositAndRegisterCompact + + // Add the order to our local order list. + this.saveOrder({ + order: intent.asOrder(), + inputSettler: INPUT_SETTLER_COMPACT_LIFI + }); + + // Submit the order to the intent-api. + const unsignedOrder = await this.intentApi.submitOrder({ + orderType: "CatalystCompactOrder", + order: intent.asOrder(), + inputSettler: INPUT_SETTLER_COMPACT_LIFI, + compactRegistrationTxHash: transactionHash + }); + + console.log("unsignedOrder", unsignedOrder); + if (this.postHook) await this.postHook(); + }; + } + + openIntent(opts: AppCreateIntentOptions) { + return async () => { + const { inputTokens, account } = opts; + const intentInstance3 = new Intent(toCoreCreateIntentOptions(opts), intentDeps); + applySameChainTimings(intentInstance3); + const sameChain3 = intentInstance3.isSameChain(); + const intent = intentInstance3.order(); + applyExclusivityOverride(intent, opts.exclusiveFor, sameChain3); + + const inputChain = inputTokens[0].token.chainId; + if (this.preHook) await this.preHook(inputChain); + + // Execute the open. + const transactionHashes = await openEscrowIntent(intent, account(), this.walletClient); + console.log({ tsh: transactionHashes }); + + // for (const hash of transactionHashes) { + // await clients[inputChain].waitForTransactionReceipt({ + // hash: await hash + // }); + // } + + if (this.postHook) await this.postHook(); + + this.saveOrder({ + order: intent.asOrder(), + inputSettler: store.inputSettler + }); + + return transactionHashes; + }; + } } export function escrowApprove( - walletClient: WC, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - inputTokens: AppTokenContext[]; - account: () => `0x${string}`; - } + walletClient: WC, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + inputTokens: AppTokenContext[]; + account: () => `0x${string}`; + } ) { - return async () => { - const settler = store.multichain ? MULTICHAIN_INPUT_SETTLER_ESCROW : INPUT_SETTLER_ESCROW_LIFI; - - const { preHook, postHook, inputTokens, account } = opts; - for (let i = 0; i < inputTokens.length; ++i) { - const { token, amount } = inputTokens[i]; - if (preHook) await preHook(token.chainId); - const publicClient = getClient(token.chainId); - const currentAllowance = await publicClient.readContract({ - address: token.address, - abi: ERC20_ABI, - functionName: "allowance", - args: [account(), settler] - }); - if (currentAllowance >= amount) continue; - const transactionHash = walletClient.writeContract({ - chain: getChain(token.chainId), - account: account(), - address: token.address, - abi: ERC20_ABI, - functionName: "approve", - args: [settler, maxUint256] - }); - - await publicClient.waitForTransactionReceipt({ - hash: await transactionHash - }); - } - if (postHook) await postHook(); - }; + return async () => { + const settler = store.multichain ? MULTICHAIN_INPUT_SETTLER_ESCROW : INPUT_SETTLER_ESCROW_LIFI; + + const { preHook, postHook, inputTokens, account } = opts; + for (let i = 0; i < inputTokens.length; ++i) { + const { token, amount } = inputTokens[i]; + if (preHook) await preHook(token.chainId); + const publicClient = getClient(token.chainId); + const currentAllowance = await publicClient.readContract({ + address: token.address, + abi: ERC20_ABI, + functionName: "allowance", + args: [account(), settler] + }); + if (currentAllowance >= amount) continue; + const transactionHash = walletClient.writeContract({ + chain: getChain(token.chainId), + account: account(), + address: token.address, + abi: ERC20_ABI, + functionName: "approve", + args: [settler, maxUint256] + }); + + await publicClient.waitForTransactionReceipt({ + hash: await transactionHash + }); + } + if (postHook) await postHook(); + }; } diff --git a/src/lib/libraries/intentList.ts b/src/lib/libraries/intentList.ts index 4689d51..d0c3d54 100644 --- a/src/lib/libraries/intentList.ts +++ b/src/lib/libraries/intentList.ts @@ -1,11 +1,11 @@ import { - formatTokenAmount, - getChainName, - getCoin, - INPUT_SETTLER_ESCROW_LIFI, - INPUT_SETTLER_COMPACT_LIFI, - MULTICHAIN_INPUT_SETTLER_ESCROW, - MULTICHAIN_INPUT_SETTLER_COMPACT + formatTokenAmount, + getChainName, + getCoin, + INPUT_SETTLER_ESCROW_LIFI, + INPUT_SETTLER_COMPACT_LIFI, + MULTICHAIN_INPUT_SETTLER_ESCROW, + MULTICHAIN_INPUT_SETTLER_COMPACT } from "../config"; import { orderToIntent } from "@lifi/intent"; import { bytes32ToAddress, idToToken } from "@lifi/intent"; @@ -14,264 +14,264 @@ import { validateOrderContainerWithReason } from "@lifi/intent"; import { orderValidationDeps } from "./coreDeps"; export type Chip = { - key: string; - text: string; + key: string; + text: string; }; export type Status = "active" | "expiring" | "expired"; export type ChainScope = "singlechain" | "multichain" | "samechain"; export type BaseIntentRow = { - orderContainer: OrderContainer; - orderId: string; - orderIdShort: string; - userShort: string; - fillDeadline: number; - inputCount: number; - outputCount: number; - chainScope: ChainScope; - chainScopeBadge: string; - inputSchemeBadge?: string; - orderTypeBadge?: string; - exclusiveForAddress?: string; - exclusiveUntil?: number; - inputChips: Chip[]; - inputOverflow: number; - outputChips: Chip[]; - outputOverflow: number; - validationPassed: boolean; - validationReason: string; + orderContainer: OrderContainer; + orderId: string; + orderIdShort: string; + userShort: string; + fillDeadline: number; + inputCount: number; + outputCount: number; + chainScope: ChainScope; + chainScopeBadge: string; + inputSchemeBadge?: string; + orderTypeBadge?: string; + exclusiveForAddress?: string; + exclusiveUntil?: number; + inputChips: Chip[]; + inputOverflow: number; + outputChips: Chip[]; + outputOverflow: number; + validationPassed: boolean; + validationReason: string; }; export type TimedIntentRow = BaseIntentRow & { - status: Status; - secondsToDeadline: number; - protocolBadges: string[]; + status: Status; + secondsToDeadline: number; + protocolBadges: string[]; }; export const EXPIRING_THRESHOLD_SECONDS = 5 * 60; export const MAX_CHIPS_PER_SIDE = 2; function flattenInputs(inputs: { chainId: bigint; inputs: [bigint, bigint][] }[]) { - return inputs.flatMap((chainInput) => { - return chainInput.inputs.map((input) => ({ - chainId: chainInput.chainId, - input - })); - }); + return inputs.flatMap((chainInput) => { + return chainInput.inputs.map((input) => ({ + chainId: chainInput.chainId, + input + })); + }); } function safeChainName(chainId: bigint): string | undefined { - try { - return getChainName(chainId); - } catch { - return undefined; - } + try { + return getChainName(chainId); + } catch { + return undefined; + } } function shortAddress(value: string, start = 6, end = 4) { - if (value.length <= start + end) return value; - return `${value.slice(0, start)}...${value.slice(-end)}`; + if (value.length <= start + end) return value; + return `${value.slice(0, start)}...${value.slice(-end)}`; } function summarizeInput(chainId: bigint, tokenId: bigint, amount: bigint): string { - const tokenAddress = idToToken(tokenId); - const chainName = safeChainName(chainId); - if (!chainName) { - return `${amount.toString()} ${shortAddress(tokenAddress)} on chain-${chainId.toString()}`; - } - const coin = getCoin({ address: tokenAddress, chainId }); - const amountText = formatTokenAmount(amount, coin.decimals); - return `${amountText} ${coin.name.toUpperCase()} on ${chainName}`; + const tokenAddress = idToToken(tokenId); + const chainName = safeChainName(chainId); + if (!chainName) { + return `${amount.toString()} ${shortAddress(tokenAddress)} on chain-${chainId.toString()}`; + } + const coin = getCoin({ address: tokenAddress, chainId }); + const amountText = formatTokenAmount(amount, coin.decimals); + return `${amountText} ${coin.name.toUpperCase()} on ${chainName}`; } function summarizeOutput(chainId: bigint, token: `0x${string}`, amount: bigint): string { - const chainName = safeChainName(chainId); - if (!chainName) { - return `${amount.toString()} ${shortAddress(token)} on chain-${chainId.toString()}`; - } - const coin = getCoin({ address: token, chainId }); - const amountText = formatTokenAmount(amount, coin.decimals); - return `${amountText} ${coin.name.toUpperCase()} on ${chainName}`; + const chainName = safeChainName(chainId); + if (!chainName) { + return `${amount.toString()} ${shortAddress(token)} on chain-${chainId.toString()}`; + } + const coin = getCoin({ address: token, chainId }); + const amountText = formatTokenAmount(amount, coin.decimals); + return `${amountText} ${coin.name.toUpperCase()} on ${chainName}`; } function getInputs(order: StandardOrder | MultichainOrder) { - if ("originChainId" in order) { - return order.inputs.map((input, index) => ({ - key: `s-${index}-${input[0].toString()}`, - text: summarizeInput(order.originChainId, input[0], input[1]) - })); - } - - return flattenInputs(order.inputs).map((input, index) => ({ - key: `m-${index}-${input.input[0].toString()}`, - text: summarizeInput(input.chainId, input.input[0], input.input[1]) - })); + if ("originChainId" in order) { + return order.inputs.map((input, index) => ({ + key: `s-${index}-${input[0].toString()}`, + text: summarizeInput(order.originChainId, input[0], input[1]) + })); + } + + return flattenInputs(order.inputs).map((input, index) => ({ + key: `m-${index}-${input.input[0].toString()}`, + text: summarizeInput(input.chainId, input.input[0], input.input[1]) + })); } function getOutputs(order: StandardOrder | MultichainOrder) { - return order.outputs.map((output, index) => ({ - key: `o-${index}-${output.token}`, - text: summarizeOutput(output.chainId, output.token, output.amount) - })); + return order.outputs.map((output, index) => ({ + key: `o-${index}-${output.token}`, + text: summarizeOutput(output.chainId, output.token, output.amount) + })); } function getChainScope(order: StandardOrder | MultichainOrder): ChainScope { - if (!("originChainId" in order)) return "multichain"; - const isSameChain = order.outputs.every((output) => output.chainId === order.originChainId); - return isSameChain ? "samechain" : "singlechain"; + if (!("originChainId" in order)) return "multichain"; + const isSameChain = order.outputs.every((output) => output.chainId === order.originChainId); + return isSameChain ? "samechain" : "singlechain"; } function toChainScopeBadge(scope: ChainScope) { - if (scope === "samechain") return "SameChain"; - if (scope === "singlechain") return "SingleChain"; - return "MultiChain"; + if (scope === "samechain") return "SameChain"; + if (scope === "singlechain") return "SingleChain"; + return "MultiChain"; } function shortHexAddress(value: `0x${string}`) { - return `${value.slice(0, 6)}...${value.slice(-4)}`; + return `${value.slice(0, 6)}...${value.slice(-4)}`; } function normalizeAddress(value: string) { - return value.toLowerCase(); + return value.toLowerCase(); } function mapInputScheme(inputSettler: `0x${string}`): string | undefined { - const settler = normalizeAddress(inputSettler); - if (settler === normalizeAddress(INPUT_SETTLER_ESCROW_LIFI)) return "Escrow"; - if (settler === normalizeAddress(INPUT_SETTLER_COMPACT_LIFI)) return "Compact"; - if (settler === normalizeAddress(MULTICHAIN_INPUT_SETTLER_ESCROW)) return "MultichainEscrow"; - if (settler === normalizeAddress(MULTICHAIN_INPUT_SETTLER_COMPACT)) return "MultichainCompact"; - return undefined; + const settler = normalizeAddress(inputSettler); + if (settler === normalizeAddress(INPUT_SETTLER_ESCROW_LIFI)) return "Escrow"; + if (settler === normalizeAddress(INPUT_SETTLER_COMPACT_LIFI)) return "Compact"; + if (settler === normalizeAddress(MULTICHAIN_INPUT_SETTLER_ESCROW)) return "MultichainEscrow"; + if (settler === normalizeAddress(MULTICHAIN_INPUT_SETTLER_COMPACT)) return "MultichainCompact"; + return undefined; } function parseContextType(context: `0x${string}`) { - if (context === "0x" || context === "0x00") return "Limit"; - const typeByte = context.slice(2, 4).toLowerCase(); - if (typeByte === "00") return "Limit"; - if (typeByte === "01") return "Dutch"; - if (typeByte === "e0") return "Limit"; - if (typeByte === "e1") return "Dutch"; - return undefined; + if (context === "0x" || context === "0x00") return "Limit"; + const typeByte = context.slice(2, 4).toLowerCase(); + if (typeByte === "00") return "Limit"; + if (typeByte === "01") return "Dutch"; + if (typeByte === "e0") return "Limit"; + if (typeByte === "e1") return "Dutch"; + return undefined; } function decodeExclusiveFor(context: `0x${string}`): `0x${string}` | undefined { - if (context.length < 2 + 2 + 64) return undefined; - const exclusiveHex = context.slice(4, 68); - try { - return bytes32ToAddress(`0x${exclusiveHex}`); - } catch { - return undefined; - } + if (context.length < 2 + 2 + 64) return undefined; + const exclusiveHex = context.slice(4, 68); + try { + return bytes32ToAddress(`0x${exclusiveHex}`); + } catch { + return undefined; + } } type ContextDetails = { - orderTypeBadge?: string; - exclusiveForAddress?: string; - exclusiveUntil?: number; + orderTypeBadge?: string; + exclusiveForAddress?: string; + exclusiveUntil?: number; }; function getContextDetails(orderContainer: OrderContainer): ContextDetails { - const order = orderContainer.order; - const details: ContextDetails = {}; + const order = orderContainer.order; + const details: ContextDetails = {}; - const contexts = order.outputs.map((o) => o.context); - const firstContext = contexts[0]; - const allContextsMatch = contexts.every((c) => c === firstContext); - if (!firstContext || !allContextsMatch) return details; + const contexts = order.outputs.map((o) => o.context); + const firstContext = contexts[0]; + const allContextsMatch = contexts.every((c) => c === firstContext); + if (!firstContext || !allContextsMatch) return details; - details.orderTypeBadge = parseContextType(firstContext); + details.orderTypeBadge = parseContextType(firstContext); - const typeByte = firstContext.slice(2, 4).toLowerCase(); - const isExclusive = typeByte === "e0" || typeByte === "e1"; - if (!isExclusive) return details; + const typeByte = firstContext.slice(2, 4).toLowerCase(); + const isExclusive = typeByte === "e0" || typeByte === "e1"; + if (!isExclusive) return details; - const exclusiveFor = decodeExclusiveFor(firstContext); - if (exclusiveFor) details.exclusiveForAddress = shortHexAddress(exclusiveFor); + const exclusiveFor = decodeExclusiveFor(firstContext); + if (exclusiveFor) details.exclusiveForAddress = shortHexAddress(exclusiveFor); - // bytes1 + bytes32 + uint32 (big-endian) - if (firstContext.length >= 76) { - const untilHex = firstContext.slice(68, 76); - const until = Number.parseInt(untilHex, 16); - if (!Number.isNaN(until)) details.exclusiveUntil = until; - } + // bytes1 + bytes32 + uint32 (big-endian) + if (firstContext.length >= 76) { + const untilHex = firstContext.slice(68, 76); + const until = Number.parseInt(untilHex, 16); + if (!Number.isNaN(until)) details.exclusiveUntil = until; + } - return details; + return details; } export function buildBaseIntentRow(orderContainer: OrderContainer): BaseIntentRow { - const order = orderContainer.order; - const orderId = orderToIntent(orderContainer).orderId(); - const inputChipsRaw = getInputs(order); - const outputChipsRaw = getOutputs(order); - const chainScope = getChainScope(order); - const contextDetails = getContextDetails(orderContainer); - - const validation = validateOrderContainerWithReason({ - orderContainer, - deps: orderValidationDeps - }); - - return { - orderContainer, - orderId, - orderIdShort: shortAddress(orderId, 10, 4), - userShort: shortAddress(order.user, 8, 4), - fillDeadline: order.fillDeadline, - inputCount: inputChipsRaw.length, - outputCount: outputChipsRaw.length, - chainScope, - chainScopeBadge: toChainScopeBadge(chainScope), - inputSchemeBadge: mapInputScheme(orderContainer.inputSettler), - orderTypeBadge: contextDetails.orderTypeBadge, - exclusiveForAddress: contextDetails.exclusiveForAddress, - exclusiveUntil: contextDetails.exclusiveUntil, - inputChips: inputChipsRaw.slice(0, MAX_CHIPS_PER_SIDE), - inputOverflow: Math.max(0, inputChipsRaw.length - MAX_CHIPS_PER_SIDE), - outputChips: outputChipsRaw.slice(0, MAX_CHIPS_PER_SIDE), - outputOverflow: Math.max(0, outputChipsRaw.length - MAX_CHIPS_PER_SIDE), - validationPassed: validation.passed, - validationReason: validation.reason - }; + const order = orderContainer.order; + const orderId = orderToIntent(orderContainer).orderId(); + const inputChipsRaw = getInputs(order); + const outputChipsRaw = getOutputs(order); + const chainScope = getChainScope(order); + const contextDetails = getContextDetails(orderContainer); + + const validation = validateOrderContainerWithReason({ + orderContainer, + deps: orderValidationDeps + }); + + return { + orderContainer, + orderId, + orderIdShort: shortAddress(orderId, 10, 4), + userShort: shortAddress(order.user, 8, 4), + fillDeadline: order.fillDeadline, + inputCount: inputChipsRaw.length, + outputCount: outputChipsRaw.length, + chainScope, + chainScopeBadge: toChainScopeBadge(chainScope), + inputSchemeBadge: mapInputScheme(orderContainer.inputSettler), + orderTypeBadge: contextDetails.orderTypeBadge, + exclusiveForAddress: contextDetails.exclusiveForAddress, + exclusiveUntil: contextDetails.exclusiveUntil, + inputChips: inputChipsRaw.slice(0, MAX_CHIPS_PER_SIDE), + inputOverflow: Math.max(0, inputChipsRaw.length - MAX_CHIPS_PER_SIDE), + outputChips: outputChipsRaw.slice(0, MAX_CHIPS_PER_SIDE), + outputOverflow: Math.max(0, outputChipsRaw.length - MAX_CHIPS_PER_SIDE), + validationPassed: validation.passed, + validationReason: validation.reason + }; } export function withTiming(baseRow: BaseIntentRow, nowSeconds: number): TimedIntentRow { - const secondsToDeadline = baseRow.fillDeadline - nowSeconds; - const status: Status = - secondsToDeadline <= 0 - ? "expired" - : secondsToDeadline <= EXPIRING_THRESHOLD_SECONDS - ? "expiring" - : "active"; - - const protocolBadges: string[] = []; - if (baseRow.orderTypeBadge) protocolBadges.push(baseRow.orderTypeBadge); - if (baseRow.exclusiveForAddress) - protocolBadges.push(`Exclusive for ${baseRow.exclusiveForAddress}`); - if (baseRow.exclusiveUntil !== undefined) { - const secondsRemaining = baseRow.exclusiveUntil - nowSeconds; - if (secondsRemaining > 0) { - protocolBadges.push(`Exclusive until ${formatRemaining(secondsRemaining)}`); - } - } - - return { ...baseRow, status, secondsToDeadline, protocolBadges }; + const secondsToDeadline = baseRow.fillDeadline - nowSeconds; + const status: Status = + secondsToDeadline <= 0 + ? "expired" + : secondsToDeadline <= EXPIRING_THRESHOLD_SECONDS + ? "expiring" + : "active"; + + const protocolBadges: string[] = []; + if (baseRow.orderTypeBadge) protocolBadges.push(baseRow.orderTypeBadge); + if (baseRow.exclusiveForAddress) + protocolBadges.push(`Exclusive for ${baseRow.exclusiveForAddress}`); + if (baseRow.exclusiveUntil !== undefined) { + const secondsRemaining = baseRow.exclusiveUntil - nowSeconds; + if (secondsRemaining > 0) { + protocolBadges.push(`Exclusive until ${formatRemaining(secondsRemaining)}`); + } + } + + return { ...baseRow, status, secondsToDeadline, protocolBadges }; } export function formatRelativeDeadline(secondsToDeadline: number) { - const abs = Math.abs(secondsToDeadline); - if (abs < 60) return secondsToDeadline >= 0 ? `in ${abs}s` : `${abs}s ago`; - const minutes = Math.floor(abs / 60); - if (minutes < 60) return secondsToDeadline >= 0 ? `in ${minutes}m` : `${minutes}m ago`; - const hours = Math.floor(minutes / 60); - return secondsToDeadline >= 0 ? `in ${hours}h` : `${hours}h ago`; + const abs = Math.abs(secondsToDeadline); + if (abs < 60) return secondsToDeadline >= 0 ? `in ${abs}s` : `${abs}s ago`; + const minutes = Math.floor(abs / 60); + if (minutes < 60) return secondsToDeadline >= 0 ? `in ${minutes}m` : `${minutes}m ago`; + const hours = Math.floor(minutes / 60); + return secondsToDeadline >= 0 ? `in ${hours}h` : `${hours}h ago`; } export function formatRemaining(secondsToDeadline: number) { - const clamped = Math.max(0, secondsToDeadline); - if (clamped < 60) return `${clamped}s`; - const minutes = Math.floor(clamped / 60); - if (minutes < 60) return `${minutes}m`; - const hours = Math.floor(minutes / 60); - return `${hours}h`; + const clamped = Math.max(0, secondsToDeadline); + if (clamped < 60) return `${clamped}s`; + const minutes = Math.floor(clamped / 60); + if (minutes < 60) return `${minutes}m`; + const hours = Math.floor(minutes / 60); + return `${hours}h`; } diff --git a/src/lib/libraries/rpcCache.ts b/src/lib/libraries/rpcCache.ts index 2790e8b..1167031 100644 --- a/src/lib/libraries/rpcCache.ts +++ b/src/lib/libraries/rpcCache.ts @@ -1,71 +1,71 @@ type CacheEntry = { - value: T; - expiresAt: number; + value: T; + expiresAt: number; }; const cache = new Map>(); const inflight = new Map>(); const stats = { - hits: 0, - misses: 0, - inflightJoins: 0 + hits: 0, + misses: 0, + inflightJoins: 0 }; export function getRpcCacheStats() { - return { ...stats }; + return { ...stats }; } export function clearRpcCache() { - cache.clear(); - inflight.clear(); + cache.clear(); + inflight.clear(); } export function invalidateRpcKey(key: string) { - cache.delete(key); - inflight.delete(key); + cache.delete(key); + inflight.delete(key); } export function invalidateRpcPrefix(prefix: string) { - for (const key of cache.keys()) { - if (key.startsWith(prefix)) cache.delete(key); - } - for (const key of inflight.keys()) { - if (key.startsWith(prefix)) inflight.delete(key); - } + for (const key of cache.keys()) { + if (key.startsWith(prefix)) cache.delete(key); + } + for (const key of inflight.keys()) { + if (key.startsWith(prefix)) inflight.delete(key); + } } export async function getOrFetchRpc( - key: string, - fetcher: () => Promise, - opts: { ttlMs: number; force?: boolean } + key: string, + fetcher: () => Promise, + opts: { ttlMs: number; force?: boolean } ): Promise { - const { ttlMs, force = false } = opts; - const now = Date.now(); + const { ttlMs, force = false } = opts; + const now = Date.now(); - if (!force) { - const cached = cache.get(key) as CacheEntry | undefined; - if (cached && cached.expiresAt > now) { - stats.hits += 1; - return cached.value; - } - const pending = inflight.get(key) as Promise | undefined; - if (pending) { - stats.inflightJoins += 1; - return pending; - } - } + if (!force) { + const cached = cache.get(key) as CacheEntry | undefined; + if (cached && cached.expiresAt > now) { + stats.hits += 1; + return cached.value; + } + const pending = inflight.get(key) as Promise | undefined; + if (pending) { + stats.inflightJoins += 1; + return pending; + } + } - stats.misses += 1; - const request = fetcher() - .then((value) => { - cache.set(key, { value, expiresAt: Date.now() + ttlMs }); - return value; - }) - .finally(() => { - inflight.delete(key); - }); + stats.misses += 1; + const request = fetcher() + .then((value) => { + cache.set(key, { value, expiresAt: Date.now() + ttlMs }); + return value; + }) + .finally(() => { + inflight.delete(key); + }); - inflight.set(key, request); - return request; + inflight.set(key, request); + return request; } diff --git a/src/lib/libraries/solver.ts b/src/lib/libraries/solver.ts index 674ce29..961b7dd 100644 --- a/src/lib/libraries/solver.ts +++ b/src/lib/libraries/solver.ts @@ -15,375 +15,375 @@ import { finaliseIntent } from "./intentExecution"; * @notice Class for solving intents. Functions called by solvers. */ export class Solver { - private static validationInflight = new Map>(); - private static polymerRequestIndexByLog = new Map(); + private static validationInflight = new Map>(); + private static polymerRequestIndexByLog = new Map(); - private static sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); - } + private static sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } - private static async persistReceipt( - chainId: number | bigint, - txHash: `0x${string}`, - receipt: unknown - ) { - try { - await store.saveTransactionReceipt(chainId, txHash, receipt); - } catch (error) { - console.warn("saveTransactionReceipt error", { chainId: Number(chainId), txHash, error }); - } - } + private static async persistReceipt( + chainId: number | bigint, + txHash: `0x${string}`, + receipt: unknown + ) { + try { + await store.saveTransactionReceipt(chainId, txHash, receipt); + } catch (error) { + console.warn("saveTransactionReceipt error", { chainId: Number(chainId), txHash, error }); + } + } - private static async getReceiptCachedOrRpc(chainId: number | bigint, txHash: `0x${string}`) { - const cached = store.getTransactionReceipt(chainId, txHash); - if ( - cached && - typeof cached === "object" && - Array.isArray((cached as { logs?: unknown[] }).logs) && - (cached as { logs?: unknown[] }).logs!.length > 0 - ) - return cached as any; - const receipt = await getClient(chainId).getTransactionReceipt({ hash: txHash }); - await Solver.persistReceipt(chainId, txHash, receipt); - return receipt; - } + private static async getReceiptCachedOrRpc(chainId: number | bigint, txHash: `0x${string}`) { + const cached = store.getTransactionReceipt(chainId, txHash); + if ( + cached && + typeof cached === "object" && + Array.isArray((cached as { logs?: unknown[] }).logs) && + (cached as { logs?: unknown[] }).logs!.length > 0 + ) + return cached as any; + const receipt = await getClient(chainId).getTransactionReceipt({ hash: txHash }); + await Solver.persistReceipt(chainId, txHash, receipt); + return receipt; + } - static fill( - walletClient: WC, - args: { - orderContainer: OrderContainer; - outputs: MandateOutput[]; - }, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - account: () => `0x${string}`; - } - ) { - return async () => { - const { preHook, postHook, account } = opts; - const { - orderContainer: { order, inputSettler }, - outputs - } = args; - const orderId = orderToIntent({ order, inputSettler }).orderId(); + static fill( + walletClient: WC, + args: { + orderContainer: OrderContainer; + outputs: MandateOutput[]; + }, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + account: () => `0x${string}`; + } + ) { + return async () => { + const { preHook, postHook, account } = opts; + const { + orderContainer: { order, inputSettler }, + outputs + } = args; + const orderId = orderToIntent({ order, inputSettler }).orderId(); - const outputChainId = Number(outputs[0].chainId); - const outputChain = getChain(outputChainId); - // Always attempt chain switch before fill, including native-token fills. - if (preHook) await preHook(outputChain.id); - const connectedChainId = await walletClient.getChainId(); - const expectedChainId = outputChain.id; - if (connectedChainId !== expectedChainId) { - throw new Error(`Wallet is on chain ${connectedChainId}, expected ${expectedChainId}`); - } + const outputChainId = Number(outputs[0].chainId); + const outputChain = getChain(outputChainId); + // Always attempt chain switch before fill, including native-token fills. + if (preHook) await preHook(outputChain.id); + const connectedChainId = await walletClient.getChainId(); + const expectedChainId = outputChain.id; + if (connectedChainId !== expectedChainId) { + throw new Error(`Wallet is on chain ${connectedChainId}, expected ${expectedChainId}`); + } - let value = 0n; - for (const output of outputs) { - if (output.token === BYTES32_ZERO) { - value += output.amount; - continue; - } - if (output.chainId != outputs[0].chainId) { - throw new Error("Filling outputs on multiple chains with single fill call not supported"); - } - if (output.settler != outputs[0].settler) { - throw new Error("Different settlers on outputs, not supported"); - } + let value = 0n; + for (const output of outputs) { + if (output.token === BYTES32_ZERO) { + value += output.amount; + continue; + } + if (output.chainId != outputs[0].chainId) { + throw new Error("Filling outputs on multiple chains with single fill call not supported"); + } + if (output.settler != outputs[0].settler) { + throw new Error("Different settlers on outputs, not supported"); + } - // Check allowance & set allowance if needed - const assetAddress = bytes32ToAddress(output.token); - const allowance = await getClient(outputChain.id).readContract({ - address: assetAddress, - abi: ERC20_ABI, - functionName: "allowance", - args: [account(), bytes32ToAddress(output.settler)] - }); - if (BigInt(allowance) < output.amount) { - const approveTransaction = await walletClient.writeContract({ - chain: outputChain, - account: account(), - address: assetAddress, - abi: ERC20_ABI, - functionName: "approve", - args: [bytes32ToAddress(output.settler), maxUint256] - }); - const approveReceipt = await getClient(outputChain.id).waitForTransactionReceipt({ - hash: approveTransaction - }); - await Solver.persistReceipt(outputs[0].chainId, approveTransaction, approveReceipt); - } - } + // Check allowance & set allowance if needed + const assetAddress = bytes32ToAddress(output.token); + const allowance = await getClient(outputChain.id).readContract({ + address: assetAddress, + abi: ERC20_ABI, + functionName: "allowance", + args: [account(), bytes32ToAddress(output.settler)] + }); + if (BigInt(allowance) < output.amount) { + const approveTransaction = await walletClient.writeContract({ + chain: outputChain, + account: account(), + address: assetAddress, + abi: ERC20_ABI, + functionName: "approve", + args: [bytes32ToAddress(output.settler), maxUint256] + }); + const approveReceipt = await getClient(outputChain.id).waitForTransactionReceipt({ + hash: approveTransaction + }); + await Solver.persistReceipt(outputs[0].chainId, approveTransaction, approveReceipt); + } + } - const transactionHash = await walletClient.writeContract({ - chain: outputChain, - account: account(), - address: bytes32ToAddress(outputs[0].settler), - value, - abi: COIN_FILLER_ABI, - functionName: "fillOrderOutputs", - args: [orderId, outputs, order.fillDeadline, addressToBytes32(account())] - }); - const fillReceipt = await getClient(outputChain.id).waitForTransactionReceipt({ - hash: transactionHash - }); - await Solver.persistReceipt(outputs[0].chainId, transactionHash, fillReceipt); - // orderInputs.validate[index] = transactionHash; - if (postHook) await postHook(); - return transactionHash; - }; - } + const transactionHash = await walletClient.writeContract({ + chain: outputChain, + account: account(), + address: bytes32ToAddress(outputs[0].settler), + value, + abi: COIN_FILLER_ABI, + functionName: "fillOrderOutputs", + args: [orderId, outputs, order.fillDeadline, addressToBytes32(account())] + }); + const fillReceipt = await getClient(outputChain.id).waitForTransactionReceipt({ + hash: transactionHash + }); + await Solver.persistReceipt(outputs[0].chainId, transactionHash, fillReceipt); + // orderInputs.validate[index] = transactionHash; + if (postHook) await postHook(); + return transactionHash; + }; + } - static validate( - walletClient: WC, - args: { - output: MandateOutput; - orderContainer: OrderContainer; - fillTransactionHash: string; - sourceChainId: number | bigint; - mainnet: boolean; - }, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - account: () => `0x${string}`; - } - ) { - return async () => { - const { preHook, postHook, account } = opts; - const { - output, - orderContainer: { order }, - fillTransactionHash, - sourceChainId, - mainnet - } = args; - const expectedOutputHash = hashStruct({ - types: compactTypes, - primaryType: "MandateOutput", - data: output - }); - const validationKey = `${Number(sourceChainId)}:${fillTransactionHash}:${expectedOutputHash}`; - const existingValidation = Solver.validationInflight.get(validationKey); - if (existingValidation) return existingValidation; + static validate( + walletClient: WC, + args: { + output: MandateOutput; + orderContainer: OrderContainer; + fillTransactionHash: string; + sourceChainId: number | bigint; + mainnet: boolean; + }, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + account: () => `0x${string}`; + } + ) { + return async () => { + const { preHook, postHook, account } = opts; + const { + output, + orderContainer: { order }, + fillTransactionHash, + sourceChainId, + mainnet + } = args; + const expectedOutputHash = hashStruct({ + types: compactTypes, + primaryType: "MandateOutput", + data: output + }); + const validationKey = `${Number(sourceChainId)}:${fillTransactionHash}:${expectedOutputHash}`; + const existingValidation = Solver.validationInflight.get(validationKey); + if (existingValidation) return existingValidation; - const validationPromise = (async () => { - if ( - !fillTransactionHash || - !fillTransactionHash.startsWith("0x") || - fillTransactionHash.length !== 66 - ) { - throw new Error(`Invalid fill transaction hash: ${fillTransactionHash}`); - } + const validationPromise = (async () => { + if ( + !fillTransactionHash || + !fillTransactionHash.startsWith("0x") || + fillTransactionHash.length !== 66 + ) { + throw new Error(`Invalid fill transaction hash: ${fillTransactionHash}`); + } - // Get the output filled event. - const transactionReceipt = await Solver.getReceiptCachedOrRpc( - output.chainId, - fillTransactionHash as `0x${string}` - ); + // Get the output filled event. + const transactionReceipt = await Solver.getReceiptCachedOrRpc( + output.chainId, + fillTransactionHash as `0x${string}` + ); - const logs = parseEventLogs({ - abi: COIN_FILLER_ABI, - eventName: "OutputFilled", - logs: transactionReceipt.logs - }); - // We need to search through each log until we find one matching our output. - let logIndex = -1; - for (const log of logs) { - const logOutput = log.args.output; - // TODO: Optimise by comparing the dicts. - const logOutputHash = hashStruct({ - types: compactTypes, - primaryType: "MandateOutput", - data: logOutput - }); - if (logOutputHash === expectedOutputHash) { - logIndex = log.logIndex; - break; - } - } - if (logIndex === -1) throw Error(`Could not find matching log`); + const logs = parseEventLogs({ + abi: COIN_FILLER_ABI, + eventName: "OutputFilled", + logs: transactionReceipt.logs + }); + // We need to search through each log until we find one matching our output. + let logIndex = -1; + for (const log of logs) { + const logOutput = log.args.output; + // TODO: Optimise by comparing the dicts. + const logOutputHash = hashStruct({ + types: compactTypes, + primaryType: "MandateOutput", + data: logOutput + }); + if (logOutputHash === expectedOutputHash) { + logIndex = log.logIndex; + break; + } + } + if (logIndex === -1) throw Error(`Could not find matching log`); - if (order.inputOracle === getOracle("polymer", sourceChainId)) { - let proof: string | undefined; - const polymerKey = `${Number(output.chainId)}:${Number(transactionReceipt.blockNumber)}:${Number(logIndex)}`; - let polymerIndex: number | undefined = Solver.polymerRequestIndexByLog.get(polymerKey); - for (const waitMs of [1000, 2000, 4000, 8000]) { - const response = await axios.post( - `/polymer`, - { - srcChainId: Number(output.chainId), - srcBlockNumber: Number(transactionReceipt.blockNumber), - globalLogIndex: Number(logIndex), - polymerIndex, - mainnet: mainnet - }, - { timeout: 15_000 } - ); - const dat = response.data as { - proof: undefined | string; - polymerIndex: number; - }; - polymerIndex = dat.polymerIndex; - if (polymerIndex !== undefined) { - Solver.polymerRequestIndexByLog.set(polymerKey, polymerIndex); - } - if (dat.proof) { - proof = dat.proof; - break; - } - await Solver.sleep(waitMs); - } - if (proof) { - if (preHook) await preHook(Number(sourceChainId)); + if (order.inputOracle === getOracle("polymer", sourceChainId)) { + let proof: string | undefined; + const polymerKey = `${Number(output.chainId)}:${Number(transactionReceipt.blockNumber)}:${Number(logIndex)}`; + let polymerIndex: number | undefined = Solver.polymerRequestIndexByLog.get(polymerKey); + for (const waitMs of [1000, 2000, 4000, 8000]) { + const response = await axios.post( + `/polymer`, + { + srcChainId: Number(output.chainId), + srcBlockNumber: Number(transactionReceipt.blockNumber), + globalLogIndex: Number(logIndex), + polymerIndex, + mainnet: mainnet + }, + { timeout: 15_000 } + ); + const dat = response.data as { + proof: undefined | string; + polymerIndex: number; + }; + polymerIndex = dat.polymerIndex; + if (polymerIndex !== undefined) { + Solver.polymerRequestIndexByLog.set(polymerKey, polymerIndex); + } + if (dat.proof) { + proof = dat.proof; + break; + } + await Solver.sleep(waitMs); + } + if (proof) { + if (preHook) await preHook(Number(sourceChainId)); - const transactionHash = await walletClient.writeContract({ - chain: getChain(sourceChainId), - account: account(), - address: order.inputOracle, - abi: POLYMER_ORACLE_ABI, - functionName: "receiveMessage", - args: [`0x${proof.replace("0x", "")}`] - }); + const transactionHash = await walletClient.writeContract({ + chain: getChain(sourceChainId), + account: account(), + address: order.inputOracle, + abi: POLYMER_ORACLE_ABI, + functionName: "receiveMessage", + args: [`0x${proof.replace("0x", "")}`] + }); - const result = await getClient(sourceChainId).waitForTransactionReceipt({ - hash: transactionHash, - timeout: 120_000, - pollingInterval: 2_000 - }); - await Solver.persistReceipt(sourceChainId, transactionHash, result); - if (postHook) await postHook(); - return result; - } - throw new Error( - `Polymer proof unavailable for output on ${output.chainId.toString()}. Try again after the fill attestation is indexed.` - ); - } else if (order.inputOracle === COIN_FILLER) { - const log = logs.find((log) => log.logIndex === logIndex)!; - if (preHook) await preHook(Number(sourceChainId)); - const transactionHash = await walletClient.writeContract({ - chain: getChain(sourceChainId), - account: account(), - address: order.inputOracle, - abi: COIN_FILLER_ABI, - functionName: "setAttestation", - args: [log.args.orderId, log.args.solver, log.args.timestamp, log.args.output] - }); + const result = await getClient(sourceChainId).waitForTransactionReceipt({ + hash: transactionHash, + timeout: 120_000, + pollingInterval: 2_000 + }); + await Solver.persistReceipt(sourceChainId, transactionHash, result); + if (postHook) await postHook(); + return result; + } + throw new Error( + `Polymer proof unavailable for output on ${output.chainId.toString()}. Try again after the fill attestation is indexed.` + ); + } else if (order.inputOracle === COIN_FILLER) { + const log = logs.find((log) => log.logIndex === logIndex)!; + if (preHook) await preHook(Number(sourceChainId)); + const transactionHash = await walletClient.writeContract({ + chain: getChain(sourceChainId), + account: account(), + address: order.inputOracle, + abi: COIN_FILLER_ABI, + functionName: "setAttestation", + args: [log.args.orderId, log.args.solver, log.args.timestamp, log.args.output] + }); - const result = await getClient(sourceChainId).waitForTransactionReceipt({ - hash: transactionHash, - timeout: 120_000, - pollingInterval: 2_000 - }); - await Solver.persistReceipt(sourceChainId, transactionHash, result); - if (postHook) await postHook(); - return result; - } - throw new Error( - `Unsupported input oracle ${order.inputOracle} for source chain ${Number(sourceChainId)}.` - ); - })(); + const result = await getClient(sourceChainId).waitForTransactionReceipt({ + hash: transactionHash, + timeout: 120_000, + pollingInterval: 2_000 + }); + await Solver.persistReceipt(sourceChainId, transactionHash, result); + if (postHook) await postHook(); + return result; + } + throw new Error( + `Unsupported input oracle ${order.inputOracle} for source chain ${Number(sourceChainId)}.` + ); + })(); - Solver.validationInflight.set(validationKey, validationPromise); - try { - return await validationPromise; - } finally { - Solver.validationInflight.delete(validationKey); - } - }; - } + Solver.validationInflight.set(validationKey, validationPromise); + try { + return await validationPromise; + } finally { + Solver.validationInflight.delete(validationKey); + } + }; + } - static claim( - walletClient: WC, - args: { - orderContainer: OrderContainer; - fillTransactionHashes: string[]; - sourceChainId: number | bigint; - }, - opts: { - preHook?: (chainId: number) => Promise; - postHook?: () => Promise; - account: () => `0x${string}`; - } - ) { - return async () => { - const { preHook, postHook, account } = opts; - const { orderContainer, fillTransactionHashes, sourceChainId } = args; - const { order, inputSettler } = orderContainer; - const intent = orderToIntent({ - inputSettler, - order - }); - if (fillTransactionHashes.length !== order.outputs.length) { - throw new Error( - `Fill transaction hash count (${fillTransactionHashes.length}) does not match output count (${order.outputs.length}).` - ); - } - for (let i = 0; i < fillTransactionHashes.length; i++) { - const hash = fillTransactionHashes[i]; - if (!hash || !hash.startsWith("0x") || hash.length !== 66) { - throw new Error(`Invalid fill tx hash at index ${i}: ${hash}`); - } - } - const transactionReceipts = await Promise.all( - fillTransactionHashes.map((fth, i) => - Solver.getReceiptCachedOrRpc(order.outputs[i].chainId, fth as `0x${string}`) - ) - ); - const blocks = await Promise.all( - transactionReceipts.map((r, i) => { - return getClient(order.outputs[i].chainId).getBlock({ - blockHash: r.blockHash - }); - }) - ); - const fillTimestamps = blocks.map((b) => b.timestamp); + static claim( + walletClient: WC, + args: { + orderContainer: OrderContainer; + fillTransactionHashes: string[]; + sourceChainId: number | bigint; + }, + opts: { + preHook?: (chainId: number) => Promise; + postHook?: () => Promise; + account: () => `0x${string}`; + } + ) { + return async () => { + const { preHook, postHook, account } = opts; + const { orderContainer, fillTransactionHashes, sourceChainId } = args; + const { order, inputSettler } = orderContainer; + const intent = orderToIntent({ + inputSettler, + order + }); + if (fillTransactionHashes.length !== order.outputs.length) { + throw new Error( + `Fill transaction hash count (${fillTransactionHashes.length}) does not match output count (${order.outputs.length}).` + ); + } + for (let i = 0; i < fillTransactionHashes.length; i++) { + const hash = fillTransactionHashes[i]; + if (!hash || !hash.startsWith("0x") || hash.length !== 66) { + throw new Error(`Invalid fill tx hash at index ${i}: ${hash}`); + } + } + const transactionReceipts = await Promise.all( + fillTransactionHashes.map((fth, i) => + Solver.getReceiptCachedOrRpc(order.outputs[i].chainId, fth as `0x${string}`) + ) + ); + const blocks = await Promise.all( + transactionReceipts.map((r, i) => { + return getClient(order.outputs[i].chainId).getBlock({ + blockHash: r.blockHash + }); + }) + ); + const fillTimestamps = blocks.map((b) => b.timestamp); - if (preHook) await preHook(Number(sourceChainId)); - const expectedChainId = Number(sourceChainId); - const connectedChainId = await walletClient.getChainId(); - if (connectedChainId !== expectedChainId) { - throw new Error( - `Wallet is on chain ${connectedChainId}, expected ${expectedChainId} before finalise` - ); - } + if (preHook) await preHook(Number(sourceChainId)); + const expectedChainId = Number(sourceChainId); + const connectedChainId = await walletClient.getChainId(); + if (connectedChainId !== expectedChainId) { + throw new Error( + `Wallet is on chain ${connectedChainId}, expected ${expectedChainId} before finalise` + ); + } - const solveParams = fillTimestamps.map((fillTimestamp) => { - return { - timestamp: Number(fillTimestamp), - solver: addressToBytes32(account()) - }; - }); + const solveParams = fillTimestamps.map((fillTimestamp) => { + return { + timestamp: Number(fillTimestamp), + solver: addressToBytes32(account()) + }; + }); - const transactionHash = await finaliseIntent({ - intent, - sourceChainId, - account: account(), - walletClient, - solveParams, - signatures: orderContainer - }); - if (!transactionHash) { - throw new Error( - `Finalise did not return a transaction hash for source chain ${Number(sourceChainId)}.` - ); - } - let result; - try { - result = await getClient(sourceChainId).waitForTransactionReceipt({ - hash: transactionHash, - timeout: 120_000, - pollingInterval: 2_000 - }); - } catch (error) { - throw new Error( - `Timed out waiting for finalise tx receipt on ${Number(sourceChainId)} for hash ${transactionHash}.`, - { cause: error as Error } - ); - } - await Solver.persistReceipt(sourceChainId, transactionHash, result); - if (postHook) await postHook(); - return result; - }; - } + const transactionHash = await finaliseIntent({ + intent, + sourceChainId, + account: account(), + walletClient, + solveParams, + signatures: orderContainer + }); + if (!transactionHash) { + throw new Error( + `Finalise did not return a transaction hash for source chain ${Number(sourceChainId)}.` + ); + } + let result; + try { + result = await getClient(sourceChainId).waitForTransactionReceipt({ + hash: transactionHash, + timeout: 120_000, + pollingInterval: 2_000 + }); + } catch (error) { + throw new Error( + `Timed out waiting for finalise tx receipt on ${Number(sourceChainId)} for hash ${transactionHash}.`, + { cause: error as Error } + ); + } + await Solver.persistReceipt(sourceChainId, transactionHash, result); + if (postHook) await postHook(); + return result; + }; + } } diff --git a/src/lib/libraries/token.ts b/src/lib/libraries/token.ts index b4ae255..d000190 100644 --- a/src/lib/libraries/token.ts +++ b/src/lib/libraries/token.ts @@ -5,59 +5,59 @@ import { ADDRESS_ZERO, clients, COMPACT } from "../config"; import { ResetPeriod, toId } from "@lifi/intent"; export async function getBalance( - user: `0x${string}` | undefined, - asset: `0x${string}`, - client: (typeof clients)[keyof typeof clients] + user: `0x${string}` | undefined, + asset: `0x${string}`, + client: (typeof clients)[keyof typeof clients] ) { - if (!user) return 0n; - if (asset === ADDRESS_ZERO) { - return client.getBalance({ - address: user, - blockTag: "latest" - }); - } else { - return client.readContract({ - address: asset, - abi: ERC20_ABI, - functionName: "balanceOf", - args: [user] - }); - } + if (!user) return 0n; + if (asset === ADDRESS_ZERO) { + return client.getBalance({ + address: user, + blockTag: "latest" + }); + } else { + return client.readContract({ + address: asset, + abi: ERC20_ABI, + functionName: "balanceOf", + args: [user] + }); + } } export function getAllowance(contract: `0x${string}`) { - return async ( - user: `0x${string}` | undefined, - asset: `0x${string}`, - client: (typeof clients)[keyof typeof clients] - ) => { - if (!user) return 0n; - if (asset == ADDRESS_ZERO) return maxUint256; - return client.readContract({ - address: asset, - abi: ERC20_ABI, - functionName: "allowance", - args: [user, contract] - }); - }; + return async ( + user: `0x${string}` | undefined, + asset: `0x${string}`, + client: (typeof clients)[keyof typeof clients] + ) => { + if (!user) return 0n; + if (asset == ADDRESS_ZERO) return maxUint256; + return client.readContract({ + address: asset, + abi: ERC20_ABI, + functionName: "allowance", + args: [user, contract] + }); + }; } export async function getCompactBalance( - user: `0x${string}` | undefined, - asset: `0x${string}`, - client: (typeof clients)[keyof typeof clients], - allocatorId: string + user: `0x${string}` | undefined, + asset: `0x${string}`, + client: (typeof clients)[keyof typeof clients], + allocatorId: string ) { - if (!user) return 0n; - const assetId = toId(true, ResetPeriod.OneDay, allocatorId, asset); - try { - return await client.readContract({ - address: COMPACT, - abi: COMPACT_ABI, - functionName: "balanceOf", - args: [user, assetId] - }); - } catch { - return 0n; - } + if (!user) return 0n; + const assetId = toId(true, ResetPeriod.OneDay, allocatorId, asset); + try { + return await client.readContract({ + address: COMPACT, + abi: COMPACT_ABI, + functionName: "balanceOf", + args: [user, assetId] + }); + } catch { + return 0n; + } } diff --git a/src/lib/migrations.json b/src/lib/migrations.json index addf1ba..2cf776d 100644 --- a/src/lib/migrations.json +++ b/src/lib/migrations.json @@ -1,44 +1,44 @@ [ - { - "sql": [ - "CREATE TABLE \"intents\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"order_id\" text NOT NULL,\n\t\"intent_type\" text NOT NULL,\n\t\"data\" text NOT NULL,\n\t\"created_at\" integer NOT NULL\n);\n" - ], - "bps": true, - "folderMillis": 1770712231202, - "hash": "3ec46f3cc562c5204f9e841d2ea2086d8994c80253445074b646b07900b30a9f" - }, - { - "sql": [ - "CREATE TABLE \"fill_transactions\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"output_hash\" text NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\tCONSTRAINT \"fill_transactions_output_hash_unique\" UNIQUE(\"output_hash\")\n);\n" - ], - "bps": true, - "folderMillis": 1770803119280, - "hash": "f963c9a03076fc9754b51c2850ad42f5edfdf19fb018a0616db37d935907b165" - }, - { - "sql": ["ALTER TABLE \"intents\" ALTER COLUMN \"created_at\" TYPE bigint;\n"], - "bps": true, - "folderMillis": 1770809000000, - "hash": "45484cce461ab6b6ac735465757bebec7d5bf488ed58c4288ebf1fd75d1881f5" - }, - { - "sql": [ - "CREATE UNIQUE INDEX IF NOT EXISTS \"intents_order_id_unique\" ON \"intents\" (\"order_id\");\n" - ], - "bps": true, - "folderMillis": 1770810000000, - "hash": "387946018137748e3a5dd66fca8a1da71ddabc4191a835a3254fad26c6b6d412" - }, - { - "sql": [ - "CREATE TABLE \"tokens\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"address\" text NOT NULL,\n\t\"name\" text NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"decimals\" bigint NOT NULL,\n\t\"is_manual\" boolean DEFAULT false NOT NULL,\n\t\"is_testnet\" boolean DEFAULT false NOT NULL\n);\n", - "\nCREATE TABLE \"transaction_receipts\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\t\"receipt\" text NOT NULL,\n\t\"created_at\" bigint NOT NULL\n);\n", - "\nALTER TABLE \"intents\" ALTER COLUMN \"created_at\" SET DATA TYPE bigint;", - "\nCREATE UNIQUE INDEX \"tokens_address_chain_idx\" ON \"tokens\" USING btree (\"address\",\"chain_id\");", - "\nALTER TABLE \"intents\" ADD CONSTRAINT \"intents_order_id_unique\" UNIQUE(\"order_id\");" - ], - "bps": true, - "folderMillis": 1773066106972, - "hash": "486043322db64a03ff9040a7cf7062a1d452554261d63c9c406c782e1e45b76b" - } + { + "sql": [ + "CREATE TABLE \"intents\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"order_id\" text NOT NULL,\n\t\"intent_type\" text NOT NULL,\n\t\"data\" text NOT NULL,\n\t\"created_at\" integer NOT NULL\n);\n" + ], + "bps": true, + "folderMillis": 1770712231202, + "hash": "3ec46f3cc562c5204f9e841d2ea2086d8994c80253445074b646b07900b30a9f" + }, + { + "sql": [ + "CREATE TABLE \"fill_transactions\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"output_hash\" text NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\tCONSTRAINT \"fill_transactions_output_hash_unique\" UNIQUE(\"output_hash\")\n);\n" + ], + "bps": true, + "folderMillis": 1770803119280, + "hash": "f963c9a03076fc9754b51c2850ad42f5edfdf19fb018a0616db37d935907b165" + }, + { + "sql": ["ALTER TABLE \"intents\" ALTER COLUMN \"created_at\" TYPE bigint;\n"], + "bps": true, + "folderMillis": 1770809000000, + "hash": "45484cce461ab6b6ac735465757bebec7d5bf488ed58c4288ebf1fd75d1881f5" + }, + { + "sql": [ + "CREATE UNIQUE INDEX IF NOT EXISTS \"intents_order_id_unique\" ON \"intents\" (\"order_id\");\n" + ], + "bps": true, + "folderMillis": 1770810000000, + "hash": "387946018137748e3a5dd66fca8a1da71ddabc4191a835a3254fad26c6b6d412" + }, + { + "sql": [ + "CREATE TABLE \"tokens\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"address\" text NOT NULL,\n\t\"name\" text NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"decimals\" bigint NOT NULL,\n\t\"is_manual\" boolean DEFAULT false NOT NULL,\n\t\"is_testnet\" boolean DEFAULT false NOT NULL\n);\n", + "\nCREATE TABLE \"transaction_receipts\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\t\"receipt\" text NOT NULL,\n\t\"created_at\" bigint NOT NULL\n);\n", + "\nALTER TABLE \"intents\" ALTER COLUMN \"created_at\" SET DATA TYPE bigint;", + "\nCREATE UNIQUE INDEX \"tokens_address_chain_idx\" ON \"tokens\" USING btree (\"address\",\"chain_id\");", + "\nALTER TABLE \"intents\" ADD CONSTRAINT \"intents_order_id_unique\" UNIQUE(\"order_id\");" + ], + "bps": true, + "folderMillis": 1773066106972, + "hash": "486043322db64a03ff9040a7cf7062a1d452554261d63c9c406c782e1e45b76b" + } ] diff --git a/src/lib/schema.ts b/src/lib/schema.ts index 6c1b96f..a6fa802 100644 --- a/src/lib/schema.ts +++ b/src/lib/schema.ts @@ -1,39 +1,39 @@ import { pgTable, text, bigint, boolean, uniqueIndex } from "drizzle-orm/pg-core"; export const intents = pgTable("intents", { - id: text("id").primaryKey(), - orderId: text("order_id").notNull().unique(), - intentType: text("intent_type").notNull(), - data: text("data").notNull(), - createdAt: bigint("created_at", { mode: "number" }).notNull() + id: text("id").primaryKey(), + orderId: text("order_id").notNull().unique(), + intentType: text("intent_type").notNull(), + data: text("data").notNull(), + createdAt: bigint("created_at", { mode: "number" }).notNull() }); export const fillTransactions = pgTable("fill_transactions", { - id: text("id").primaryKey(), - outputHash: text("output_hash").notNull().unique(), - txHash: text("tx_hash").notNull() + id: text("id").primaryKey(), + outputHash: text("output_hash").notNull().unique(), + txHash: text("tx_hash").notNull() }); export const transactionReceipts = pgTable("transaction_receipts", { - id: text("id").primaryKey(), - chainId: bigint("chain_id", { mode: "number" }).notNull(), - txHash: text("tx_hash").notNull(), - receipt: text("receipt").notNull(), - createdAt: bigint("created_at", { mode: "number" }).notNull() + id: text("id").primaryKey(), + chainId: bigint("chain_id", { mode: "number" }).notNull(), + txHash: text("tx_hash").notNull(), + receipt: text("receipt").notNull(), + createdAt: bigint("created_at", { mode: "number" }).notNull() }); export const tokens = pgTable( - "tokens", - { - id: text("id").primaryKey(), - address: text("address").notNull(), - name: text("name").notNull(), - chainId: bigint("chain_id", { mode: "number" }).notNull(), - decimals: bigint("decimals", { mode: "number" }).notNull(), - isManual: boolean("is_manual").notNull().default(false), - isTestnet: boolean("is_testnet").notNull().default(false) - }, - (table) => [uniqueIndex("tokens_address_chain_idx").on(table.address, table.chainId)] + "tokens", + { + id: text("id").primaryKey(), + address: text("address").notNull(), + name: text("name").notNull(), + chainId: bigint("chain_id", { mode: "number" }).notNull(), + decimals: bigint("decimals", { mode: "number" }).notNull(), + isManual: boolean("is_manual").notNull().default(false), + isTestnet: boolean("is_testnet").notNull().default(false) + }, + (table) => [uniqueIndex("tokens_address_chain_idx").on(table.address, table.chainId)] ); export const schema = { intents, fillTransactions, transactionReceipts, tokens }; diff --git a/src/lib/screens/ConnectWallet.svelte b/src/lib/screens/ConnectWallet.svelte index e08b7e5..7461fea 100644 --- a/src/lib/screens/ConnectWallet.svelte +++ b/src/lib/screens/ConnectWallet.svelte @@ -1,49 +1,49 @@ -
- {#each connectors as connector (connector.id)} - - {/each} +
+ {#each connectors as connector (connector.id)} + + {/each} - {#if !walletConnectProjectId} -

- WalletConnect is disabled (missing `PUBLIC_WALLET_CONNECT_PROJECT_ID`). -

- {/if} - {#if errorMessage} -

{errorMessage}

- {/if} -
+ {#if !walletConnectProjectId} +

+ WalletConnect is disabled (missing `PUBLIC_WALLET_CONNECT_PROJECT_ID`). +

+ {/if} + {#if errorMessage} +

{errorMessage}

+ {/if} +
diff --git a/src/lib/screens/FillIntent.svelte b/src/lib/screens/FillIntent.svelte index de5f4cd..018d95a 100644 --- a/src/lib/screens/FillIntent.svelte +++ b/src/lib/screens/FillIntent.svelte @@ -1,271 +1,271 @@ -
- -
- {#each orderContainer.order.outputs as output} - {@const key = outputKey(output)} - {@const currentHash = store.fillTransactions[key]} -
- - { - const value = (event.currentTarget as HTMLInputElement).value; - manualFillTxInputs[key] = value; - manualFillTxSaved[key] = false; - manualFillTxErrors[key] = ""; - }} - /> - - {#if manualFillTxErrors[key]} -
{manualFillTxErrors[key]}
- {:else if manualFillTxSaved[key]} -
Saved
- {/if} -
- {/each} -
-
- {#each sortOutputsByChain(orderContainer) as chainIdAndOutputs} - - - {#snippet action()} - {@const chainStatuses = chainIdAndOutputs[1].map( - (output) => fillStatuses[outputKey(output)] - )} - {#if chainStatuses.some((status) => status === undefined)} - - {:else} - v == BYTES32_ZERO) ? "default" : "muted"} - buttonFunction={chainStatuses.every((v) => v == BYTES32_ZERO) - ? fillWrapper( - chainIdAndOutputs[1], - Solver.fill( - store.walletClient, - { - orderContainer, - outputs: chainIdAndOutputs[1] - }, - { - preHook, - postHook: postHookScroll, - account - } - ) - ) - : async () => {}} - > - {#snippet name()} - Fill - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {/if} - {/snippet} - {#snippet chips()} - {#each chainIdAndOutputs[1] as output} - {@const filled = fillStatuses[outputKey(output)]} - - {/each} - {/snippet} - - - {/each} -
+
+ +
+ {#each orderContainer.order.outputs as output} + {@const key = outputKey(output)} + {@const currentHash = store.fillTransactions[key]} +
+ + { + const value = (event.currentTarget as HTMLInputElement).value; + manualFillTxInputs[key] = value; + manualFillTxSaved[key] = false; + manualFillTxErrors[key] = ""; + }} + /> + + {#if manualFillTxErrors[key]} +
{manualFillTxErrors[key]}
+ {:else if manualFillTxSaved[key]} +
Saved
+ {/if} +
+ {/each} +
+
+ {#each sortOutputsByChain(orderContainer) as chainIdAndOutputs} + + + {#snippet action()} + {@const chainStatuses = chainIdAndOutputs[1].map( + (output) => fillStatuses[outputKey(output)] + )} + {#if chainStatuses.some((status) => status === undefined)} + + {:else} + v == BYTES32_ZERO) ? "default" : "muted"} + buttonFunction={chainStatuses.every((v) => v == BYTES32_ZERO) + ? fillWrapper( + chainIdAndOutputs[1], + Solver.fill( + store.walletClient, + { + orderContainer, + outputs: chainIdAndOutputs[1] + }, + { + preHook, + postHook: postHookScroll, + account + } + ) + ) + : async () => {}} + > + {#snippet name()} + Fill + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {/if} + {/snippet} + {#snippet chips()} + {#each chainIdAndOutputs[1] as output} + {@const filled = fillStatuses[outputKey(output)]} + + {/each} + {/snippet} + + + {/each} +
diff --git a/src/lib/screens/Finalise.svelte b/src/lib/screens/Finalise.svelte index 5dcf169..e3ec236 100644 --- a/src/lib/screens/Finalise.svelte +++ b/src/lib/screens/Finalise.svelte @@ -1,284 +1,284 @@ -
- {#if allFinalised} - - {/if} - {#if allFinalised} -
-
All inputs finalised
-
Intent fully solved.
-
- {/if} - {#each inputChains as inputChain} - - - {#snippet action()} - {@const isClaimedStatus = claimedByChain[inputChain.toString()]} - {#if isClaimedStatus === undefined} - - {:else if isClaimedStatus} - - {:else} - {@const fillTransactionHashes = fillTransactionHashesFor(orderContainer)} - {@const canClaim = fillTransactionHashes.every((hash) => isValidFillTxHash(hash))} - {#if !canClaim} - - {:else} - - {#snippet name()} - Claim - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {/if} - {/if} - {/snippet} - {#snippet chips()} - {#each getInputsForChain(orderContainer, inputChain) as input} - - {/each} - {/snippet} - - - {/each} -
+
+ {#if allFinalised} + + {/if} + {#if allFinalised} +
+
All inputs finalised
+
Intent fully solved.
+
+ {/if} + {#each inputChains as inputChain} + + + {#snippet action()} + {@const isClaimedStatus = claimedByChain[inputChain.toString()]} + {#if isClaimedStatus === undefined} + + {:else if isClaimedStatus} + + {:else} + {@const fillTransactionHashes = fillTransactionHashesFor(orderContainer)} + {@const canClaim = fillTransactionHashes.every((hash) => isValidFillTxHash(hash))} + {#if !canClaim} + + {:else} + + {#snippet name()} + Claim + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {/if} + {/if} + {/snippet} + {#snippet chips()} + {#each getInputsForChain(orderContainer, inputChain) as input} + + {/each} + {/snippet} + + + {/each} +
diff --git a/src/lib/screens/IntentDescription.svelte b/src/lib/screens/IntentDescription.svelte index 0c463f5..106fb04 100644 --- a/src/lib/screens/IntentDescription.svelte +++ b/src/lib/screens/IntentDescription.svelte @@ -1,33 +1,33 @@
-

Intent Description

-

- To fill an intent, you may need to execute up to 4 transactions. This intent requires 3. -

-
-
    -
  1. - -
  2. -
  3. - -
  4. -
  5. - -
  6. -
  7. - -
  8. -
+

Intent Description

+

+ To fill an intent, you may need to execute up to 4 transactions. This intent requires 3. +

+
+
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + +
  6. +
  7. + +
  8. +
diff --git a/src/lib/screens/IntentList.svelte b/src/lib/screens/IntentList.svelte index f3cd53b..4f2c3a1 100644 --- a/src/lib/screens/IntentList.svelte +++ b/src/lib/screens/IntentList.svelte @@ -1,225 +1,225 @@ -
- { - if (event.key === "Enter") handleImport(); - }} - /> - -
- {#if importMessage} -
- {importMessage} -
- {/if} - -
- {#each activeRows as row (row.orderId)} -
- - -
- {/each} -
-
- -
- {#each expiredRows as row (row.orderId)} -
- - {#if expandedExpiredOrderId === row.orderId} - - {/if} -
- {/each} -
-
+
+ { + if (event.key === "Enter") handleImport(); + }} + /> + +
+ {#if importMessage} +
+ {importMessage} +
+ {/if} + +
+ {#each activeRows as row (row.orderId)} +
+ + +
+ {/each} +
+
+ +
+ {#each expiredRows as row (row.orderId)} +
+ + {#if expandedExpiredOrderId === row.orderId} + + {/if} +
+ {/each} +
+
diff --git a/src/lib/screens/IssueIntent.svelte b/src/lib/screens/IssueIntent.svelte index 167d326..5a7f32f 100644 --- a/src/lib/screens/IssueIntent.svelte +++ b/src/lib/screens/IssueIntent.svelte @@ -1,383 +1,383 @@ - {#if inputTokenSelectorActive} - - {/if} - {#if outputTokenSelectorActive} - - {/if} + {#if inputTokenSelectorActive} + + {/if} + {#if outputTokenSelectorActive} + + {/if} -
- - {#snippet headerRight()} -
- -
- {/snippet} -
-
-

You Pay

- {#each abstractInputs as input, i (input.name)} - - {/each} - {#if numInputChains > 1} -
Multichain
- {/if} - {#if sameChain} -
Same chain
- {/if} -
-
-
-
In
-
exchange
-
for
-
-
-
-

You Receive

- {#each store.outputTokens as outputToken, i (`${outputToken.token.chainId}-${outputToken.token.address}-${i}`)} - - {/each} -
-
-
+
+ + {#snippet headerRight()} +
+ +
+ {/snippet} +
+
+

You Pay

+ {#each abstractInputs as input, i (input.name)} + + {/each} + {#if numInputChains > 1} +
Multichain
+ {/if} + {#if sameChain} +
Same chain
+ {/if} +
+
+
+
In
+
exchange
+
for
+
+
+
+

You Receive

+ {#each store.outputTokens as outputToken, i (`${outputToken.token.chainId}-${outputToken.token.address}-${i}`)} + + {/each} +
+
+
- -
-
- Verifier - {#if sameChain} - - - - {:else} - - - - - {/if} -
-
- Exclusive - - -
-
-
+ +
+
+ Verifier + {#if sameChain} + + + + {:else} + + + + + {/if} +
+
+ Exclusive + + +
+
+
-
- {#if !true} - - {:else if !allowanceCheck} - - {#snippet name()} - Set allowance - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {:else} -
- {#if !balanceCheckWallet} - - {:else if store.intentType === "escrow"} - - {#snippet name()} - Execute Open - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {/if} - {#if store.intentType === "compact" && store.allocatorId !== POLYMER_ALLOCATOR} - {#if !balanceCheckCompact} - - {:else} - - {#snippet name()} - Sign Order - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {/if} - {/if} -
- {/if} -
- {#if numInputChains > 1 && store.intentType !== "compact"} -

- You'll need to open the order on {numInputChains} chains. Be prepared and do not interrupt the - process. -

- {/if} -
+
+ {#if !true} + + {:else if !allowanceCheck} + + {#snippet name()} + Set allowance + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {:else} +
+ {#if !balanceCheckWallet} + + {:else if store.intentType === "escrow"} + + {#snippet name()} + Execute Open + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {/if} + {#if store.intentType === "compact" && store.allocatorId !== POLYMER_ALLOCATOR} + {#if !balanceCheckCompact} + + {:else} + + {#snippet name()} + Sign Order + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {/if} + {/if} +
+ {/if} +
+ {#if numInputChains > 1 && store.intentType !== "compact"} +

+ You'll need to open the order on {numInputChains} chains. Be prepared and do not interrupt the + process. +

+ {/if} +
diff --git a/src/lib/screens/ManageDeposit.svelte b/src/lib/screens/ManageDeposit.svelte index 435f077..0f90551 100644 --- a/src/lib/screens/ManageDeposit.svelte +++ b/src/lib/screens/ManageDeposit.svelte @@ -1,267 +1,267 @@ -
- -
-

Network

- (store.mainnet = v === "mainnet")} - /> -
-
- -
-

Input Type

- (store.intentType = v as "compact" | "escrow")} - /> -
-
- {#if store.intentType === "compact"} - -
-
-

Allocator

- (store.allocatorId = v as typeof store.allocatorId)} - /> -
-
- - - - - - of - {#if (manageAssetAction === "withdraw" ? store.compactBalances : store.balances)[token.chainId]} - - {/if} - - {#each store.availableTokens as tkn, i} - - {/each} - -
-
- {#if manageAssetAction === "withdraw"} - - {#snippet name()} - Withdraw - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {:else if allowance < inputAmount} - - {#snippet name()} - Set allowance - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {:else} - - {#snippet name()} - Execute deposit - {/snippet} - {#snippet awaiting()} - Waiting for transaction... - {/snippet} - - {/if} -
-
-
- {/if} - -
-
-

Add Token

- - - {#each chainList(store.mainnet) as chainName} - - {/each} - - {#if addTokenError} -

{addTokenError}

- {/if} - { - addTokenError = ""; - if (!/^0x[0-9a-fA-F]{40}$/.test(newTokenAddress)) { - addTokenError = "Invalid address"; - return; - } - try { - const client = getClient(newTokenChainId); - const addr = newTokenAddress as `0x${string}`; - const decimals = await client.readContract({ - address: addr, - abi: erc20Abi, - functionName: "decimals" - }); - const symbol = await client.readContract({ - address: addr, - abi: erc20Abi, - functionName: "symbol" - }); - await store.addCustomToken({ - address: addr, - name: symbol.toLowerCase(), - chainId: newTokenChainId, - decimals: Number(decimals) - }); - newTokenAddress = ""; - } catch (e) { - addTokenError = e instanceof Error ? e.message : "Failed to fetch token"; - } - }} - > - {#snippet name()} - Add - {/snippet} - {#snippet awaiting()} - Fetching... - {/snippet} - -
-
- {#each store.availableTokens as tkn} - {@const tokenKey = `${tkn.chainId}:${tkn.address.toLowerCase()}`} - {@const isManual = store.manualTokenKeys.has(tokenKey)} -
- {tkn.name.toUpperCase()} - {printToken(tkn)} - {tkn.address.slice(0, 8)}… - {#if isManual} - - {/if} -
- {/each} -
-
-
-
+
+ +
+

Network

+ (store.mainnet = v === "mainnet")} + /> +
+
+ +
+

Input Type

+ (store.intentType = v as "compact" | "escrow")} + /> +
+
+ {#if store.intentType === "compact"} + +
+
+

Allocator

+ (store.allocatorId = v as typeof store.allocatorId)} + /> +
+
+ + + + + + of + {#if (manageAssetAction === "withdraw" ? store.compactBalances : store.balances)[token.chainId]} + + {/if} + + {#each store.availableTokens as tkn, i} + + {/each} + +
+
+ {#if manageAssetAction === "withdraw"} + + {#snippet name()} + Withdraw + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {:else if allowance < inputAmount} + + {#snippet name()} + Set allowance + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {:else} + + {#snippet name()} + Execute deposit + {/snippet} + {#snippet awaiting()} + Waiting for transaction... + {/snippet} + + {/if} +
+
+
+ {/if} + +
+
+

Add Token

+ + + {#each chainList(store.mainnet) as chainName} + + {/each} + + {#if addTokenError} +

{addTokenError}

+ {/if} + { + addTokenError = ""; + if (!/^0x[0-9a-fA-F]{40}$/.test(newTokenAddress)) { + addTokenError = "Invalid address"; + return; + } + try { + const client = getClient(newTokenChainId); + const addr = newTokenAddress as `0x${string}`; + const decimals = await client.readContract({ + address: addr, + abi: erc20Abi, + functionName: "decimals" + }); + const symbol = await client.readContract({ + address: addr, + abi: erc20Abi, + functionName: "symbol" + }); + await store.addCustomToken({ + address: addr, + name: symbol.toLowerCase(), + chainId: newTokenChainId, + decimals: Number(decimals) + }); + newTokenAddress = ""; + } catch (e) { + addTokenError = e instanceof Error ? e.message : "Failed to fetch token"; + } + }} + > + {#snippet name()} + Add + {/snippet} + {#snippet awaiting()} + Fetching... + {/snippet} + +
+
+ {#each store.availableTokens as tkn} + {@const tokenKey = `${tkn.chainId}:${tkn.address.toLowerCase()}`} + {@const isManual = store.manualTokenKeys.has(tokenKey)} +
+ {tkn.name.toUpperCase()} + {printToken(tkn)} + {tkn.address.slice(0, 8)}… + {#if isManual} + + {/if} +
+ {/each} +
+
+
+
diff --git a/src/lib/screens/ReceiveMessage.svelte b/src/lib/screens/ReceiveMessage.svelte index d19ecf7..c867b68 100644 --- a/src/lib/screens/ReceiveMessage.svelte +++ b/src/lib/screens/ReceiveMessage.svelte @@ -1,227 +1,227 @@ -
- {#each orderToIntent(orderContainer).inputChains() as inputChain} - - - {#snippet action()} -
Validate outputs
- {/snippet} - {#snippet chips()} - {#each orderContainer.order.outputs as output} - {@const status = validationStatuses[validationKey(inputChain, output)]} - {#if status === undefined} - - {:else} - {} - : Solver.validate( - store.walletClient, - { - output, - orderContainer, - fillTransactionHash: store.fillTransactions[outputKey(output)], - sourceChainId: Number(inputChain), - mainnet: store.mainnet - }, - { - preHook, - postHook: postHookRefreshValidate, - account - } - )} - > - {#snippet name()} - {formatTokenAmount( - output.amount, - getCoin({ address: output.token, chainId: output.chainId }).decimals - )} -   - {getCoin({ - address: output.token, - chainId: output.chainId - }).name.toUpperCase()} - {/snippet} - {#snippet awaiting()} - Validating... - {/snippet} - - {/if} - {/each} - {/snippet} -
-
- {/each} -
+
+ {#each orderToIntent(orderContainer).inputChains() as inputChain} + + + {#snippet action()} +
Validate outputs
+ {/snippet} + {#snippet chips()} + {#each orderContainer.order.outputs as output} + {@const status = validationStatuses[validationKey(inputChain, output)]} + {#if status === undefined} + + {:else} + {} + : Solver.validate( + store.walletClient, + { + output, + orderContainer, + fillTransactionHash: store.fillTransactions[outputKey(output)], + sourceChainId: Number(inputChain), + mainnet: store.mainnet + }, + { + preHook, + postHook: postHookRefreshValidate, + account + } + )} + > + {#snippet name()} + {formatTokenAmount( + output.amount, + getCoin({ address: output.token, chainId: output.chainId }).decimals + )} +   + {getCoin({ + address: output.token, + chainId: output.chainId + }).name.toUpperCase()} + {/snippet} + {#snippet awaiting()} + Validating... + {/snippet} + + {/if} + {/each} + {/snippet} +
+
+ {/each} +
diff --git a/src/lib/state.svelte.ts b/src/lib/state.svelte.ts index aac0545..fa84279 100644 --- a/src/lib/state.svelte.ts +++ b/src/lib/state.svelte.ts @@ -1,572 +1,572 @@ import type { OrderContainer } from "@lifi/intent"; import type { AppTokenContext } from "./appTypes"; import { - ALWAYS_OK_ALLOCATOR, - clientsById, - coinList, - COMPACT, - INPUT_SETTLER_COMPACT_LIFI, - INPUT_SETTLER_ESCROW_LIFI, - MULTICHAIN_INPUT_SETTLER_COMPACT, - MULTICHAIN_INPUT_SETTLER_ESCROW, - isChainIdTestnet, - type availableAllocators, - type Token, - type Verifier, - type WC + ALWAYS_OK_ALLOCATOR, + clientsById, + coinList, + COMPACT, + INPUT_SETTLER_COMPACT_LIFI, + INPUT_SETTLER_ESCROW_LIFI, + MULTICHAIN_INPUT_SETTLER_COMPACT, + MULTICHAIN_INPUT_SETTLER_ESCROW, + isChainIdTestnet, + type availableAllocators, + type Token, + type Verifier, + type WC } from "./config"; import { getAllowance, getBalance, getCompactBalance } from "./libraries/token"; import { browser } from "$app/environment"; import { initDb, db } from "./db"; import { - intents, - fillTransactions as fillTransactionsTable, - transactionReceipts as transactionReceiptsTable, - tokens as tokensTable + intents, + fillTransactions as fillTransactionsTable, + transactionReceipts as transactionReceiptsTable, + tokens as tokensTable } from "./schema"; import { and, eq, ne, notInArray } from "drizzle-orm"; import { orderToIntent } from "@lifi/intent"; import { getOrFetchRpc, invalidateRpcPrefix } from "./libraries/rpcCache"; import { - getCurrentConnection, - getCurrentWalletClient, - reconnectWallet, - type WalletConnection, - watchWalletConnection + getCurrentConnection, + getCurrentWalletClient, + reconnectWallet, + type WalletConnection, + watchWalletConnection } from "./utils/wagmi"; import { switchWalletChain } from "./utils/walletClientRuntime"; function generateUUID(): string { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - const r = (Math.random() * 16) | 0; - const v = c === "x" ? r : (r & 0x3) | 0x8; - return v.toString(16); - }); + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); } class Store { - mainnet = $state(true); - orders = $state([]); - - async loadOrdersFromDb() { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const rows = await db!.select().from(intents); - this.orders = rows.map((r: any) => JSON.parse(r.data) as OrderContainer); - } - - async saveOrderToDb(order: OrderContainer) { - if (!browser) return; - if (!db) await initDb(); - const orderId = orderToIntent(order).orderId(); - const now = Math.floor(Date.now() / 1000); - const id = (order as any).id ?? generateUUID(); - const intentType = (order as any).intentType ?? "escrow"; - const data = JSON.stringify(order); - if (db) { - try { - try { - await db - .insert(intents) - .values({ - id, - orderId, - intentType, - data, - createdAt: now - }) - .onConflictDoUpdate({ - target: intents.orderId, - set: { intentType, data } - }); - } catch (_error) { - const existing = await db.select().from(intents).where(eq(intents.orderId, orderId)); - if (existing.length > 0) { - await db.update(intents).set({ intentType, data }).where(eq(intents.orderId, orderId)); - } else { - await db.insert(intents).values({ - id, - orderId, - intentType, - data, - createdAt: now - }); - } - } - } catch (error) { - console.warn("saveOrderToDb db write failed", { orderId, error }); - } - } - const idx = this.orders.findIndex((o) => orderToIntent(o).orderId() === orderId); - if (idx >= 0) this.orders[idx] = order; - else this.orders.push(order); - } - - async deleteOrderFromDb(orderId: string) { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - await db!.delete(intents).where(eq(intents.orderId, orderId)); - await this.loadOrdersFromDb(); - } - - async loadFillTransactionsFromDb() { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const rows = await db!.select().from(fillTransactionsTable); - const loaded: { [outputId: string]: `0x${string}` } = {}; - for (const row of rows) loaded[row.outputHash] = row.txHash as `0x${string}`; - this.fillTransactions = loaded; - } - - async saveFillTransaction(outputHash: string, txHash: `0x${string}`) { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const existing = await db! - .select() - .from(fillTransactionsTable) - .where(eq(fillTransactionsTable.outputHash, outputHash)); - if (existing.length > 0) { - await db! - .update(fillTransactionsTable) - .set({ txHash }) - .where(eq(fillTransactionsTable.outputHash, outputHash)); - } else { - await db!.insert(fillTransactionsTable).values({ - id: generateUUID(), - outputHash, - txHash - }); - } - } - - async loadTransactionReceiptsFromDb() { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const rows = await db!.select().from(transactionReceiptsTable); - const loaded: Record = {}; - for (const row of rows) { - loaded[`${row.chainId}:${row.txHash}`] = row.receipt; - } - this.transactionReceipts = loaded; - } - - async saveTransactionReceipt(chainId: number | bigint, txHash: `0x${string}`, receipt: unknown) { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const chainIdNumber = Number(chainId); - const serializedReceipt = JSON.stringify(receipt, (_key, value) => - typeof value === "bigint" ? value.toString() : value - ); - const existing = await db! - .select() - .from(transactionReceiptsTable) - .where( - and( - eq(transactionReceiptsTable.chainId, chainIdNumber), - eq(transactionReceiptsTable.txHash, txHash) - ) - ); - if (existing.length > 0) { - await db! - .update(transactionReceiptsTable) - .set({ receipt: serializedReceipt }) - .where( - and( - eq(transactionReceiptsTable.chainId, chainIdNumber), - eq(transactionReceiptsTable.txHash, txHash) - ) - ); - } else { - await db!.insert(transactionReceiptsTable).values({ - id: typeof crypto !== "undefined" ? crypto.randomUUID() : String(Date.now()), - chainId: chainIdNumber, - txHash, - receipt: serializedReceipt, - createdAt: Math.floor(Date.now() / 1000) - }); - } - this.transactionReceipts[`${chainIdNumber}:${txHash}`] = serializedReceipt; - } - - getTransactionReceipt(chainId: number | bigint, txHash: `0x${string}`) { - const serialized = this.transactionReceipts[`${Number(chainId)}:${txHash}`]; - if (!serialized) return undefined; - try { - return JSON.parse(serialized) as unknown; - } catch (error) { - console.warn("parse cached transaction receipt failed", { - chainId: Number(chainId), - txHash, - error - }); - return undefined; - } - } - - walletConnection = $state(getCurrentConnection()); - connectedAccount = $derived( - this.walletConnection.status === "connected" - ? { address: this.walletConnection.address } - : undefined - ); - walletClient = $state(undefined as unknown as WC); - _unwatchWalletConnection?: () => void; - - availableTokens = $state([...(coinList(true) as readonly Token[])]); - manualTokenKeys = $state>(new Set()); - inputTokens = $state([]); - outputTokens = $state([]); - fillTransactions = $state<{ [outputId: string]: `0x${string}` }>({}); - transactionReceipts = $state>({}); - - refreshEpoch = $state(0); - rpcRefreshMs = 45_000; - _rpcRefreshHandle?: ReturnType; - - balances = $derived.by(() => { - this.refreshEpoch; - const account = this.connectedAccount?.address; - return this.mapOverCoinsCached({ - bucket: "balance", - ttlMs: 30_000, - isMainnet: this.mainnet, - scopeKey: account ?? "none", - fetcher: (asset, client) => getBalance(account, asset, client) - }); - }); - - allowances = $derived.by(() => { - this.refreshEpoch; - const account = this.connectedAccount?.address; - const spender = - this.inputSettler === INPUT_SETTLER_COMPACT_LIFI || - this.inputSettler === MULTICHAIN_INPUT_SETTLER_COMPACT - ? COMPACT - : this.inputSettler; - return this.mapOverCoinsCached({ - bucket: "allowance", - ttlMs: 60_000, - isMainnet: this.mainnet, - scopeKey: `${account ?? "none"}:${spender}`, - fetcher: (asset, client) => getAllowance(spender)(account, asset, client) - }); - }); - - compactBalances = $derived.by(() => { - this.refreshEpoch; - const account = this.connectedAccount?.address; - const allocatorId = this.allocatorId; - return this.mapOverCoinsCached({ - bucket: "compact", - ttlMs: 60_000, - isMainnet: this.mainnet, - scopeKey: `${account ?? "none"}:${allocatorId}`, - fetcher: (asset, client) => getCompactBalance(account, asset, client, allocatorId) - }); - }); - - multichain = $derived([...new Set(this.inputTokens.map((i) => i.token.chainId))].length > 1); - - inputSettler = $derived.by(() => { - if (this.intentType === "escrow" && !this.multichain) return INPUT_SETTLER_ESCROW_LIFI; - if (this.intentType === "escrow" && this.multichain) return MULTICHAIN_INPUT_SETTLER_ESCROW; - if (this.intentType === "compact" && !this.multichain) return INPUT_SETTLER_COMPACT_LIFI; - if (this.intentType === "compact" && this.multichain) return MULTICHAIN_INPUT_SETTLER_COMPACT; - return INPUT_SETTLER_ESCROW_LIFI; - }); - intentType = $state<"escrow" | "compact">("escrow"); - allocatorId = $state(ALWAYS_OK_ALLOCATOR); - verifier = $state("polymer"); - exclusiveFor: string = $state(""); - useExclusiveForQuoteRequest = $state(false); - - invalidateWalletReadCache(scope: "all" | "balance" | "allowance" | "compact" = "all") { - if (scope === "all" || scope === "balance") invalidateRpcPrefix("balance:"); - if (scope === "all" || scope === "allowance") invalidateRpcPrefix("allowance:"); - if (scope === "all" || scope === "compact") invalidateRpcPrefix("compact:"); - } - - refreshWalletReads(opts?: { - force?: boolean; - scope?: "all" | "balance" | "allowance" | "compact"; - }) { - const force = opts?.force ?? false; - const scope = opts?.scope ?? "all"; - if (force) this.invalidateWalletReadCache(scope); - this.refreshEpoch += 1; - } - - refreshTokenBalance(token: Token, force = true) { - if (force) { - invalidateRpcPrefix( - `balance:${this.mainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:` - ); - } - this.refreshEpoch += 1; - } - - refreshTokenAllowance(token: Token, force = true) { - if (force) { - invalidateRpcPrefix( - `allowance:${this.mainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:` - ); - } - this.refreshEpoch += 1; - } - - refreshCompactBalance(token: Token, force = true) { - if (force) { - invalidateRpcPrefix( - `compact:${this.mainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:` - ); - } - this.refreshEpoch += 1; - } - - forceUpdate = () => { - this.refreshWalletReads({ force: true, scope: "all" }); - }; - - syncIntervalMs = 5000; - _syncHandle?: ReturnType; - - startSync(intervalMs?: number) { - this.stopSync(); - this._syncHandle = setInterval(() => { - this.loadOrdersFromDb().catch((e) => console.warn("sync error", e)); - }, intervalMs ?? this.syncIntervalMs); - } - - stopSync() { - if (this._syncHandle) { - clearInterval(this._syncHandle); - this._syncHandle = undefined; - } - } - - startRpcRefreshLoop(intervalMs?: number) { - if (!browser) return; - this.stopRpcRefreshLoop(); - this._rpcRefreshHandle = setInterval(() => { - this.refreshWalletReads(); - }, intervalMs ?? this.rpcRefreshMs); - } - - stopRpcRefreshLoop() { - if (this._rpcRefreshHandle) { - clearInterval(this._rpcRefreshHandle); - this._rpcRefreshHandle = undefined; - } - } - - private async loadTokensFromDb(mainnet: boolean) { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const rows = await db!.select().from(tokensTable).where(eq(tokensTable.isTestnet, !mainnet)); - this.availableTokens = rows.map((r) => ({ - address: r.address as `0x${string}`, - name: r.name, - chainId: r.chainId, - decimals: r.decimals - })); - this.manualTokenKeys = new Set( - rows.filter((r) => r.isManual).map((r) => `${r.chainId}:${r.address.toLowerCase()}`) - ); - } - - async syncConfiguredTokens() { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - - const mainnetTokens = [...(coinList(true) as readonly Token[])]; - const testnetTokens = [...(coinList(false) as readonly Token[])]; - const allConfigured = [ - ...mainnetTokens.map((t) => ({ ...t, isTestnet: false })), - ...testnetTokens.map((t) => ({ ...t, isTestnet: true })) - ]; - - // Upsert all configured tokens - for (const t of allConfigured) { - const id = `${t.chainId}:${t.address.toLowerCase()}`; - try { - await db! - .insert(tokensTable) - .values({ - id, - address: t.address, - name: t.name, - chainId: t.chainId, - decimals: t.decimals, - isManual: false, - isTestnet: t.isTestnet - }) - .onConflictDoUpdate({ - target: tokensTable.id, - set: { name: t.name, decimals: t.decimals, isTestnet: t.isTestnet, isManual: false } - }); - } catch (_e) { - // ignore individual upsert errors - } - } - - // Delete stale non-manual tokens not in current configured lists - const configuredIds = allConfigured.map((t) => `${t.chainId}:${t.address.toLowerCase()}`); - try { - await db! - .delete(tokensTable) - .where(and(eq(tokensTable.isManual, false), notInArray(tokensTable.id, configuredIds))); - } catch (_e) { - // ignore - } - - await this.loadTokensFromDb(this.mainnet); - } - - async addCustomToken(token: Token) { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - const isTestnet = isChainIdTestnet(token.chainId); - const id = `${token.chainId}:${token.address.toLowerCase()}`; - try { - await db! - .insert(tokensTable) - .values({ - id, - address: token.address, - name: token.name, - chainId: token.chainId, - decimals: token.decimals, - isManual: true, - isTestnet - }) - .onConflictDoUpdate({ - target: tokensTable.id, - set: { name: token.name, decimals: token.decimals, isManual: true } - }); - } catch (_e) { - // fallback update - await db! - .update(tokensTable) - .set({ name: token.name, decimals: token.decimals, isManual: true }) - .where(eq(tokensTable.id, id)); - } - await this.loadTokensFromDb(this.mainnet); - } - - async removeCustomToken(address: string, chainId: number) { - if (!browser) return; - if (!db) await initDb(); - if (!db) return; - await db! - .delete(tokensTable) - .where( - and( - eq(tokensTable.address, address), - eq(tokensTable.chainId, chainId), - eq(tokensTable.isManual, true) - ) - ); - await this.loadTokensFromDb(this.mainnet); - } - - async syncTokensForNetwork(mainnet: boolean) { - await this.loadTokensFromDb(mainnet); - } - - async syncWalletClient() { - if (this.walletConnection.status !== "connected") { - this.walletClient = undefined as unknown as WC; - return; - } - try { - this.walletClient = (await getCurrentWalletClient()) as unknown as WC; - } catch (error) { - console.warn("getCurrentWalletClient failed", error); - this.walletClient = undefined as unknown as WC; - } - } - - async setWalletToCorrectChain(chainId: number | bigint) { - try { - return await switchWalletChain(this.walletClient, Number(chainId)); - } catch (error) { - console.warn( - `Wallet does not support switchChain or failed to switch chain: ${Number(chainId)}`, - error - ); - return undefined; - } - } - - mapOverCoinsCached(opts: { - bucket: "balance" | "allowance" | "compact"; - ttlMs: number; - isMainnet: boolean; - scopeKey: string; - fetcher: ( - asset: `0x${string}`, - client: (typeof clientsById)[keyof typeof clientsById] - ) => Promise; - }) { - const { bucket, ttlMs, isMainnet, scopeKey, fetcher } = opts; - const resolved: Record>> = {}; - for (const token of this.availableTokens) { - if (!resolved[token.chainId]) resolved[token.chainId] = {}; - const key = `${bucket}:${isMainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:${scopeKey}`; - resolved[token.chainId][token.address] = getOrFetchRpc( - key, - () => fetcher(token.address, clientsById[token.chainId]), - { ttlMs } - ); - } - return resolved; - } - - dbReady: Promise | undefined; - - constructor() { - this.availableTokens = [...(coinList(this.mainnet) as readonly Token[])]; - this.inputTokens = [{ token: this.availableTokens[0], amount: 1000000n }]; - this.outputTokens = [{ token: this.availableTokens[1], amount: 1000000n }]; - - if (browser) { - reconnectWallet() - .catch((error) => console.warn("reconnectWallet failed", error)) - .finally(() => { - this.walletConnection = getCurrentConnection(); - this.syncWalletClient().catch((error) => console.warn("syncWalletClient failed", error)); - }); - - this._unwatchWalletConnection = watchWalletConnection((connection) => { - this.walletConnection = connection; - this.syncWalletClient().catch((error) => console.warn("syncWalletClient failed", error)); - }); - } - - this.startRpcRefreshLoop(); - - this.dbReady = browser - ? Promise.all([ - this.loadOrdersFromDb().catch((e) => console.warn("loadOrdersFromDb error", e)), - this.loadFillTransactionsFromDb().catch((e) => - console.warn("loadFillTransactionsFromDb error", e) - ), - this.loadTransactionReceiptsFromDb().catch((e) => - console.warn("loadTransactionReceiptsFromDb error", e) - ), - this.syncConfiguredTokens().catch((e) => console.warn("syncConfiguredTokens error", e)) - ]).then(() => {}) - : Promise.resolve(); - } + mainnet = $state(true); + orders = $state([]); + + async loadOrdersFromDb() { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const rows = await db!.select().from(intents); + this.orders = rows.map((r: any) => JSON.parse(r.data) as OrderContainer); + } + + async saveOrderToDb(order: OrderContainer) { + if (!browser) return; + if (!db) await initDb(); + const orderId = orderToIntent(order).orderId(); + const now = Math.floor(Date.now() / 1000); + const id = (order as any).id ?? generateUUID(); + const intentType = (order as any).intentType ?? "escrow"; + const data = JSON.stringify(order); + if (db) { + try { + try { + await db + .insert(intents) + .values({ + id, + orderId, + intentType, + data, + createdAt: now + }) + .onConflictDoUpdate({ + target: intents.orderId, + set: { intentType, data } + }); + } catch (_error) { + const existing = await db.select().from(intents).where(eq(intents.orderId, orderId)); + if (existing.length > 0) { + await db.update(intents).set({ intentType, data }).where(eq(intents.orderId, orderId)); + } else { + await db.insert(intents).values({ + id, + orderId, + intentType, + data, + createdAt: now + }); + } + } + } catch (error) { + console.warn("saveOrderToDb db write failed", { orderId, error }); + } + } + const idx = this.orders.findIndex((o) => orderToIntent(o).orderId() === orderId); + if (idx >= 0) this.orders[idx] = order; + else this.orders.push(order); + } + + async deleteOrderFromDb(orderId: string) { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + await db!.delete(intents).where(eq(intents.orderId, orderId)); + await this.loadOrdersFromDb(); + } + + async loadFillTransactionsFromDb() { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const rows = await db!.select().from(fillTransactionsTable); + const loaded: { [outputId: string]: `0x${string}` } = {}; + for (const row of rows) loaded[row.outputHash] = row.txHash as `0x${string}`; + this.fillTransactions = loaded; + } + + async saveFillTransaction(outputHash: string, txHash: `0x${string}`) { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const existing = await db! + .select() + .from(fillTransactionsTable) + .where(eq(fillTransactionsTable.outputHash, outputHash)); + if (existing.length > 0) { + await db! + .update(fillTransactionsTable) + .set({ txHash }) + .where(eq(fillTransactionsTable.outputHash, outputHash)); + } else { + await db!.insert(fillTransactionsTable).values({ + id: generateUUID(), + outputHash, + txHash + }); + } + } + + async loadTransactionReceiptsFromDb() { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const rows = await db!.select().from(transactionReceiptsTable); + const loaded: Record = {}; + for (const row of rows) { + loaded[`${row.chainId}:${row.txHash}`] = row.receipt; + } + this.transactionReceipts = loaded; + } + + async saveTransactionReceipt(chainId: number | bigint, txHash: `0x${string}`, receipt: unknown) { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const chainIdNumber = Number(chainId); + const serializedReceipt = JSON.stringify(receipt, (_key, value) => + typeof value === "bigint" ? value.toString() : value + ); + const existing = await db! + .select() + .from(transactionReceiptsTable) + .where( + and( + eq(transactionReceiptsTable.chainId, chainIdNumber), + eq(transactionReceiptsTable.txHash, txHash) + ) + ); + if (existing.length > 0) { + await db! + .update(transactionReceiptsTable) + .set({ receipt: serializedReceipt }) + .where( + and( + eq(transactionReceiptsTable.chainId, chainIdNumber), + eq(transactionReceiptsTable.txHash, txHash) + ) + ); + } else { + await db!.insert(transactionReceiptsTable).values({ + id: typeof crypto !== "undefined" ? crypto.randomUUID() : String(Date.now()), + chainId: chainIdNumber, + txHash, + receipt: serializedReceipt, + createdAt: Math.floor(Date.now() / 1000) + }); + } + this.transactionReceipts[`${chainIdNumber}:${txHash}`] = serializedReceipt; + } + + getTransactionReceipt(chainId: number | bigint, txHash: `0x${string}`) { + const serialized = this.transactionReceipts[`${Number(chainId)}:${txHash}`]; + if (!serialized) return undefined; + try { + return JSON.parse(serialized) as unknown; + } catch (error) { + console.warn("parse cached transaction receipt failed", { + chainId: Number(chainId), + txHash, + error + }); + return undefined; + } + } + + walletConnection = $state(getCurrentConnection()); + connectedAccount = $derived( + this.walletConnection.status === "connected" + ? { address: this.walletConnection.address } + : undefined + ); + walletClient = $state(undefined as unknown as WC); + _unwatchWalletConnection?: () => void; + + availableTokens = $state([...(coinList(true) as readonly Token[])]); + manualTokenKeys = $state>(new Set()); + inputTokens = $state([]); + outputTokens = $state([]); + fillTransactions = $state<{ [outputId: string]: `0x${string}` }>({}); + transactionReceipts = $state>({}); + + refreshEpoch = $state(0); + rpcRefreshMs = 45_000; + _rpcRefreshHandle?: ReturnType; + + balances = $derived.by(() => { + this.refreshEpoch; + const account = this.connectedAccount?.address; + return this.mapOverCoinsCached({ + bucket: "balance", + ttlMs: 30_000, + isMainnet: this.mainnet, + scopeKey: account ?? "none", + fetcher: (asset, client) => getBalance(account, asset, client) + }); + }); + + allowances = $derived.by(() => { + this.refreshEpoch; + const account = this.connectedAccount?.address; + const spender = + this.inputSettler === INPUT_SETTLER_COMPACT_LIFI || + this.inputSettler === MULTICHAIN_INPUT_SETTLER_COMPACT + ? COMPACT + : this.inputSettler; + return this.mapOverCoinsCached({ + bucket: "allowance", + ttlMs: 60_000, + isMainnet: this.mainnet, + scopeKey: `${account ?? "none"}:${spender}`, + fetcher: (asset, client) => getAllowance(spender)(account, asset, client) + }); + }); + + compactBalances = $derived.by(() => { + this.refreshEpoch; + const account = this.connectedAccount?.address; + const allocatorId = this.allocatorId; + return this.mapOverCoinsCached({ + bucket: "compact", + ttlMs: 60_000, + isMainnet: this.mainnet, + scopeKey: `${account ?? "none"}:${allocatorId}`, + fetcher: (asset, client) => getCompactBalance(account, asset, client, allocatorId) + }); + }); + + multichain = $derived([...new Set(this.inputTokens.map((i) => i.token.chainId))].length > 1); + + inputSettler = $derived.by(() => { + if (this.intentType === "escrow" && !this.multichain) return INPUT_SETTLER_ESCROW_LIFI; + if (this.intentType === "escrow" && this.multichain) return MULTICHAIN_INPUT_SETTLER_ESCROW; + if (this.intentType === "compact" && !this.multichain) return INPUT_SETTLER_COMPACT_LIFI; + if (this.intentType === "compact" && this.multichain) return MULTICHAIN_INPUT_SETTLER_COMPACT; + return INPUT_SETTLER_ESCROW_LIFI; + }); + intentType = $state<"escrow" | "compact">("escrow"); + allocatorId = $state(ALWAYS_OK_ALLOCATOR); + verifier = $state("polymer"); + exclusiveFor: string = $state(""); + useExclusiveForQuoteRequest = $state(false); + + invalidateWalletReadCache(scope: "all" | "balance" | "allowance" | "compact" = "all") { + if (scope === "all" || scope === "balance") invalidateRpcPrefix("balance:"); + if (scope === "all" || scope === "allowance") invalidateRpcPrefix("allowance:"); + if (scope === "all" || scope === "compact") invalidateRpcPrefix("compact:"); + } + + refreshWalletReads(opts?: { + force?: boolean; + scope?: "all" | "balance" | "allowance" | "compact"; + }) { + const force = opts?.force ?? false; + const scope = opts?.scope ?? "all"; + if (force) this.invalidateWalletReadCache(scope); + this.refreshEpoch += 1; + } + + refreshTokenBalance(token: Token, force = true) { + if (force) { + invalidateRpcPrefix( + `balance:${this.mainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:` + ); + } + this.refreshEpoch += 1; + } + + refreshTokenAllowance(token: Token, force = true) { + if (force) { + invalidateRpcPrefix( + `allowance:${this.mainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:` + ); + } + this.refreshEpoch += 1; + } + + refreshCompactBalance(token: Token, force = true) { + if (force) { + invalidateRpcPrefix( + `compact:${this.mainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:` + ); + } + this.refreshEpoch += 1; + } + + forceUpdate = () => { + this.refreshWalletReads({ force: true, scope: "all" }); + }; + + syncIntervalMs = 5000; + _syncHandle?: ReturnType; + + startSync(intervalMs?: number) { + this.stopSync(); + this._syncHandle = setInterval(() => { + this.loadOrdersFromDb().catch((e) => console.warn("sync error", e)); + }, intervalMs ?? this.syncIntervalMs); + } + + stopSync() { + if (this._syncHandle) { + clearInterval(this._syncHandle); + this._syncHandle = undefined; + } + } + + startRpcRefreshLoop(intervalMs?: number) { + if (!browser) return; + this.stopRpcRefreshLoop(); + this._rpcRefreshHandle = setInterval(() => { + this.refreshWalletReads(); + }, intervalMs ?? this.rpcRefreshMs); + } + + stopRpcRefreshLoop() { + if (this._rpcRefreshHandle) { + clearInterval(this._rpcRefreshHandle); + this._rpcRefreshHandle = undefined; + } + } + + private async loadTokensFromDb(mainnet: boolean) { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const rows = await db!.select().from(tokensTable).where(eq(tokensTable.isTestnet, !mainnet)); + this.availableTokens = rows.map((r) => ({ + address: r.address as `0x${string}`, + name: r.name, + chainId: r.chainId, + decimals: r.decimals + })); + this.manualTokenKeys = new Set( + rows.filter((r) => r.isManual).map((r) => `${r.chainId}:${r.address.toLowerCase()}`) + ); + } + + async syncConfiguredTokens() { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + + const mainnetTokens = [...(coinList(true) as readonly Token[])]; + const testnetTokens = [...(coinList(false) as readonly Token[])]; + const allConfigured = [ + ...mainnetTokens.map((t) => ({ ...t, isTestnet: false })), + ...testnetTokens.map((t) => ({ ...t, isTestnet: true })) + ]; + + // Upsert all configured tokens + for (const t of allConfigured) { + const id = `${t.chainId}:${t.address.toLowerCase()}`; + try { + await db! + .insert(tokensTable) + .values({ + id, + address: t.address, + name: t.name, + chainId: t.chainId, + decimals: t.decimals, + isManual: false, + isTestnet: t.isTestnet + }) + .onConflictDoUpdate({ + target: tokensTable.id, + set: { name: t.name, decimals: t.decimals, isTestnet: t.isTestnet, isManual: false } + }); + } catch (_e) { + // ignore individual upsert errors + } + } + + // Delete stale non-manual tokens not in current configured lists + const configuredIds = allConfigured.map((t) => `${t.chainId}:${t.address.toLowerCase()}`); + try { + await db! + .delete(tokensTable) + .where(and(eq(tokensTable.isManual, false), notInArray(tokensTable.id, configuredIds))); + } catch (_e) { + // ignore + } + + await this.loadTokensFromDb(this.mainnet); + } + + async addCustomToken(token: Token) { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + const isTestnet = isChainIdTestnet(token.chainId); + const id = `${token.chainId}:${token.address.toLowerCase()}`; + try { + await db! + .insert(tokensTable) + .values({ + id, + address: token.address, + name: token.name, + chainId: token.chainId, + decimals: token.decimals, + isManual: true, + isTestnet + }) + .onConflictDoUpdate({ + target: tokensTable.id, + set: { name: token.name, decimals: token.decimals, isManual: true } + }); + } catch (_e) { + // fallback update + await db! + .update(tokensTable) + .set({ name: token.name, decimals: token.decimals, isManual: true }) + .where(eq(tokensTable.id, id)); + } + await this.loadTokensFromDb(this.mainnet); + } + + async removeCustomToken(address: string, chainId: number) { + if (!browser) return; + if (!db) await initDb(); + if (!db) return; + await db! + .delete(tokensTable) + .where( + and( + eq(tokensTable.address, address), + eq(tokensTable.chainId, chainId), + eq(tokensTable.isManual, true) + ) + ); + await this.loadTokensFromDb(this.mainnet); + } + + async syncTokensForNetwork(mainnet: boolean) { + await this.loadTokensFromDb(mainnet); + } + + async syncWalletClient() { + if (this.walletConnection.status !== "connected") { + this.walletClient = undefined as unknown as WC; + return; + } + try { + this.walletClient = (await getCurrentWalletClient()) as unknown as WC; + } catch (error) { + console.warn("getCurrentWalletClient failed", error); + this.walletClient = undefined as unknown as WC; + } + } + + async setWalletToCorrectChain(chainId: number | bigint) { + try { + return await switchWalletChain(this.walletClient, Number(chainId)); + } catch (error) { + console.warn( + `Wallet does not support switchChain or failed to switch chain: ${Number(chainId)}`, + error + ); + return undefined; + } + } + + mapOverCoinsCached(opts: { + bucket: "balance" | "allowance" | "compact"; + ttlMs: number; + isMainnet: boolean; + scopeKey: string; + fetcher: ( + asset: `0x${string}`, + client: (typeof clientsById)[keyof typeof clientsById] + ) => Promise; + }) { + const { bucket, ttlMs, isMainnet, scopeKey, fetcher } = opts; + const resolved: Record>> = {}; + for (const token of this.availableTokens) { + if (!resolved[token.chainId]) resolved[token.chainId] = {}; + const key = `${bucket}:${isMainnet ? "mainnet" : "testnet"}:${token.chainId}:${token.address}:${scopeKey}`; + resolved[token.chainId][token.address] = getOrFetchRpc( + key, + () => fetcher(token.address, clientsById[token.chainId]), + { ttlMs } + ); + } + return resolved; + } + + dbReady: Promise | undefined; + + constructor() { + this.availableTokens = [...(coinList(this.mainnet) as readonly Token[])]; + this.inputTokens = [{ token: this.availableTokens[0], amount: 1000000n }]; + this.outputTokens = [{ token: this.availableTokens[1], amount: 1000000n }]; + + if (browser) { + reconnectWallet() + .catch((error) => console.warn("reconnectWallet failed", error)) + .finally(() => { + this.walletConnection = getCurrentConnection(); + this.syncWalletClient().catch((error) => console.warn("syncWalletClient failed", error)); + }); + + this._unwatchWalletConnection = watchWalletConnection((connection) => { + this.walletConnection = connection; + this.syncWalletClient().catch((error) => console.warn("syncWalletClient failed", error)); + }); + } + + this.startRpcRefreshLoop(); + + this.dbReady = browser + ? Promise.all([ + this.loadOrdersFromDb().catch((e) => console.warn("loadOrdersFromDb error", e)), + this.loadFillTransactionsFromDb().catch((e) => + console.warn("loadFillTransactionsFromDb error", e) + ), + this.loadTransactionReceiptsFromDb().catch((e) => + console.warn("loadTransactionReceiptsFromDb error", e) + ), + this.syncConfiguredTokens().catch((e) => console.warn("syncConfiguredTokens error", e)) + ]).then(() => {}) + : Promise.resolve(); + } } export const store = new Store(); diff --git a/src/lib/utils/wagmi.ts b/src/lib/utils/wagmi.ts index a02bb41..0b665cc 100644 --- a/src/lib/utils/wagmi.ts +++ b/src/lib/utils/wagmi.ts @@ -1,103 +1,103 @@ import { browser } from "$app/environment"; import { env } from "$env/dynamic/public"; import { - connect, - createConfig, - disconnect, - getConnection, - getConnectors, - http, - reconnect, - watchConnection + connect, + createConfig, + disconnect, + getConnection, + getConnectors, + http, + reconnect, + watchConnection } from "@wagmi/core"; import { injected, metaMask, walletConnect } from "@wagmi/connectors"; import { createWalletClient, custom, type Chain, type EIP1193Provider } from "viem"; import { chainMap } from "../config"; const APP_METADATA = { - name: "Open Intents Framework Demo", - description: "A demo website showcasing using the Open Intents Framework. Built by LIFI.", - url: "https://lintent.org", - icons: ["https://lintent.org/favicon.ico"] + name: "Open Intents Framework Demo", + description: "A demo website showcasing using the Open Intents Framework. Built by LIFI.", + url: "https://lintent.org", + icons: ["https://lintent.org/favicon.ico"] }; export const walletConnectProjectId = env.PUBLIC_WALLET_CONNECT_PROJECT_ID?.trim(); export function resolveConnectorIds(projectId?: string) { - return ["injected", ...(projectId ? ["walletConnect"] : []), "metaMask"]; + return ["injected", ...(projectId ? ["walletConnect"] : []), "metaMask"]; } const wagmiChains = Object.values(chainMap) as Chain[]; const connectors = [ - injected(), - ...(walletConnectProjectId - ? [ - walletConnect({ - projectId: walletConnectProjectId, - showQrModal: true, - metadata: APP_METADATA - }) - ] - : []), - metaMask({ dappMetadata: APP_METADATA }) + injected(), + ...(walletConnectProjectId + ? [ + walletConnect({ + projectId: walletConnectProjectId, + showQrModal: true, + metadata: APP_METADATA + }) + ] + : []), + metaMask({ dappMetadata: APP_METADATA }) ]; const transports = Object.fromEntries(wagmiChains.map((chain) => [chain.id, http()])); export const wagmiConfig = createConfig({ - ssr: true, - chains: wagmiChains as [Chain, ...Chain[]], - connectors, - transports: transports as Record> + ssr: true, + chains: wagmiChains as [Chain, ...Chain[]], + connectors, + transports: transports as Record> }); export type WalletConnection = ReturnType; export function listWalletConnectors() { - return getConnectors(wagmiConfig).map((connector) => ({ - id: connector.id, - name: connector.name - })); + return getConnectors(wagmiConfig).map((connector) => ({ + id: connector.id, + name: connector.name + })); } export async function connectWith(connectorId: string) { - const connector = getConnectors(wagmiConfig).find((candidate) => candidate.id === connectorId); - if (!connector) throw new Error(`Connector not found: ${connectorId}`); - return connect(wagmiConfig, { connector }); + const connector = getConnectors(wagmiConfig).find((candidate) => candidate.id === connectorId); + if (!connector) throw new Error(`Connector not found: ${connectorId}`); + return connect(wagmiConfig, { connector }); } export async function reconnectWallet() { - return reconnect(wagmiConfig); + return reconnect(wagmiConfig); } export async function disconnectWallet() { - const connection = getConnection(wagmiConfig); - if (connection.status !== "connected") return; - return disconnect(wagmiConfig, { connector: connection.connector }); + const connection = getConnection(wagmiConfig); + if (connection.status !== "connected") return; + return disconnect(wagmiConfig, { connector: connection.connector }); } export function getCurrentConnection() { - return getConnection(wagmiConfig); + return getConnection(wagmiConfig); } export async function getCurrentProvider() { - const connection = getConnection(wagmiConfig); - if (connection.status !== "connected") return undefined; - return (await connection.connector.getProvider()) as EIP1193Provider; + const connection = getConnection(wagmiConfig); + if (connection.status !== "connected") return undefined; + return (await connection.connector.getProvider()) as EIP1193Provider; } export async function getCurrentWalletClient() { - const provider = await getCurrentProvider(); - if (!provider) return undefined; - return createWalletClient({ transport: custom(provider) }); + const provider = await getCurrentProvider(); + if (!provider) return undefined; + return createWalletClient({ transport: custom(provider) }); } export function watchWalletConnection(onChange: (connection: WalletConnection) => void) { - if (!browser) return () => {}; - return watchConnection(wagmiConfig, { - onChange(connection) { - onChange(connection); - } - }); + if (!browser) return () => {}; + return watchConnection(wagmiConfig, { + onChange(connection) { + onChange(connection); + } + }); } diff --git a/src/lib/utils/walletClient.ts b/src/lib/utils/walletClient.ts index b040963..34ed3ea 100644 --- a/src/lib/utils/walletClient.ts +++ b/src/lib/utils/walletClient.ts @@ -3,67 +3,67 @@ import { toHex } from "viem"; import type { WC } from "$lib/config"; export type SwitchableWalletClient = WC & { - switchChain?: (args: { id: number }) => Promise; + switchChain?: (args: { id: number }) => Promise; }; export type SwitchWalletChainOptions = { - provider?: EIP1193Provider; + provider?: EIP1193Provider; }; export type SwitchWalletChain = ( - walletClient: WC | undefined, - chainId: number, - options?: SwitchWalletChainOptions + walletClient: WC | undefined, + chainId: number, + options?: SwitchWalletChainOptions ) => Promise; export type SwitchWalletChainDeps = { - getCurrentProvider: () => Promise; + getCurrentProvider: () => Promise; }; async function resolveWalletProvider( - walletClient: WC | undefined, - deps: SwitchWalletChainDeps, - provider?: EIP1193Provider + walletClient: WC | undefined, + deps: SwitchWalletChainDeps, + provider?: EIP1193Provider ): Promise { - if (provider?.request) return provider; + if (provider?.request) return provider; - const walletClientWithTransport = walletClient as - | (WC & { transport?: { value?: EIP1193Provider } }) - | undefined; - const transportProvider = walletClientWithTransport?.transport?.value; - if (transportProvider?.request) return transportProvider; + const walletClientWithTransport = walletClient as + | (WC & { transport?: { value?: EIP1193Provider } }) + | undefined; + const transportProvider = walletClientWithTransport?.transport?.value; + if (transportProvider?.request) return transportProvider; - try { - return await deps.getCurrentProvider(); - } catch { - return undefined; - } + try { + return await deps.getCurrentProvider(); + } catch { + return undefined; + } } export function createSwitchWalletChain(deps: SwitchWalletChainDeps): SwitchWalletChain { - return async ( - walletClient: WC | undefined, - chainId: number, - options?: SwitchWalletChainOptions - ) => { - if (!walletClient) return; + return async ( + walletClient: WC | undefined, + chainId: number, + options?: SwitchWalletChainOptions + ) => { + if (!walletClient) return; - const switchableClient = walletClient as SwitchableWalletClient; - if (typeof switchableClient.switchChain === "function") { - await switchableClient.switchChain({ id: chainId }); - return; - } + const switchableClient = walletClient as SwitchableWalletClient; + if (typeof switchableClient.switchChain === "function") { + await switchableClient.switchChain({ id: chainId }); + return; + } - const provider = await resolveWalletProvider(walletClient, deps, options?.provider); - if (!provider?.request) { - throw new Error( - `Wallet client does not support switchChain and no provider is available for chain ${chainId}.` - ); - } + const provider = await resolveWalletProvider(walletClient, deps, options?.provider); + if (!provider?.request) { + throw new Error( + `Wallet client does not support switchChain and no provider is available for chain ${chainId}.` + ); + } - await provider.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: toHex(chainId) }] - }); - }; + await provider.request({ + method: "wallet_switchEthereumChain", + params: [{ chainId: toHex(chainId) }] + }); + }; } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 2458f08..801be90 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,7 +1,7 @@ {@render children()} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 2995803..3b6bdc1 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,258 +1,258 @@
-

- Resource lock intents using OIF -

-
- -
-
- - -
- - - Preview by LI.FI - +

+ Resource lock intents using OIF +

+
+ +
+
+ + +
+ + + Preview by LI.FI + - {#if !(!store.connectedAccount || !store.walletClient)} - - - - - {/if} -
- {#if !store.connectedAccount || !store.walletClient} - - {:else} - - - - {#if selectedOrder !== undefined} - - - - - {/if} - {/if} -
-
-
- { - if (step.targetIndex === undefined) return; - goToScreen(step.targetIndex); - }} - /> -
-
- - + {#if !(!store.connectedAccount || !store.walletClient)} + + + + + {/if} +
+ {#if !store.connectedAccount || !store.walletClient} + + {:else} + + + + {#if selectedOrder !== undefined} + + + + + {/if} + {/if} +
+
+
+ { + if (step.targetIndex === undefined) return; + goToScreen(step.targetIndex); + }} + /> +
+
+ +
diff --git a/src/routes/allocator/+server.ts b/src/routes/allocator/+server.ts index 4f03cea..5a747a6 100644 --- a/src/routes/allocator/+server.ts +++ b/src/routes/allocator/+server.ts @@ -3,81 +3,81 @@ import axios from "axios"; import type { RequestHandler } from "./$types"; import { type StandardOrder } from "@lifi/intent"; import { - PRIVATE_POLYMER_MAINNET_ZONE_API_KEY, - PRIVATE_POLYMER_TESTNET_ZONE_API_KEY + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY, + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY } from "$env/static/private"; function getPolymerKey(mainnet: boolean) { - return mainnet ? PRIVATE_POLYMER_MAINNET_ZONE_API_KEY : PRIVATE_POLYMER_TESTNET_ZONE_API_KEY; + return mainnet ? PRIVATE_POLYMER_MAINNET_ZONE_API_KEY : PRIVATE_POLYMER_TESTNET_ZONE_API_KEY; } export const POST: RequestHandler = async ({ request }) => { - const { - order, - claimHash, - blockNumber, - chainId, - mainnet - }: { - order: StandardOrder; - claimHash: `0x${string}`; - blockNumber: number; - chainId: number; - mainnet?: boolean; - } = await request.json(); - console.log({ order, claimHash, blockNumber, chainId }); + const { + order, + claimHash, + blockNumber, + chainId, + mainnet + }: { + order: StandardOrder; + claimHash: `0x${string}`; + blockNumber: number; + chainId: number; + mainnet?: boolean; + } = await request.json(); + console.log({ order, claimHash, blockNumber, chainId }); - const PRIVATE_POLYMER_ZONE_API_KEY = getPolymerKey(mainnet ?? true); + const PRIVATE_POLYMER_ZONE_API_KEY = getPolymerKey(mainnet ?? true); - const requestAllocation = await axios.post( - "https://allocator.devnet.polymer.zone/", - { - jsonrpc: "2.0", - id: 1, - method: "allocator_attestCommit", - params: [ - { - chainId, - blockNumber, - claimHash, - order - } - ] - }, - { - headers: { - Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, - "Content-Type": "application/json", - Accept: "application/json" - } - } - ); + const requestAllocation = await axios.post( + "https://allocator.devnet.polymer.zone/", + { + jsonrpc: "2.0", + id: 1, + method: "allocator_attestCommit", + params: [ + { + chainId, + blockNumber, + claimHash, + order + } + ] + }, + { + headers: { + Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, + "Content-Type": "application/json", + Accept: "application/json" + } + } + ); - const dat: { - jsonrpc: "2.0"; - id: 1; - result: { - chainId: number; - blockNumber: number; - logIndex: number; - order: StandardOrder; - commitSignature: `0x${string}`; - allocatorSignature: `0x${string}`; - allocatorAddress: `0x${string}`; - claimHash: `0x${string}`; - sponsor: `0x${string}`; - tokenBalances: { - tokenId: `0x${string}`; - balance: `0x${string}`; - }[]; - }; - } = requestAllocation.data; + const dat: { + jsonrpc: "2.0"; + id: 1; + result: { + chainId: number; + blockNumber: number; + logIndex: number; + order: StandardOrder; + commitSignature: `0x${string}`; + allocatorSignature: `0x${string}`; + allocatorAddress: `0x${string}`; + claimHash: `0x${string}`; + sponsor: `0x${string}`; + tokenBalances: { + tokenId: `0x${string}`; + balance: `0x${string}`; + }[]; + }; + } = requestAllocation.data; - console.log(dat); + console.log(dat); - // create a JSON Response using a header we received - return json({ - allocatorSignature: dat.result.allocatorSignature, - allocatorAddress: dat.result.allocatorAddress - }); + // create a JSON Response using a header we received + return json({ + allocatorSignature: dat.result.allocatorSignature, + allocatorAddress: dat.result.allocatorAddress + }); }; diff --git a/src/routes/health/+server.ts b/src/routes/health/+server.ts index 94f864c..cfd89c7 100644 --- a/src/routes/health/+server.ts +++ b/src/routes/health/+server.ts @@ -1,5 +1,5 @@ import type { RequestHandler } from "./$types"; export const GET: RequestHandler = async ({}) => { - return new Response(JSON.stringify({ status: "ok", timestamp: Date.now() })); + return new Response(JSON.stringify({ status: "ok", timestamp: Date.now() })); }; diff --git a/src/routes/polymer/+server.ts b/src/routes/polymer/+server.ts index c19da15..98d8df4 100644 --- a/src/routes/polymer/+server.ts +++ b/src/routes/polymer/+server.ts @@ -2,109 +2,109 @@ import { json } from "@sveltejs/kit"; import axios from "axios"; import type { RequestHandler } from "./$types"; import { - PRIVATE_POLYMER_MAINNET_ZONE_API_KEY, - PRIVATE_POLYMER_TESTNET_ZONE_API_KEY + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY, + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY } from "$env/static/private"; import { toByteArray } from "base64-js"; function getPolymerUrl(mainnet: boolean) { - return mainnet - ? ("https://api.polymer.zone/v1/" as const) - : ("https://api.testnet.polymer.zone/v1/" as const); + return mainnet + ? ("https://api.polymer.zone/v1/" as const) + : ("https://api.testnet.polymer.zone/v1/" as const); } function getPolymerKey(mainnet: boolean) { - return mainnet ? PRIVATE_POLYMER_MAINNET_ZONE_API_KEY : PRIVATE_POLYMER_TESTNET_ZONE_API_KEY; + return mainnet ? PRIVATE_POLYMER_MAINNET_ZONE_API_KEY : PRIVATE_POLYMER_TESTNET_ZONE_API_KEY; } export const POST: RequestHandler = async ({ request }) => { - const { srcChainId, srcBlockNumber, globalLogIndex, polymerIndex, mainnet } = - await request.json(); - console.log({ srcChainId, srcBlockNumber, globalLogIndex, polymerIndex, mainnet }); + const { srcChainId, srcBlockNumber, globalLogIndex, polymerIndex, mainnet } = + await request.json(); + console.log({ srcChainId, srcBlockNumber, globalLogIndex, polymerIndex, mainnet }); - const POLYMER_URL = getPolymerUrl(mainnet ?? true); - const PRIVATE_POLYMER_ZONE_API_KEY = getPolymerKey(mainnet ?? true); + const POLYMER_URL = getPolymerUrl(mainnet ?? true); + const PRIVATE_POLYMER_ZONE_API_KEY = getPolymerKey(mainnet ?? true); - let polymerRequestIndex = polymerIndex; - if (!polymerRequestIndex) { - const requestProof = await axios.post( - POLYMER_URL, - { - jsonrpc: "2.0", - id: 1, - method: "polymer_requestProof", - params: [ - { - srcChainId, - srcBlockNumber, - globalLogIndex - } - ] - }, - { - headers: { - Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, - "Content-Type": "application/json", - Accept: "application/json" - } - } - ); - polymerRequestIndex = requestProof.data.result; - console.log({ requestProof: requestProof.data }); - } - const requestProofData = await axios.post( - POLYMER_URL, - { - jsonrpc: "2.0", - id: 1, - method: "polymer_queryProof", - params: [polymerRequestIndex] - }, - { - headers: { - Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, - "Content-Type": "application/json", - Accept: "application/json" - } - } - ); - const dat: { - jsonrpc: "2.0"; - id: 1; - result: { - jobID: number; - createdAt: number; - updatedAt: number; - } & ( - | { - status: "error"; - failureReason: string; - } - | { - status: "complete"; - proof: "string"; - } - | { - status: "initialized"; - } - ); - } = requestProofData.data; + let polymerRequestIndex = polymerIndex; + if (!polymerRequestIndex) { + const requestProof = await axios.post( + POLYMER_URL, + { + jsonrpc: "2.0", + id: 1, + method: "polymer_requestProof", + params: [ + { + srcChainId, + srcBlockNumber, + globalLogIndex + } + ] + }, + { + headers: { + Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, + "Content-Type": "application/json", + Accept: "application/json" + } + } + ); + polymerRequestIndex = requestProof.data.result; + console.log({ requestProof: requestProof.data }); + } + const requestProofData = await axios.post( + POLYMER_URL, + { + jsonrpc: "2.0", + id: 1, + method: "polymer_queryProof", + params: [polymerRequestIndex] + }, + { + headers: { + Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, + "Content-Type": "application/json", + Accept: "application/json" + } + } + ); + const dat: { + jsonrpc: "2.0"; + id: 1; + result: { + jobID: number; + createdAt: number; + updatedAt: number; + } & ( + | { + status: "error"; + failureReason: string; + } + | { + status: "complete"; + proof: "string"; + } + | { + status: "initialized"; + } + ); + } = requestProofData.data; - let proof: string | undefined; - // decode proof from base64 to hex - if (dat.result.status === "complete") { - proof = dat.result.proof; - const proofBytes = toByteArray(proof); - proof = Array.from(proofBytes) - .map((byte) => byte.toString(16).padStart(2, "0")) - .join(""); - } else { - console.log(dat); - } - // create a JSON Response - return json({ - proof, - polymerIndex: polymerRequestIndex, - status: dat.result.status - }); + let proof: string | undefined; + // decode proof from base64 to hex + if (dat.result.status === "complete") { + proof = dat.result.proof; + const proofBytes = toByteArray(proof); + proof = Array.from(proofBytes) + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); + } else { + console.log(dat); + } + // create a JSON Response + return json({ + proof, + polymerIndex: polymerRequestIndex, + status: dat.result.status + }); }; diff --git a/src/routes/polymer/health/+server.ts b/src/routes/polymer/health/+server.ts index d62f822..e6071ca 100644 --- a/src/routes/polymer/health/+server.ts +++ b/src/routes/polymer/health/+server.ts @@ -2,64 +2,64 @@ import { json } from "@sveltejs/kit"; import axios from "axios"; import type { RequestHandler } from "./$types"; import { - PRIVATE_POLYMER_MAINNET_ZONE_API_KEY, - PRIVATE_POLYMER_TESTNET_ZONE_API_KEY + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY, + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY } from "$env/static/private"; function getPolymerUrl(mainnet: boolean) { - return mainnet - ? ("https://api.polymer.zone/v1/" as const) - : ("https://api.testnet.polymer.zone/v1/" as const); + return mainnet + ? ("https://api.polymer.zone/v1/" as const) + : ("https://api.testnet.polymer.zone/v1/" as const); } function getPolymerKey(mainnet: boolean) { - return mainnet ? PRIVATE_POLYMER_MAINNET_ZONE_API_KEY : PRIVATE_POLYMER_TESTNET_ZONE_API_KEY; + return mainnet ? PRIVATE_POLYMER_MAINNET_ZONE_API_KEY : PRIVATE_POLYMER_TESTNET_ZONE_API_KEY; } export const POST: RequestHandler = async ({ request }) => { - const { chainIds, mainnet }: { chainIds?: number[]; mainnet?: boolean } = await request.json(); + const { chainIds, mainnet }: { chainIds?: number[]; mainnet?: boolean } = await request.json(); - const POLYMER_URL = getPolymerUrl(mainnet ?? true); - const PRIVATE_POLYMER_ZONE_API_KEY = getPolymerKey(mainnet ?? true); + const POLYMER_URL = getPolymerUrl(mainnet ?? true); + const PRIVATE_POLYMER_ZONE_API_KEY = getPolymerKey(mainnet ?? true); - const requestProofData = await axios.post( - POLYMER_URL, - { - jsonrpc: "2.0", - id: 1, - method: "info_health", - params: [{ chain_ids: chainIds ?? [] }] - }, - { - headers: { - Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, - "Content-Type": "application/json", - Accept: "application/json" - } - } - ); + const requestProofData = await axios.post( + POLYMER_URL, + { + jsonrpc: "2.0", + id: 1, + method: "info_health", + params: [{ chain_ids: chainIds ?? [] }] + }, + { + headers: { + Authorization: `Bearer ${PRIVATE_POLYMER_ZONE_API_KEY}`, + "Content-Type": "application/json", + Accept: "application/json" + } + } + ); - const dat: - | ({ - jsonrpc: "2.0"; - id: 1; - } & { - result: { - status: { - [chainId: string]: "healthy" | "unhealthy"; - }; - }; - }) - | { error: { code: -32000; message: `unsupported chain ID(s): [${string}]` } } = - requestProofData.data; + const dat: + | ({ + jsonrpc: "2.0"; + id: 1; + } & { + result: { + status: { + [chainId: string]: "healthy" | "unhealthy"; + }; + }; + }) + | { error: { code: -32000; message: `unsupported chain ID(s): [${string}]` } } = + requestProofData.data; - const failed = "error" in dat; - const status = !failed ? dat.result.status : []; - const error = failed ? dat.error : {}; + const failed = "error" in dat; + const status = !failed ? dat.result.status : []; + const error = failed ? dat.error : {}; - return json({ - failed, - status, - error - }); + return json({ + failed, + status, + error + }); }; diff --git a/svelte.config.js b/svelte.config.js index 9343c0b..a2cfc22 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -3,16 +3,16 @@ import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; /** @type {import('@sveltejs/kit').Config} */ const config = { - // Consult https://svelte.dev/docs/kit/integrations - // for more information about preprocessors - preprocess: vitePreprocess(), + // Consult https://svelte.dev/docs/kit/integrations + // for more information about preprocessors + preprocess: vitePreprocess(), - kit: { - // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. - // If your environment is not supported, or you settled on a specific environment, switch out the adapter. - // See https://svelte.dev/docs/kit/adapters for more information about adapters. - adapter: adapter() - } + kit: { + // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. + // If your environment is not supported, or you settled on a specific environment, switch out the adapter. + // See https://svelte.dev/docs/kit/adapters for more information about adapters. + adapter: adapter() + } }; export default config; diff --git a/tests/db.test.ts b/tests/db.test.ts index 4e452e0..7801b80 100644 --- a/tests/db.test.ts +++ b/tests/db.test.ts @@ -5,50 +5,50 @@ import migrations from "../src/lib/migrations.json"; import { intents } from "../src/lib/schema"; async function createTestDb() { - const pglite = new PGlite({ fs: new MemoryFS("testdb") }); - const db = drizzle(pglite); + const pglite = new PGlite({ fs: new MemoryFS("testdb") }); + const db = drizzle(pglite); - // dialect and session will appear to not exist...but they do on the pglite drizzle instance - // @ts-ignore - await db.dialect.migrate(migrations, db.session, { - migrationsTable: "drizzle_migrations" - }); + // dialect and session will appear to not exist...but they do on the pglite drizzle instance + // @ts-ignore + await db.dialect.migrate(migrations, db.session, { + migrationsTable: "drizzle_migrations" + }); - return { db, pglite }; + return { db, pglite }; } describe("pglite migrations", () => { - it("applies migrations and supports upserts", async () => { - const { db, pglite } = await createTestDb(); - try { - const now = Date.now(); - await db.insert(intents).values({ - id: "1", - orderId: "order-1", - intentType: "escrow", - data: "{}", - createdAt: now - }); + it("applies migrations and supports upserts", async () => { + const { db, pglite } = await createTestDb(); + try { + const now = Date.now(); + await db.insert(intents).values({ + id: "1", + orderId: "order-1", + intentType: "escrow", + data: "{}", + createdAt: now + }); - await db - .insert(intents) - .values({ - id: "2", - orderId: "order-1", - intentType: "escrow", - data: '{"v":2}', - createdAt: now - }) - .onConflictDoUpdate({ - target: intents.orderId, - set: { data: '{"v":2}' } - }); + await db + .insert(intents) + .values({ + id: "2", + orderId: "order-1", + intentType: "escrow", + data: '{"v":2}', + createdAt: now + }) + .onConflictDoUpdate({ + target: intents.orderId, + set: { data: '{"v":2}' } + }); - const rows = await db.select().from(intents); - expect(rows).toHaveLength(1); - expect(rows[0].data).toBe('{"v":2}'); - } finally { - await pglite.close(); - } - }); + const rows = await db.select().from(intents); + expect(rows).toHaveLength(1); + expect(rows[0].data).toBe('{"v":2}'); + } finally { + await pglite.close(); + } + }); }); diff --git a/tests/e2e/escrow-standard-blackbox.spec.ts b/tests/e2e/escrow-standard-blackbox.spec.ts index a8247fd..80cbc04 100644 --- a/tests/e2e/escrow-standard-blackbox.spec.ts +++ b/tests/e2e/escrow-standard-blackbox.spec.ts @@ -1,9 +1,9 @@ import { expect, test, type Page } from "@playwright/test"; import { - connectInjectedWallet, - e2eWalletAddress, - hasE2EPrivateKey, - installInjectedWalletProvider + connectInjectedWallet, + e2eWalletAddress, + hasE2EPrivateKey, + installInjectedWalletProvider } from "./helpers/bootstrap"; const REQUIRED_INPUT_USDC_HUMAN = "0.0001"; @@ -22,275 +22,275 @@ test.skip(!hasE2EPrivateKey, "Skipping private-key E2E tests: E2E_PRIVATE_KEY is test.setTimeout(TEST_TIMEOUT_MS); async function expectRightRailState(page: Page, state: FlowState) { - const entries = Object.entries(state) as Array<[FlowStepName, FlowStepStatus]>; - for (const [step, status] of entries) { - await expect(page.getByRole("button", { name: `${step} (${status})` })).toBeVisible({ - timeout: UI_TIMEOUT_MS - }); - } + const entries = Object.entries(state) as Array<[FlowStepName, FlowStepStatus]>; + for (const [step, status] of entries) { + await expect(page.getByRole("button", { name: `${step} (${status})` })).toBeVisible({ + timeout: UI_TIMEOUT_MS + }); + } } async function lockVerticalScrollAtTop(page: Page) { - await page.addInitScript(() => { - const enforceTop = () => { - if (window.scrollY > 0) window.scrollTo(0, 0); - }; - window.addEventListener("scroll", enforceTop, { passive: true }); - window.addEventListener("load", enforceTop); - }); + await page.addInitScript(() => { + const enforceTop = () => { + if (window.scrollY > 0) window.scrollTo(0, 0); + }; + window.addEventListener("scroll", enforceTop, { passive: true }); + window.addEventListener("load", enforceTop); + }); } test("black-box escrow flow shows expected UI state transitions", async ({ page }) => { - const issuerAddress = e2eWalletAddress(); - let sawRequiredInputAmount = false; - const getReceiptCount = async () => - await page.evaluate(async () => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - return Object.keys(store.transactionReceipts).length; - }); - - await lockVerticalScrollAtTop(page); - - await page.route("**/quote/request", async (route) => { - const body = route.request().postDataJSON() as - | { - intent?: { - inputs?: Array<{ amount?: string }>; - }; - } - | undefined; - const totalInputRaw = (body?.intent?.inputs ?? []).reduce((sum, input) => { - try { - return sum + BigInt(input.amount ?? "0"); - } catch { - return sum; - } - }, 0n); - if (totalInputRaw.toString() === REQUIRED_INPUT_USDC_RAW) { - sawRequiredInputAmount = true; - } - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - quotes: [ - { - order: null, - eta: null, - validUntil: Date.now() + 60_000, - quoteId: null, - metadata: { exclusiveFor: issuerAddress }, - preview: { - inputs: [], - outputs: [ - { - receiver: "0x0000000000000000000000000000000000000000", - asset: "0x0000000000000000000000000000000000000000", - amount: REQUIRED_INPUT_USDC_RAW - } - ] - }, - provider: null, - partialFill: false, - failureHandling: "refund-automatic" - } - ] - }) - }); - }); - - await installInjectedWalletProvider(page); - await page.goto("/"); - await connectInjectedWallet(page); - - await expect(page.getByRole("heading", { name: "Assets Management" })).toBeVisible(); - await expectRightRailState(page, { - Asset: "Now", - Issue: "Next", - Fetch: "Next", - Fill: "Locked", - Prove: "Locked", - Claim: "Locked" - }); - - await page.getByTestId("network-mainnet").click(); - await page.getByTestId("intent-type-escrow").click(); - - await page.getByRole("button", { name: "→" }).first().click(); - await expect(page.getByRole("heading", { name: "Intent Issuance" })).toBeVisible(); - await expectRightRailState(page, { - Asset: "Done", - Issue: "Now", - Fetch: "Next", - Fill: "Locked", - Prove: "Locked", - Claim: "Locked" - }); - - await page.getByTestId("open-input-modal-0").click(); - const inputModal = page.getByTestId("input-token-modal"); - await expect(inputModal).toBeVisible({ timeout: UI_TIMEOUT_MS }); - await inputModal.locator("select#tokenSelector").selectOption("usdc"); - - const baseRow = inputModal.getByTestId("input-token-row-base"); - await baseRow.locator('input[type="checkbox"]').check(); - await baseRow.locator('input[type="number"]').fill(REQUIRED_INPUT_USDC_HUMAN); - await page.getByTestId("input-token-modal-save").click(); - await expect(inputModal).toBeHidden({ timeout: UI_TIMEOUT_MS }); - - const exclusiveInput = page.getByPlaceholder("0x... (optional)"); - await exclusiveInput.fill(issuerAddress); - await page.getByLabel("Lock Exclusive").check(); - await expect(exclusiveInput).toHaveValue(issuerAddress); - - await page.getByTestId("quote-button").click(); - await expect(page.getByTestId("quote-button")).toBeVisible(); - await expect.poll(() => sawRequiredInputAmount).toBe(true); - - if ( - await page - .getByRole("button", { name: "Set allowance" }) - .isVisible() - .catch(() => false) - ) { - await page.getByRole("button", { name: "Set allowance" }).click(); - } - - const executeOpenButton = page.getByRole("button", { name: "Execute Open" }); - await expect(executeOpenButton).toBeVisible({ timeout: TX_TIMEOUT_MS }); - await executeOpenButton.click(); - - await expect(page.getByRole("heading", { name: "Select Intent To Solve" })).toBeVisible({ - timeout: TX_TIMEOUT_MS - }); - await expectRightRailState(page, { - Asset: "Done", - Issue: "Done", - Fetch: "Now", - Fill: "Locked", - Prove: "Locked", - Claim: "Locked" - }); - - const activeIntentRow = page.getByRole("button", { name: /SingleChain/i }).first(); - await expect(activeIntentRow).toBeVisible({ timeout: UI_TIMEOUT_MS }); - await expect(page.getByRole("button", { name: /IN 0\.0001 USDC on base/i }).first()).toBeVisible({ - timeout: UI_TIMEOUT_MS - }); - await activeIntentRow.click(); - const currentOrder = await page.evaluate(async () => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - const { buildBaseIntentRow } = await import("/src/lib/libraries/intentList.ts"); - const latest = store.orders.at(-1); - if (!latest) return null; - const baseRow = buildBaseIntentRow(latest); - - const order = latest.order as - | { originChainId?: bigint } - | { inputs?: Array<{ chainId: bigint }> }; - const inputChainId = - "originChainId" in order && typeof order.originChainId === "bigint" - ? order.originChainId.toString() - : (order.inputs?.[0]?.chainId?.toString() ?? ""); - - return { - orderId: baseRow.orderId, - inputSettler: latest.inputSettler, - inputChainId - }; - }); - expect(currentOrder).not.toBeNull(); - - await expect(page.getByRole("heading", { name: "Fill Intent" })).toBeVisible({ - timeout: UI_TIMEOUT_MS - }); - await expectRightRailState(page, { - Asset: "Done", - Issue: "Done", - Fetch: "Done", - Fill: "Now", - Prove: "Locked", - Claim: "Locked" - }); - - const fillButton = page.getByRole("button", { name: /^Fill$/ }).first(); - await expect(fillButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); - await fillButton.click(); - - await expect(page.getByRole("heading", { name: "Submit Proof of Fill" })).toBeVisible({ - timeout: TX_TIMEOUT_MS - }); - await expectRightRailState(page, { - Asset: "Done", - Issue: "Done", - Fetch: "Done", - Fill: "Done", - Prove: "Now", - Claim: "Locked" - }); - - const proveButton = page.getByRole("button", { name: /^\d+(\.\d+)?\s+USDC$/ }).first(); - let reachedFinalise = false; - for (let attempt = 0; attempt < 4; attempt++) { - await expect(proveButton).toBeVisible({ timeout: UI_TIMEOUT_MS }); - await expect(proveButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); - await proveButton.click(); - try { - await expect(page.getByRole("heading", { name: "Finalise Intent" })).toBeVisible({ - timeout: PROVE_ATTEMPT_TIMEOUT_MS - }); - reachedFinalise = true; - break; - } catch { - await page.waitForTimeout(3_000); - } - } - expect(reachedFinalise).toBe(true); - - await expectRightRailState(page, { - Asset: "Done", - Issue: "Done", - Fetch: "Done", - Fill: "Done", - Prove: "Done", - Claim: "Now" - }); - - const claimButton = page.getByRole("button", { name: "Claim" }).first(); - await expect(claimButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); - const receiptsBeforeClaim = await getReceiptCount(); - await claimButton.click(); - - await expect - .poll(async () => await getReceiptCount(), { timeout: TX_TIMEOUT_MS }) - .toBeGreaterThan(receiptsBeforeClaim); - - await expect - .poll( - async () => - await page.evaluate(async (orderMeta) => { - const { getClient } = await import("/src/lib/config.ts"); - const { SETTLER_ESCROW_ABI } = await import("/src/lib/abi/escrow.ts"); - if (!orderMeta) return -1; - const status = await getClient(orderMeta.inputChainId).readContract({ - address: orderMeta.inputSettler as `0x${string}`, - abi: SETTLER_ESCROW_ABI, - functionName: "orderStatus", - args: [orderMeta.orderId as `0x${string}`] - }); - return Number(status); - }, currentOrder), - { timeout: TX_TIMEOUT_MS } - ) - .toBe(ORDER_STATUS_CLAIMED); - - await expectRightRailState(page, { - Asset: "Done", - Issue: "Done", - Fetch: "Done", - Fill: "Done", - Prove: "Done", - Claim: "Now" - }); + const issuerAddress = e2eWalletAddress(); + let sawRequiredInputAmount = false; + const getReceiptCount = async () => + await page.evaluate(async () => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + return Object.keys(store.transactionReceipts).length; + }); + + await lockVerticalScrollAtTop(page); + + await page.route("**/quote/request", async (route) => { + const body = route.request().postDataJSON() as + | { + intent?: { + inputs?: Array<{ amount?: string }>; + }; + } + | undefined; + const totalInputRaw = (body?.intent?.inputs ?? []).reduce((sum, input) => { + try { + return sum + BigInt(input.amount ?? "0"); + } catch { + return sum; + } + }, 0n); + if (totalInputRaw.toString() === REQUIRED_INPUT_USDC_RAW) { + sawRequiredInputAmount = true; + } + + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + quotes: [ + { + order: null, + eta: null, + validUntil: Date.now() + 60_000, + quoteId: null, + metadata: { exclusiveFor: issuerAddress }, + preview: { + inputs: [], + outputs: [ + { + receiver: "0x0000000000000000000000000000000000000000", + asset: "0x0000000000000000000000000000000000000000", + amount: REQUIRED_INPUT_USDC_RAW + } + ] + }, + provider: null, + partialFill: false, + failureHandling: "refund-automatic" + } + ] + }) + }); + }); + + await installInjectedWalletProvider(page); + await page.goto("/"); + await connectInjectedWallet(page); + + await expect(page.getByRole("heading", { name: "Assets Management" })).toBeVisible(); + await expectRightRailState(page, { + Asset: "Now", + Issue: "Next", + Fetch: "Next", + Fill: "Locked", + Prove: "Locked", + Claim: "Locked" + }); + + await page.getByTestId("network-mainnet").click(); + await page.getByTestId("intent-type-escrow").click(); + + await page.getByRole("button", { name: "→" }).first().click(); + await expect(page.getByRole("heading", { name: "Intent Issuance" })).toBeVisible(); + await expectRightRailState(page, { + Asset: "Done", + Issue: "Now", + Fetch: "Next", + Fill: "Locked", + Prove: "Locked", + Claim: "Locked" + }); + + await page.getByTestId("open-input-modal-0").click(); + const inputModal = page.getByTestId("input-token-modal"); + await expect(inputModal).toBeVisible({ timeout: UI_TIMEOUT_MS }); + await inputModal.locator("select#tokenSelector").selectOption("usdc"); + + const baseRow = inputModal.getByTestId("input-token-row-base"); + await baseRow.locator('input[type="checkbox"]').check(); + await baseRow.locator('input[type="number"]').fill(REQUIRED_INPUT_USDC_HUMAN); + await page.getByTestId("input-token-modal-save").click(); + await expect(inputModal).toBeHidden({ timeout: UI_TIMEOUT_MS }); + + const exclusiveInput = page.getByPlaceholder("0x... (optional)"); + await exclusiveInput.fill(issuerAddress); + await page.getByLabel("Lock Exclusive").check(); + await expect(exclusiveInput).toHaveValue(issuerAddress); + + await page.getByTestId("quote-button").click(); + await expect(page.getByTestId("quote-button")).toBeVisible(); + await expect.poll(() => sawRequiredInputAmount).toBe(true); + + if ( + await page + .getByRole("button", { name: "Set allowance" }) + .isVisible() + .catch(() => false) + ) { + await page.getByRole("button", { name: "Set allowance" }).click(); + } + + const executeOpenButton = page.getByRole("button", { name: "Execute Open" }); + await expect(executeOpenButton).toBeVisible({ timeout: TX_TIMEOUT_MS }); + await executeOpenButton.click(); + + await expect(page.getByRole("heading", { name: "Select Intent To Solve" })).toBeVisible({ + timeout: TX_TIMEOUT_MS + }); + await expectRightRailState(page, { + Asset: "Done", + Issue: "Done", + Fetch: "Now", + Fill: "Locked", + Prove: "Locked", + Claim: "Locked" + }); + + const activeIntentRow = page.getByRole("button", { name: /SingleChain/i }).first(); + await expect(activeIntentRow).toBeVisible({ timeout: UI_TIMEOUT_MS }); + await expect(page.getByRole("button", { name: /IN 0\.0001 USDC on base/i }).first()).toBeVisible({ + timeout: UI_TIMEOUT_MS + }); + await activeIntentRow.click(); + const currentOrder = await page.evaluate(async () => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + const { buildBaseIntentRow } = await import("/src/lib/libraries/intentList.ts"); + const latest = store.orders.at(-1); + if (!latest) return null; + const baseRow = buildBaseIntentRow(latest); + + const order = latest.order as + | { originChainId?: bigint } + | { inputs?: Array<{ chainId: bigint }> }; + const inputChainId = + "originChainId" in order && typeof order.originChainId === "bigint" + ? order.originChainId.toString() + : (order.inputs?.[0]?.chainId?.toString() ?? ""); + + return { + orderId: baseRow.orderId, + inputSettler: latest.inputSettler, + inputChainId + }; + }); + expect(currentOrder).not.toBeNull(); + + await expect(page.getByRole("heading", { name: "Fill Intent" })).toBeVisible({ + timeout: UI_TIMEOUT_MS + }); + await expectRightRailState(page, { + Asset: "Done", + Issue: "Done", + Fetch: "Done", + Fill: "Now", + Prove: "Locked", + Claim: "Locked" + }); + + const fillButton = page.getByRole("button", { name: /^Fill$/ }).first(); + await expect(fillButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); + await fillButton.click(); + + await expect(page.getByRole("heading", { name: "Submit Proof of Fill" })).toBeVisible({ + timeout: TX_TIMEOUT_MS + }); + await expectRightRailState(page, { + Asset: "Done", + Issue: "Done", + Fetch: "Done", + Fill: "Done", + Prove: "Now", + Claim: "Locked" + }); + + const proveButton = page.getByRole("button", { name: /^\d+(\.\d+)?\s+USDC$/ }).first(); + let reachedFinalise = false; + for (let attempt = 0; attempt < 4; attempt++) { + await expect(proveButton).toBeVisible({ timeout: UI_TIMEOUT_MS }); + await expect(proveButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); + await proveButton.click(); + try { + await expect(page.getByRole("heading", { name: "Finalise Intent" })).toBeVisible({ + timeout: PROVE_ATTEMPT_TIMEOUT_MS + }); + reachedFinalise = true; + break; + } catch { + await page.waitForTimeout(3_000); + } + } + expect(reachedFinalise).toBe(true); + + await expectRightRailState(page, { + Asset: "Done", + Issue: "Done", + Fetch: "Done", + Fill: "Done", + Prove: "Done", + Claim: "Now" + }); + + const claimButton = page.getByRole("button", { name: "Claim" }).first(); + await expect(claimButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); + const receiptsBeforeClaim = await getReceiptCount(); + await claimButton.click(); + + await expect + .poll(async () => await getReceiptCount(), { timeout: TX_TIMEOUT_MS }) + .toBeGreaterThan(receiptsBeforeClaim); + + await expect + .poll( + async () => + await page.evaluate(async (orderMeta) => { + const { getClient } = await import("/src/lib/config.ts"); + const { SETTLER_ESCROW_ABI } = await import("/src/lib/abi/escrow.ts"); + if (!orderMeta) return -1; + const status = await getClient(orderMeta.inputChainId).readContract({ + address: orderMeta.inputSettler as `0x${string}`, + abi: SETTLER_ESCROW_ABI, + functionName: "orderStatus", + args: [orderMeta.orderId as `0x${string}`] + }); + return Number(status); + }, currentOrder), + { timeout: TX_TIMEOUT_MS } + ) + .toBe(ORDER_STATUS_CLAIMED); + + await expectRightRailState(page, { + Asset: "Done", + Issue: "Done", + Fetch: "Done", + Fill: "Done", + Prove: "Done", + Claim: "Now" + }); }); diff --git a/tests/e2e/escrow-standard-live.spec.ts b/tests/e2e/escrow-standard-live.spec.ts index 6e24696..cf444a2 100644 --- a/tests/e2e/escrow-standard-live.spec.ts +++ b/tests/e2e/escrow-standard-live.spec.ts @@ -1,9 +1,9 @@ import { expect, test, type Page } from "@playwright/test"; import { - connectInjectedWallet, - e2eWalletAddress, - hasE2EPrivateKey, - installInjectedWalletProvider + connectInjectedWallet, + e2eWalletAddress, + hasE2EPrivateKey, + installInjectedWalletProvider } from "./helpers/bootstrap"; const REQUIRED_INPUT_USDC_RAW = "100"; @@ -18,263 +18,263 @@ test.skip(!hasE2EPrivateKey, "Skipping private-key E2E tests: E2E_PRIVATE_KEY is test.setTimeout(TEST_TIMEOUT_MS); async function resolveIssuanceActionState(page: Page): Promise<"execute-open" | "low-balance"> { - const executeOpenButton = page.getByRole("button", { name: "Execute Open" }); - const lowBalanceButton = page.getByRole("button", { name: "Low Balance" }); - const started = Date.now(); + const executeOpenButton = page.getByRole("button", { name: "Execute Open" }); + const lowBalanceButton = page.getByRole("button", { name: "Low Balance" }); + const started = Date.now(); - while (Date.now() - started < TX_TIMEOUT_MS) { - if (await lowBalanceButton.isVisible().catch(() => false)) return "low-balance"; - if (await executeOpenButton.isVisible().catch(() => false)) return "execute-open"; - await page.waitForTimeout(200); - } + while (Date.now() - started < TX_TIMEOUT_MS) { + if (await lowBalanceButton.isVisible().catch(() => false)) return "low-balance"; + if (await executeOpenButton.isVisible().catch(() => false)) return "execute-open"; + await page.waitForTimeout(200); + } - throw new Error("Timed out waiting for issuance action state (Execute Open or Low Balance)."); + throw new Error("Timed out waiting for issuance action state (Execute Open or Low Balance)."); } test("executes full standard escrow flow from base to arbitrum with raw input 100", async ({ - page + page }) => { - const issuerAddress = e2eWalletAddress(); - let sawExpectedQuotePayload = false; - let sawExclusiveForIssuer = false; - const getReceiptCount = async () => - await page.evaluate(async () => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - return Object.keys(store.transactionReceipts).length; - }); - - await page.route("**/quote/request", async (route) => { - const body = route.request().postDataJSON() as - | { - intent?: { - metadata?: { exclusiveFor?: string[] | string }; - inputs?: Array<{ amount?: string }>; - outputs?: Array<{ amount?: string }>; - }; - } - | undefined; - - const firstInputAmount = body?.intent?.inputs?.[0]?.amount; - const firstOutputAmount = body?.intent?.outputs?.[0]?.amount; - if (firstInputAmount === REQUIRED_INPUT_USDC_RAW && firstOutputAmount === "0") { - sawExpectedQuotePayload = true; - } - const exclusiveForRaw = body?.intent?.metadata?.exclusiveFor; - const exclusiveFor = - Array.isArray(exclusiveForRaw) && exclusiveForRaw.length > 0 - ? exclusiveForRaw[0] - : (exclusiveForRaw ?? ""); - if (exclusiveFor.toLowerCase() === issuerAddress.toLowerCase()) { - sawExclusiveForIssuer = true; - } - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - quotes: [ - { - order: null, - eta: null, - validUntil: Date.now() + 60_000, - quoteId: null, - metadata: { exclusiveFor: issuerAddress }, - preview: { - inputs: [], - outputs: [ - { - receiver: "0x0000000000000000000000000000000000000000", - asset: "0x0000000000000000000000000000000000000000", - amount: REQUIRED_INPUT_USDC_RAW - } - ] - }, - provider: null, - partialFill: false, - failureHandling: "refund-automatic" - } - ] - }) - }); - }); - - await installInjectedWalletProvider(page); - await page.goto("/"); - await connectInjectedWallet(page); - - await expect(page.getByRole("heading", { name: "Assets Management" })).toBeVisible(); - await page.getByTestId("network-mainnet").click(); - await page.getByTestId("intent-type-escrow").click(); - - // Keep the flow deterministic by fixing tiny standard-order assets directly in state. - await page.evaluate( - async ({ amount, issuer }) => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - const { coinList, chainMap } = await import("/src/lib/config"); - const coins = coinList(true); - const baseUsdc = coins.find( - (token) => token.chainId === chainMap.base.id && token.name === "usdc" - ); - const arbitrumUsdc = coins.find( - (token) => token.chainId === chainMap.arbitrum.id && token.name === "usdc" - ); - if (!baseUsdc || !arbitrumUsdc) { - throw new Error("Could not resolve base/arbitrum USDC from coin list."); - } - - store.mainnet = true; - store.intentType = "escrow"; - store.orders = []; - store.inputTokens = [{ token: baseUsdc, amount: BigInt(amount) }]; - store.outputTokens = [{ token: arbitrumUsdc, amount: BigInt(amount) }]; - store.exclusiveFor = issuer; - store.useExclusiveForQuoteRequest = true; - }, - { amount: REQUIRED_INPUT_USDC_RAW, issuer: issuerAddress } - ); - - await page.getByRole("button", { name: "→" }).first().click(); - await expect(page.getByRole("heading", { name: "Intent Issuance" })).toBeVisible(); - - await page.getByTestId("quote-button").click(); - await expect.poll(() => sawExpectedQuotePayload).toBe(true); - await expect.poll(() => sawExclusiveForIssuer).toBe(true); - - if ( - await page - .getByRole("button", { name: "Set allowance" }) - .isVisible() - .catch(() => false) - ) { - await page.getByRole("button", { name: "Set allowance" }).click(); - } - - const actionState = await resolveIssuanceActionState(page); - if (actionState === "low-balance") { - test.skip(true, "Skipping live flow: wallet has insufficient Base USDC for Execute Open."); - } - - await page.getByRole("button", { name: "Execute Open" }).click(); - await expect(page.getByRole("heading", { name: "Select Intent To Solve" })).toBeVisible({ - timeout: TX_TIMEOUT_MS - }); - - const activeIntentRow = page.getByRole("button", { name: /SingleChain/i }).first(); - await expect(activeIntentRow).toBeVisible({ timeout: TX_TIMEOUT_MS }); - await activeIntentRow.click(); - - const currentOrder = await page.evaluate(async () => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - const { buildBaseIntentRow } = await import("/src/lib/libraries/intentList.ts"); - const latest = store.orders.at(-1); - if (!latest) return null; - const baseRow = buildBaseIntentRow(latest); - - const order = latest.order as - | { originChainId?: bigint } - | { inputs?: Array<{ chainId: bigint }> }; - const inputChainId = - "originChainId" in order && typeof order.originChainId === "bigint" - ? order.originChainId.toString() - : (order.inputs?.[0]?.chainId?.toString() ?? ""); - - return { - orderId: baseRow.orderId, - inputSettler: latest.inputSettler, - inputChainId - }; - }); - expect(currentOrder).not.toBeNull(); - const observedInputRaw = await page.evaluate(async () => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - const latest = store.orders.at(-1) as - | { order?: { inputs?: Array<[bigint, bigint]> } } - | undefined; - const inputs = latest?.order?.inputs; - if (!inputs || inputs.length === 0) return null; - const sum = inputs.reduce((acc, input) => acc + input[1], 0n); - return sum.toString(); - }); - // Exact raw input is asserted at quote request time; here we assert the selected order still has input. - expect(observedInputRaw).not.toBeNull(); - expect(BigInt(observedInputRaw as string)).toBeGreaterThan(0n); - - await expect(page.getByRole("heading", { name: "Fill Intent" })).toBeVisible({ - timeout: UI_TIMEOUT_MS - }); - await expect(page.getByText(/^arbitrum$/i).last()).toBeVisible(); - - const fillButton = page.getByRole("button", { name: /^Fill$/ }).first(); - await expect(fillButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); - const receiptsBeforeFill = await getReceiptCount(); - await fillButton.click(); - - await expect - .poll(async () => await getReceiptCount(), { timeout: TX_TIMEOUT_MS }) - .toBeGreaterThan(receiptsBeforeFill); - - await expect(page.getByRole("heading", { name: "Submit Proof of Fill" })).toBeVisible({ - timeout: TX_TIMEOUT_MS - }); - - const proveButton = page.getByRole("button", { name: /^\d+(\.\d+)?\s+USDC$/ }).first(); - let validated = false; - for (let attempt = 0; attempt < 4; attempt++) { - await expect(proveButton).toBeVisible({ timeout: UI_TIMEOUT_MS }); - await expect(proveButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); - await proveButton.click(); - try { - await expect - .poll( - async () => - await page.evaluate(async () => { - const { default: store } = await import("/src/lib/state.svelte.ts"); - const { getOrderProgressChecks } = await import("/src/lib/libraries/flowProgress.ts"); - const latest = store.orders.at(-1); - if (!latest) return false; - const checks = await getOrderProgressChecks(latest, store.fillTransactions); - return checks.allValidated; - }), - { timeout: PROVE_ATTEMPT_TIMEOUT_MS, intervals: [1_000, 2_000, 4_000] } - ) - .toBe(true); - validated = true; - break; - } catch { - await page.waitForTimeout(3_000); - } - } - expect(validated).toBe(true); - - await expect(page.getByRole("heading", { name: "Finalise Intent" })).toBeVisible({ - timeout: TX_TIMEOUT_MS - }); - - const claimButton = page.getByRole("button", { name: "Claim" }).first(); - await expect(claimButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); - const receiptsBeforeClaim = await getReceiptCount(); - await claimButton.click(); - - await expect - .poll(async () => await getReceiptCount(), { timeout: TX_TIMEOUT_MS }) - .toBeGreaterThan(receiptsBeforeClaim); - - await expect - .poll( - async () => - await page.evaluate(async (orderMeta) => { - const { getClient } = await import("/src/lib/config.ts"); - const { SETTLER_ESCROW_ABI } = await import("/src/lib/abi/escrow.ts"); - if (!orderMeta) return -1; - const status = await getClient(orderMeta.inputChainId).readContract({ - address: orderMeta.inputSettler as `0x${string}`, - abi: SETTLER_ESCROW_ABI, - functionName: "orderStatus", - args: [orderMeta.orderId as `0x${string}`] - }); - return Number(status); - }, currentOrder), - { timeout: TX_TIMEOUT_MS } - ) - .toBe(ORDER_STATUS_CLAIMED); + const issuerAddress = e2eWalletAddress(); + let sawExpectedQuotePayload = false; + let sawExclusiveForIssuer = false; + const getReceiptCount = async () => + await page.evaluate(async () => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + return Object.keys(store.transactionReceipts).length; + }); + + await page.route("**/quote/request", async (route) => { + const body = route.request().postDataJSON() as + | { + intent?: { + metadata?: { exclusiveFor?: string[] | string }; + inputs?: Array<{ amount?: string }>; + outputs?: Array<{ amount?: string }>; + }; + } + | undefined; + + const firstInputAmount = body?.intent?.inputs?.[0]?.amount; + const firstOutputAmount = body?.intent?.outputs?.[0]?.amount; + if (firstInputAmount === REQUIRED_INPUT_USDC_RAW && firstOutputAmount === "0") { + sawExpectedQuotePayload = true; + } + const exclusiveForRaw = body?.intent?.metadata?.exclusiveFor; + const exclusiveFor = + Array.isArray(exclusiveForRaw) && exclusiveForRaw.length > 0 + ? exclusiveForRaw[0] + : (exclusiveForRaw ?? ""); + if (exclusiveFor.toLowerCase() === issuerAddress.toLowerCase()) { + sawExclusiveForIssuer = true; + } + + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify({ + quotes: [ + { + order: null, + eta: null, + validUntil: Date.now() + 60_000, + quoteId: null, + metadata: { exclusiveFor: issuerAddress }, + preview: { + inputs: [], + outputs: [ + { + receiver: "0x0000000000000000000000000000000000000000", + asset: "0x0000000000000000000000000000000000000000", + amount: REQUIRED_INPUT_USDC_RAW + } + ] + }, + provider: null, + partialFill: false, + failureHandling: "refund-automatic" + } + ] + }) + }); + }); + + await installInjectedWalletProvider(page); + await page.goto("/"); + await connectInjectedWallet(page); + + await expect(page.getByRole("heading", { name: "Assets Management" })).toBeVisible(); + await page.getByTestId("network-mainnet").click(); + await page.getByTestId("intent-type-escrow").click(); + + // Keep the flow deterministic by fixing tiny standard-order assets directly in state. + await page.evaluate( + async ({ amount, issuer }) => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + const { coinList, chainMap } = await import("/src/lib/config"); + const coins = coinList(true); + const baseUsdc = coins.find( + (token) => token.chainId === chainMap.base.id && token.name === "usdc" + ); + const arbitrumUsdc = coins.find( + (token) => token.chainId === chainMap.arbitrum.id && token.name === "usdc" + ); + if (!baseUsdc || !arbitrumUsdc) { + throw new Error("Could not resolve base/arbitrum USDC from coin list."); + } + + store.mainnet = true; + store.intentType = "escrow"; + store.orders = []; + store.inputTokens = [{ token: baseUsdc, amount: BigInt(amount) }]; + store.outputTokens = [{ token: arbitrumUsdc, amount: BigInt(amount) }]; + store.exclusiveFor = issuer; + store.useExclusiveForQuoteRequest = true; + }, + { amount: REQUIRED_INPUT_USDC_RAW, issuer: issuerAddress } + ); + + await page.getByRole("button", { name: "→" }).first().click(); + await expect(page.getByRole("heading", { name: "Intent Issuance" })).toBeVisible(); + + await page.getByTestId("quote-button").click(); + await expect.poll(() => sawExpectedQuotePayload).toBe(true); + await expect.poll(() => sawExclusiveForIssuer).toBe(true); + + if ( + await page + .getByRole("button", { name: "Set allowance" }) + .isVisible() + .catch(() => false) + ) { + await page.getByRole("button", { name: "Set allowance" }).click(); + } + + const actionState = await resolveIssuanceActionState(page); + if (actionState === "low-balance") { + test.skip(true, "Skipping live flow: wallet has insufficient Base USDC for Execute Open."); + } + + await page.getByRole("button", { name: "Execute Open" }).click(); + await expect(page.getByRole("heading", { name: "Select Intent To Solve" })).toBeVisible({ + timeout: TX_TIMEOUT_MS + }); + + const activeIntentRow = page.getByRole("button", { name: /SingleChain/i }).first(); + await expect(activeIntentRow).toBeVisible({ timeout: TX_TIMEOUT_MS }); + await activeIntentRow.click(); + + const currentOrder = await page.evaluate(async () => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + const { buildBaseIntentRow } = await import("/src/lib/libraries/intentList.ts"); + const latest = store.orders.at(-1); + if (!latest) return null; + const baseRow = buildBaseIntentRow(latest); + + const order = latest.order as + | { originChainId?: bigint } + | { inputs?: Array<{ chainId: bigint }> }; + const inputChainId = + "originChainId" in order && typeof order.originChainId === "bigint" + ? order.originChainId.toString() + : (order.inputs?.[0]?.chainId?.toString() ?? ""); + + return { + orderId: baseRow.orderId, + inputSettler: latest.inputSettler, + inputChainId + }; + }); + expect(currentOrder).not.toBeNull(); + const observedInputRaw = await page.evaluate(async () => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + const latest = store.orders.at(-1) as + | { order?: { inputs?: Array<[bigint, bigint]> } } + | undefined; + const inputs = latest?.order?.inputs; + if (!inputs || inputs.length === 0) return null; + const sum = inputs.reduce((acc, input) => acc + input[1], 0n); + return sum.toString(); + }); + // Exact raw input is asserted at quote request time; here we assert the selected order still has input. + expect(observedInputRaw).not.toBeNull(); + expect(BigInt(observedInputRaw as string)).toBeGreaterThan(0n); + + await expect(page.getByRole("heading", { name: "Fill Intent" })).toBeVisible({ + timeout: UI_TIMEOUT_MS + }); + await expect(page.getByText(/^arbitrum$/i).last()).toBeVisible(); + + const fillButton = page.getByRole("button", { name: /^Fill$/ }).first(); + await expect(fillButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); + const receiptsBeforeFill = await getReceiptCount(); + await fillButton.click(); + + await expect + .poll(async () => await getReceiptCount(), { timeout: TX_TIMEOUT_MS }) + .toBeGreaterThan(receiptsBeforeFill); + + await expect(page.getByRole("heading", { name: "Submit Proof of Fill" })).toBeVisible({ + timeout: TX_TIMEOUT_MS + }); + + const proveButton = page.getByRole("button", { name: /^\d+(\.\d+)?\s+USDC$/ }).first(); + let validated = false; + for (let attempt = 0; attempt < 4; attempt++) { + await expect(proveButton).toBeVisible({ timeout: UI_TIMEOUT_MS }); + await expect(proveButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); + await proveButton.click(); + try { + await expect + .poll( + async () => + await page.evaluate(async () => { + const { default: store } = await import("/src/lib/state.svelte.ts"); + const { getOrderProgressChecks } = await import("/src/lib/libraries/flowProgress.ts"); + const latest = store.orders.at(-1); + if (!latest) return false; + const checks = await getOrderProgressChecks(latest, store.fillTransactions); + return checks.allValidated; + }), + { timeout: PROVE_ATTEMPT_TIMEOUT_MS, intervals: [1_000, 2_000, 4_000] } + ) + .toBe(true); + validated = true; + break; + } catch { + await page.waitForTimeout(3_000); + } + } + expect(validated).toBe(true); + + await expect(page.getByRole("heading", { name: "Finalise Intent" })).toBeVisible({ + timeout: TX_TIMEOUT_MS + }); + + const claimButton = page.getByRole("button", { name: "Claim" }).first(); + await expect(claimButton).toBeEnabled({ timeout: UI_TIMEOUT_MS }); + const receiptsBeforeClaim = await getReceiptCount(); + await claimButton.click(); + + await expect + .poll(async () => await getReceiptCount(), { timeout: TX_TIMEOUT_MS }) + .toBeGreaterThan(receiptsBeforeClaim); + + await expect + .poll( + async () => + await page.evaluate(async (orderMeta) => { + const { getClient } = await import("/src/lib/config.ts"); + const { SETTLER_ESCROW_ABI } = await import("/src/lib/abi/escrow.ts"); + if (!orderMeta) return -1; + const status = await getClient(orderMeta.inputChainId).readContract({ + address: orderMeta.inputSettler as `0x${string}`, + abi: SETTLER_ESCROW_ABI, + functionName: "orderStatus", + args: [orderMeta.orderId as `0x${string}`] + }); + return Number(status); + }, currentOrder), + { timeout: TX_TIMEOUT_MS } + ) + .toBe(ORDER_STATUS_CLAIMED); }); diff --git a/tests/e2e/helpers/bootstrap.ts b/tests/e2e/helpers/bootstrap.ts index 367b7a4..21456d2 100644 --- a/tests/e2e/helpers/bootstrap.ts +++ b/tests/e2e/helpers/bootstrap.ts @@ -7,19 +7,19 @@ import { privateKeyToAccount } from "viem/accounts"; import { arbitrum, base } from "viem/chains"; type ProviderPayload = { - method: string; - params?: unknown[]; + method: string; + params?: unknown[]; }; function ensureEnvLoaded() { - const envFilePath = process.env.E2E_ENV_FILE?.trim() || ".env"; - loadDotenv({ path: envFilePath, quiet: true }); + const envFilePath = process.env.E2E_ENV_FILE?.trim() || ".env"; + loadDotenv({ path: envFilePath, quiet: true }); } ensureEnvLoaded(); function getE2EEnv(name: string) { - return process.env[name]?.trim(); + return process.env[name]?.trim(); } export const hasE2EPrivateKey = Boolean(getE2EEnv("E2E_PRIVATE_KEY")); @@ -28,13 +28,13 @@ const BASE_CHAIN_ID = base.id; const ARBITRUM_CHAIN_ID = arbitrum.id; const BASE_USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" as const; const ERC20_BALANCE_OF_ABI = [ - { - type: "function", - name: "balanceOf", - stateMutability: "view", - inputs: [{ name: "owner", type: "address" }], - outputs: [{ name: "", type: "uint256" }] - } + { + type: "function", + name: "balanceOf", + stateMutability: "view", + inputs: [{ name: "owner", type: "address" }], + outputs: [{ name: "", type: "uint256" }] + } ] as const; const baseRpcUrl = getE2EEnv("E2E_BASE_RPC_URL") || "https://base-rpc.publicnode.com"; const arbitrumRpcUrl = getE2EEnv("E2E_ARBITRUM_RPC_URL") || "https://arbitrum-rpc.publicnode.com"; @@ -44,218 +44,218 @@ let walletClientByChainCache: Record | undefined; function rpcUrlForChain(chainId: number): string { - if (chainId === BASE_CHAIN_ID) return baseRpcUrl; - if (chainId === ARBITRUM_CHAIN_ID) return arbitrumRpcUrl; - throw new Error(`Unsupported chain for E2E wallet provider: ${chainId}`); + if (chainId === BASE_CHAIN_ID) return baseRpcUrl; + if (chainId === ARBITRUM_CHAIN_ID) return arbitrumRpcUrl; + throw new Error(`Unsupported chain for E2E wallet provider: ${chainId}`); } function getWalletContext() { - const configuredPrivateKey = getE2EEnv("E2E_PRIVATE_KEY") as Hex | undefined; - if (!configuredPrivateKey) { - throw new Error("E2E_PRIVATE_KEY is required for E2E wallet injection."); - } - - const account = (accountCache ??= privateKeyToAccount(configuredPrivateKey)); - const walletClientByChain = - walletClientByChainCache ?? - (walletClientByChainCache = { - [BASE_CHAIN_ID]: createWalletClient({ - account, - chain: base, - transport: http(baseRpcUrl) - }), - [ARBITRUM_CHAIN_ID]: createWalletClient({ - account, - chain: arbitrum, - transport: http(arbitrumRpcUrl) - }) - }); - return { account, walletClientByChain }; + const configuredPrivateKey = getE2EEnv("E2E_PRIVATE_KEY") as Hex | undefined; + if (!configuredPrivateKey) { + throw new Error("E2E_PRIVATE_KEY is required for E2E wallet injection."); + } + + const account = (accountCache ??= privateKeyToAccount(configuredPrivateKey)); + const walletClientByChain = + walletClientByChainCache ?? + (walletClientByChainCache = { + [BASE_CHAIN_ID]: createWalletClient({ + account, + chain: base, + transport: http(baseRpcUrl) + }), + [ARBITRUM_CHAIN_ID]: createWalletClient({ + account, + chain: arbitrum, + transport: http(arbitrumRpcUrl) + }) + }); + return { account, walletClientByChain }; } function activeWalletClient() { - const { walletClientByChain } = getWalletContext(); - const walletClient = walletClientByChain[currentChainId]; - if (!walletClient) { - throw new Error(`No wallet client configured for active chain ${currentChainId}.`); - } - return walletClient; + const { walletClientByChain } = getWalletContext(); + const walletClient = walletClientByChain[currentChainId]; + if (!walletClient) { + throw new Error(`No wallet client configured for active chain ${currentChainId}.`); + } + return walletClient; } let currentChainId = Number(process.env.E2E_CHAIN_ID ?? BASE_CHAIN_ID); if (!Number.isFinite(currentChainId)) { - currentChainId = BASE_CHAIN_ID; + currentChainId = BASE_CHAIN_ID; } async function rpcRequest(method: string, params: unknown[] = []) { - const response = await fetch(rpcUrlForChain(currentChainId), { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ - jsonrpc: "2.0", - id: Date.now(), - method, - params - }) - }); - const payload = (await response.json()) as { result?: unknown; error?: { message?: string } }; - if (payload.error) { - throw new Error(payload.error.message ?? `RPC error for method ${method}`); - } - return payload.result; + const response = await fetch(rpcUrlForChain(currentChainId), { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: Date.now(), + method, + params + }) + }); + const payload = (await response.json()) as { result?: unknown; error?: { message?: string } }; + if (payload.error) { + throw new Error(payload.error.message ?? `RPC error for method ${method}`); + } + return payload.result; } function asBigInt(value: unknown): bigint | undefined { - if (typeof value !== "string" || value.length === 0) return undefined; - return BigInt(value); + if (typeof value !== "string" || value.length === 0) return undefined; + return BigInt(value); } async function handleProviderRequest(payload: ProviderPayload) { - const { account } = getWalletContext(); - const { method, params = [] } = payload; - - if (method === "eth_chainId") return toHex(currentChainId); - if (method === "eth_accounts" || method === "eth_requestAccounts") return [account.address]; - if (method === "wallet_switchEthereumChain") { - const nextChainHex = (params[0] as { chainId?: string } | undefined)?.chainId; - if (!nextChainHex) throw new Error("wallet_switchEthereumChain missing chainId"); - currentChainId = Number(BigInt(nextChainHex)); - return null; - } - - if (method === "eth_sendTransaction") { - const walletClient = activeWalletClient(); - const tx = (params[0] as Record | undefined) ?? {}; - return await walletClient.sendTransaction({ - account, - to: tx.to as Hex | undefined, - data: tx.data as Hex | undefined, - value: asBigInt(tx.value), - gas: asBigInt(tx.gas), - maxFeePerGas: asBigInt(tx.maxFeePerGas), - maxPriorityFeePerGas: asBigInt(tx.maxPriorityFeePerGas) - }); - } - - if (method === "eth_signTypedData_v4" || method === "eth_signTypedData") { - const rawTypedData = params[1]; - const typedData = - typeof rawTypedData === "string" - ? (JSON.parse(rawTypedData) as Record) - : ((rawTypedData ?? {}) as Record); - const types = { ...(typedData.types as Record) }; - delete (types as Record).EIP712Domain; - return account.signTypedData({ - domain: (typedData.domain as Record) ?? {}, - types: types as Record, - primaryType: typedData.primaryType as string, - message: (typedData.message as Record) ?? {} - } as never); - } - - if (method === "personal_sign") { - const message = params[0]; - if (typeof message === "string" && message.startsWith("0x")) { - return account.signMessage({ message: { raw: message as Hex } }); - } - return account.signMessage({ message: String(message ?? "") }); - } - - return rpcRequest(method, params); + const { account } = getWalletContext(); + const { method, params = [] } = payload; + + if (method === "eth_chainId") return toHex(currentChainId); + if (method === "eth_accounts" || method === "eth_requestAccounts") return [account.address]; + if (method === "wallet_switchEthereumChain") { + const nextChainHex = (params[0] as { chainId?: string } | undefined)?.chainId; + if (!nextChainHex) throw new Error("wallet_switchEthereumChain missing chainId"); + currentChainId = Number(BigInt(nextChainHex)); + return null; + } + + if (method === "eth_sendTransaction") { + const walletClient = activeWalletClient(); + const tx = (params[0] as Record | undefined) ?? {}; + return await walletClient.sendTransaction({ + account, + to: tx.to as Hex | undefined, + data: tx.data as Hex | undefined, + value: asBigInt(tx.value), + gas: asBigInt(tx.gas), + maxFeePerGas: asBigInt(tx.maxFeePerGas), + maxPriorityFeePerGas: asBigInt(tx.maxPriorityFeePerGas) + }); + } + + if (method === "eth_signTypedData_v4" || method === "eth_signTypedData") { + const rawTypedData = params[1]; + const typedData = + typeof rawTypedData === "string" + ? (JSON.parse(rawTypedData) as Record) + : ((rawTypedData ?? {}) as Record); + const types = { ...(typedData.types as Record) }; + delete (types as Record).EIP712Domain; + return account.signTypedData({ + domain: (typedData.domain as Record) ?? {}, + types: types as Record, + primaryType: typedData.primaryType as string, + message: (typedData.message as Record) ?? {} + } as never); + } + + if (method === "personal_sign") { + const message = params[0]; + if (typeof message === "string" && message.startsWith("0x")) { + return account.signMessage({ message: { raw: message as Hex } }); + } + return account.signMessage({ message: String(message ?? "") }); + } + + return rpcRequest(method, params); } export async function installInjectedWalletProvider(page: Page) { - getWalletContext(); - - await page.exposeFunction("__lintentE2EProviderRequest", (payload: ProviderPayload) => { - return handleProviderRequest(payload); - }); - - await page.addInitScript(() => { - type E2EWindow = Window & - typeof globalThis & { - __lintentE2EProviderRequest: (payload: { - method: string; - params?: unknown[]; - }) => Promise; - __LINTENT_E2E_PROVIDER__?: unknown; - ethereum?: unknown; - }; - const e2eWindow = window as E2EWindow; - - const listeners = new Map void>>(); - const emit = (event: string, value: unknown) => { - const set = listeners.get(event); - if (!set) return; - for (const listener of set) listener(value); - }; - - const provider = { - isMetaMask: false, - request: async ({ method, params }: { method: string; params?: unknown[] }) => { - const result = await e2eWindow.__lintentE2EProviderRequest({ - method, - params: params ?? [] - }); - - if (method === "eth_requestAccounts") emit("accountsChanged", result); - if (method === "wallet_switchEthereumChain") { - const nextChain = (params?.[0] as { chainId?: string } | undefined)?.chainId; - if (nextChain) emit("chainChanged", nextChain); - } - - return result; - }, - enable: async () => { - return await provider.request({ method: "eth_requestAccounts", params: [] }); - }, - on: (event: string, callback: (value: unknown) => void) => { - const set = listeners.get(event) ?? new Set<(value: unknown) => void>(); - set.add(callback); - listeners.set(event, set); - }, - removeListener: (event: string, callback: (value: unknown) => void) => { - listeners.get(event)?.delete(callback); - }, - off: (event: string, callback: (value: unknown) => void) => { - listeners.get(event)?.delete(callback); - } - }; - - e2eWindow.__LINTENT_E2E_PROVIDER__ = provider; - e2eWindow.ethereum = provider; - }); + getWalletContext(); + + await page.exposeFunction("__lintentE2EProviderRequest", (payload: ProviderPayload) => { + return handleProviderRequest(payload); + }); + + await page.addInitScript(() => { + type E2EWindow = Window & + typeof globalThis & { + __lintentE2EProviderRequest: (payload: { + method: string; + params?: unknown[]; + }) => Promise; + __LINTENT_E2E_PROVIDER__?: unknown; + ethereum?: unknown; + }; + const e2eWindow = window as E2EWindow; + + const listeners = new Map void>>(); + const emit = (event: string, value: unknown) => { + const set = listeners.get(event); + if (!set) return; + for (const listener of set) listener(value); + }; + + const provider = { + isMetaMask: false, + request: async ({ method, params }: { method: string; params?: unknown[] }) => { + const result = await e2eWindow.__lintentE2EProviderRequest({ + method, + params: params ?? [] + }); + + if (method === "eth_requestAccounts") emit("accountsChanged", result); + if (method === "wallet_switchEthereumChain") { + const nextChain = (params?.[0] as { chainId?: string } | undefined)?.chainId; + if (nextChain) emit("chainChanged", nextChain); + } + + return result; + }, + enable: async () => { + return await provider.request({ method: "eth_requestAccounts", params: [] }); + }, + on: (event: string, callback: (value: unknown) => void) => { + const set = listeners.get(event) ?? new Set<(value: unknown) => void>(); + set.add(callback); + listeners.set(event, set); + }, + removeListener: (event: string, callback: (value: unknown) => void) => { + listeners.get(event)?.delete(callback); + }, + off: (event: string, callback: (value: unknown) => void) => { + listeners.get(event)?.delete(callback); + } + }; + + e2eWindow.__LINTENT_E2E_PROVIDER__ = provider; + e2eWindow.ethereum = provider; + }); } export async function connectInjectedWallet(page: Page) { - await page.getByRole("button", { name: "Connect Injected" }).click(); + await page.getByRole("button", { name: "Connect Injected" }).click(); } export function e2eWalletAddress() { - const { account } = getWalletContext(); - return account.address; + const { account } = getWalletContext(); + return account.address; } export async function hasBaseUsdcBalance(minimumRawAmount: bigint) { - const { account } = getWalletContext(); - const basePublicClient = - basePublicClientCache ?? - (basePublicClientCache = createPublicClient({ - chain: base, - transport: http(baseRpcUrl) - })); - - const balance = await basePublicClient.readContract({ - address: BASE_USDC, - abi: ERC20_BALANCE_OF_ABI, - functionName: "balanceOf", - args: [account.address] - }); - return balance >= minimumRawAmount; + const { account } = getWalletContext(); + const basePublicClient = + basePublicClientCache ?? + (basePublicClientCache = createPublicClient({ + chain: base, + transport: http(baseRpcUrl) + })); + + const balance = await basePublicClient.readContract({ + address: BASE_USDC, + abi: ERC20_BALANCE_OF_ABI, + functionName: "balanceOf", + args: [account.address] + }); + return balance >= minimumRawAmount; } export async function bootstrapConnectedWallet(page: Page) { - await installInjectedWalletProvider(page); - await page.goto("/"); - await connectInjectedWallet(page); + await installInjectedWalletProvider(page); + await page.goto("/"); + await connectInjectedWallet(page); } diff --git a/tests/fixtures/mockQuote.ts b/tests/fixtures/mockQuote.ts index 458da7a..9852a66 100644 --- a/tests/fixtures/mockQuote.ts +++ b/tests/fixtures/mockQuote.ts @@ -1,24 +1,24 @@ export const mockQuoteResponse = { - quotes: [ - { - order: null, - eta: null, - validUntil: Date.now() + 30_000, - quoteId: null, - metadata: { exclusiveFor: "0x0000000000000000000000000000000000000000" }, - preview: { - inputs: [], - outputs: [ - { - receiver: "0x0000000000000000000000000000000000000000", - asset: "0x0000000000000000000000000000000000000000", - amount: "1000000" - } - ] - }, - provider: null, - partialFill: false, - failureHandling: "refund-automatic" - } - ] + quotes: [ + { + order: null, + eta: null, + validUntil: Date.now() + 30_000, + quoteId: null, + metadata: { exclusiveFor: "0x0000000000000000000000000000000000000000" }, + preview: { + inputs: [], + outputs: [ + { + receiver: "0x0000000000000000000000000000000000000000", + asset: "0x0000000000000000000000000000000000000000", + amount: "1000000" + } + ] + }, + provider: null, + partialFill: false, + failureHandling: "refund-automatic" + } + ] }; diff --git a/tests/fixtures/orderFixtures.ts b/tests/fixtures/orderFixtures.ts index 7128865..ab3a7b5 100644 --- a/tests/fixtures/orderFixtures.ts +++ b/tests/fixtures/orderFixtures.ts @@ -13,49 +13,49 @@ export const TEST_NOW_SECONDS = 1_700_000_000; export const b32 = (nibble: string): `0x${string}` => `0x${nibble.repeat(64)}`; export function makeMandateOutput( - chainId = CHAIN_ID_ARBITRUM, - amount = 1n, - overrides: Partial = {} + chainId = CHAIN_ID_ARBITRUM, + amount = 1n, + overrides: Partial = {} ): MandateOutput { - return { - oracle: addressToBytes32(COIN_FILLER), - settler: addressToBytes32(COIN_FILLER), - chainId, - token: b32("3"), - amount, - recipient: b32("4"), - callbackData: "0x", - context: "0x", - ...overrides - }; + return { + oracle: addressToBytes32(COIN_FILLER), + settler: addressToBytes32(COIN_FILLER), + chainId, + token: b32("3"), + amount, + recipient: b32("4"), + callbackData: "0x", + context: "0x", + ...overrides + }; } export function makeStandardOrder(overrides: Partial = {}): StandardOrder { - return { - user: TEST_USER, - nonce: 1n, - originChainId: CHAIN_ID_ETHEREUM, - expires: TEST_NOW_SECONDS + 1000, - fillDeadline: TEST_NOW_SECONDS + 900, - inputOracle: TEST_POLYMER_ORACLE, - inputs: [[1n, 1n]], - outputs: [makeMandateOutput(CHAIN_ID_ARBITRUM)], - ...overrides - }; + return { + user: TEST_USER, + nonce: 1n, + originChainId: CHAIN_ID_ETHEREUM, + expires: TEST_NOW_SECONDS + 1000, + fillDeadline: TEST_NOW_SECONDS + 900, + inputOracle: TEST_POLYMER_ORACLE, + inputs: [[1n, 1n]], + outputs: [makeMandateOutput(CHAIN_ID_ARBITRUM)], + ...overrides + }; } export function makeMultichainOrder(overrides: Partial = {}): MultichainOrder { - return { - user: TEST_USER, - nonce: 2n, - expires: TEST_NOW_SECONDS + 1000, - fillDeadline: TEST_NOW_SECONDS + 900, - inputOracle: TEST_POLYMER_ORACLE, - outputs: [makeMandateOutput(CHAIN_ID_BASE, 2n)], - inputs: [ - { chainId: CHAIN_ID_ETHEREUM, inputs: [[1n, 1n]] }, - { chainId: CHAIN_ID_ARBITRUM, inputs: [[2n, 2n]] } - ], - ...overrides - }; + return { + user: TEST_USER, + nonce: 2n, + expires: TEST_NOW_SECONDS + 1000, + fillDeadline: TEST_NOW_SECONDS + 900, + inputOracle: TEST_POLYMER_ORACLE, + outputs: [makeMandateOutput(CHAIN_ID_BASE, 2n)], + inputs: [ + { chainId: CHAIN_ID_ETHEREUM, inputs: [[1n, 1n]] }, + { chainId: CHAIN_ID_ARBITRUM, inputs: [[2n, 2n]] } + ], + ...overrides + }; } diff --git a/tests/unit/assetSelection.test.ts b/tests/unit/assetSelection.test.ts index 0fee6c5..0371b8e 100644 --- a/tests/unit/assetSelection.test.ts +++ b/tests/unit/assetSelection.test.ts @@ -2,25 +2,25 @@ import { describe, expect, it } from "bun:test"; import { AssetSelection } from "../../src/lib/libraries/assetSelection"; describe("AssetSelection", () => { - it("picks largest-first values to satisfy goal", () => { - const selector = new AssetSelection({ - goal: 7n, - values: [4n, 4n, 3n] - }).largest(); + it("picks largest-first values to satisfy goal", () => { + const selector = new AssetSelection({ + goal: 7n, + values: [4n, 4n, 3n] + }).largest(); - expect(selector.asValues()).toEqual([4n, 3n, 0n]); - }); + expect(selector.asValues()).toEqual([4n, 3n, 0n]); + }); - it("picks smallest-first values to satisfy goal", () => { - const selector = new AssetSelection({ - goal: 7n, - values: [4n, 4n, 3n] - }).smallest(); + it("picks smallest-first values to satisfy goal", () => { + const selector = new AssetSelection({ + goal: 7n, + values: [4n, 4n, 3n] + }).smallest(); - expect(selector.asValues()).toEqual([4n, 0n, 3n]); - }); + expect(selector.asValues()).toEqual([4n, 0n, 3n]); + }); - it("throws when goal is infeasible", () => { - expect(() => new AssetSelection({ goal: 10n, values: [2n, 3n] })).toThrow(); - }); + it("throws when goal is infeasible", () => { + expect(() => new AssetSelection({ goal: 10n, values: [2n, 3n] })).toThrow(); + }); }); diff --git a/tests/unit/intentList.test.ts b/tests/unit/intentList.test.ts index af30ae3..9c42300 100644 --- a/tests/unit/intentList.test.ts +++ b/tests/unit/intentList.test.ts @@ -1,107 +1,107 @@ import { describe, expect, it } from "bun:test"; import { - buildBaseIntentRow, - EXPIRING_THRESHOLD_SECONDS, - formatRelativeDeadline, - formatRemaining, - withTiming, - type BaseIntentRow + buildBaseIntentRow, + EXPIRING_THRESHOLD_SECONDS, + formatRelativeDeadline, + formatRemaining, + withTiming, + type BaseIntentRow } from "../../src/lib/libraries/intentList"; const baseRow: BaseIntentRow = { - orderContainer: { - inputSettler: "0x000025c3226C00B2Cdc200005a1600509f4e00C0", - order: { - user: "0x1111111111111111111111111111111111111111", - nonce: 1n, - originChainId: 8453n, - expires: Math.floor(Date.now() / 1000) + 3600, - fillDeadline: Math.floor(Date.now() / 1000) + 3600, - inputOracle: "0x0000003E06000007A224AeE90052fA6bb46d43C9", - inputs: [[1n, 1n]], - outputs: [ - { - oracle: "0x0000000000000000000000000000000000000000000000000000000000000001", - settler: "0x0000000000000000000000000000000000000000000000000000000000000002", - chainId: 42161n, - token: "0x0000000000000000000000000000000000000000000000000000000000000003", - amount: 1n, - recipient: "0x0000000000000000000000000000000000000004", - callbackData: "0x", - context: "0x00" - } - ] - }, - sponsorSignature: { type: "None", payload: "0x" }, - allocatorSignature: { type: "None", payload: "0x" } - }, - orderId: "0xabc", - orderIdShort: "0xabc", - userShort: "0x1111...1111", - fillDeadline: Math.floor(Date.now() / 1000) + 3600, - inputCount: 1, - outputCount: 1, - chainScope: "singlechain", - chainScopeBadge: "SingleChain", - inputChips: [], - inputOverflow: 0, - outputChips: [], - outputOverflow: 0, - validationPassed: true, - validationReason: "Validation pass" + orderContainer: { + inputSettler: "0x000025c3226C00B2Cdc200005a1600509f4e00C0", + order: { + user: "0x1111111111111111111111111111111111111111", + nonce: 1n, + originChainId: 8453n, + expires: Math.floor(Date.now() / 1000) + 3600, + fillDeadline: Math.floor(Date.now() / 1000) + 3600, + inputOracle: "0x0000003E06000007A224AeE90052fA6bb46d43C9", + inputs: [[1n, 1n]], + outputs: [ + { + oracle: "0x0000000000000000000000000000000000000000000000000000000000000001", + settler: "0x0000000000000000000000000000000000000000000000000000000000000002", + chainId: 42161n, + token: "0x0000000000000000000000000000000000000000000000000000000000000003", + amount: 1n, + recipient: "0x0000000000000000000000000000000000000004", + callbackData: "0x", + context: "0x00" + } + ] + }, + sponsorSignature: { type: "None", payload: "0x" }, + allocatorSignature: { type: "None", payload: "0x" } + }, + orderId: "0xabc", + orderIdShort: "0xabc", + userShort: "0x1111...1111", + fillDeadline: Math.floor(Date.now() / 1000) + 3600, + inputCount: 1, + outputCount: 1, + chainScope: "singlechain", + chainScopeBadge: "SingleChain", + inputChips: [], + inputOverflow: 0, + outputChips: [], + outputOverflow: 0, + validationPassed: true, + validationReason: "Validation pass" }; describe("intentList timing and formatting", () => { - it("marks expired rows", () => { - const row = withTiming(baseRow, baseRow.fillDeadline + 1); - expect(row.status).toBe("expired"); - }); + it("marks expired rows", () => { + const row = withTiming(baseRow, baseRow.fillDeadline + 1); + expect(row.status).toBe("expired"); + }); - it("marks expiring rows", () => { - const now = baseRow.fillDeadline - EXPIRING_THRESHOLD_SECONDS + 1; - const row = withTiming(baseRow, now); - expect(row.status).toBe("expiring"); - }); + it("marks expiring rows", () => { + const now = baseRow.fillDeadline - EXPIRING_THRESHOLD_SECONDS + 1; + const row = withTiming(baseRow, now); + expect(row.status).toBe("expiring"); + }); - it("formats remaining/relative deadline values", () => { - expect(formatRemaining(59)).toBe("59s"); - expect(formatRemaining(180)).toBe("3m"); - expect(formatRelativeDeadline(30)).toBe("in 30s"); - expect(formatRelativeDeadline(-30)).toBe("30s ago"); - }); + it("formats remaining/relative deadline values", () => { + expect(formatRemaining(59)).toBe("59s"); + expect(formatRemaining(180)).toBe("3m"); + expect(formatRelativeDeadline(30)).toBe("in 30s"); + expect(formatRelativeDeadline(-30)).toBe("30s ago"); + }); - it("builds rows for unknown chains without throwing", () => { - const unknownChainId = 999999999n; - const row = buildBaseIntentRow({ - inputSettler: "0x000025c3226C00B2Cdc200005a1600509f4e00C0", - order: { - user: "0x1111111111111111111111111111111111111111", - nonce: 1n, - originChainId: unknownChainId, - expires: Math.floor(Date.now() / 1000) + 3600, - fillDeadline: Math.floor(Date.now() / 1000) + 3600, - inputOracle: "0x0000000000eC36B683C2E6AC89e9A75989C22a2e", - inputs: [[1n, 1n]], - outputs: [ - { - oracle: "0x0000000000000000000000000000000000000000000000000000000000000001", - settler: "0x0000000000000000000000000000000000000000000000000000000000000002", - chainId: unknownChainId, - token: "0x0000000000000000000000000000000000000000000000000000000000000003", - amount: 1n, - recipient: "0x0000000000000000000000000000000000000000000000000000000000000004", - callbackData: "0x", - context: "0x00" - } - ] - }, - sponsorSignature: { type: "None", payload: "0x" }, - allocatorSignature: { type: "None", payload: "0x" } - }); + it("builds rows for unknown chains without throwing", () => { + const unknownChainId = 999999999n; + const row = buildBaseIntentRow({ + inputSettler: "0x000025c3226C00B2Cdc200005a1600509f4e00C0", + order: { + user: "0x1111111111111111111111111111111111111111", + nonce: 1n, + originChainId: unknownChainId, + expires: Math.floor(Date.now() / 1000) + 3600, + fillDeadline: Math.floor(Date.now() / 1000) + 3600, + inputOracle: "0x0000000000eC36B683C2E6AC89e9A75989C22a2e", + inputs: [[1n, 1n]], + outputs: [ + { + oracle: "0x0000000000000000000000000000000000000000000000000000000000000001", + settler: "0x0000000000000000000000000000000000000000000000000000000000000002", + chainId: unknownChainId, + token: "0x0000000000000000000000000000000000000000000000000000000000000003", + amount: 1n, + recipient: "0x0000000000000000000000000000000000000000000000000000000000000004", + callbackData: "0x", + context: "0x00" + } + ] + }, + sponsorSignature: { type: "None", payload: "0x" }, + allocatorSignature: { type: "None", payload: "0x" } + }); - expect(row.inputChips[0].text).toContain("chain-999999999"); - expect(row.outputChips[0].text).toContain("chain-999999999"); - expect(row.inputChips[0].text).toContain("..."); - expect(row.outputChips[0].text).toContain("..."); - }); + expect(row.inputChips[0].text).toContain("chain-999999999"); + expect(row.outputChips[0].text).toContain("chain-999999999"); + expect(row.inputChips[0].text).toContain("..."); + expect(row.outputChips[0].text).toContain("..."); + }); }); diff --git a/tests/unit/orderValidationDeps.test.ts b/tests/unit/orderValidationDeps.test.ts index 8514908..6eaf3cc 100644 --- a/tests/unit/orderValidationDeps.test.ts +++ b/tests/unit/orderValidationDeps.test.ts @@ -1,51 +1,51 @@ import { describe, expect, it } from "bun:test"; import { - COIN_FILLER, - VALIDATION_ERRORS, - addressToBytes32, - validateOrderWithReason + COIN_FILLER, + VALIDATION_ERRORS, + addressToBytes32, + validateOrderWithReason } from "@lifi/intent"; import { makeMandateOutput, makeStandardOrder } from "../fixtures/orderFixtures"; import { orderValidationDeps } from "../../src/lib/libraries/coreDeps"; describe("orderValidationDeps unknown-chain handling", () => { - it("rejects unsupported origin chains even when same-chain fill uses COIN_FILLER", () => { - const unknownChainId = 999999999n; - const result = validateOrderWithReason({ - order: makeStandardOrder({ - originChainId: unknownChainId, - inputOracle: COIN_FILLER, - outputs: [ - makeMandateOutput(unknownChainId, 1n, { - oracle: addressToBytes32(COIN_FILLER), - settler: addressToBytes32(COIN_FILLER), - context: "0x00" - }) - ] - }), - deps: orderValidationDeps - }); + it("rejects unsupported origin chains even when same-chain fill uses COIN_FILLER", () => { + const unknownChainId = 999999999n; + const result = validateOrderWithReason({ + order: makeStandardOrder({ + originChainId: unknownChainId, + inputOracle: COIN_FILLER, + outputs: [ + makeMandateOutput(unknownChainId, 1n, { + oracle: addressToBytes32(COIN_FILLER), + settler: addressToBytes32(COIN_FILLER), + context: "0x00" + }) + ] + }), + deps: orderValidationDeps + }); - expect(result.passed).toBe(false); - expect(result.reason).toBe(VALIDATION_ERRORS.UNKNOWN_ORIGIN_CHAIN); - }); + expect(result.passed).toBe(false); + expect(result.reason).toBe(VALIDATION_ERRORS.UNKNOWN_ORIGIN_CHAIN); + }); - it("rejects unsupported output chains instead of treating them as COIN_FILLER-only", () => { - const unknownChainId = 999999999n; - const result = validateOrderWithReason({ - order: makeStandardOrder({ - outputs: [ - makeMandateOutput(unknownChainId, 1n, { - oracle: addressToBytes32(COIN_FILLER), - settler: addressToBytes32(COIN_FILLER), - context: "0x00" - }) - ] - }), - deps: orderValidationDeps - }); + it("rejects unsupported output chains instead of treating them as COIN_FILLER-only", () => { + const unknownChainId = 999999999n; + const result = validateOrderWithReason({ + order: makeStandardOrder({ + outputs: [ + makeMandateOutput(unknownChainId, 1n, { + oracle: addressToBytes32(COIN_FILLER), + settler: addressToBytes32(COIN_FILLER), + context: "0x00" + }) + ] + }), + deps: orderValidationDeps + }); - expect(result.passed).toBe(false); - expect(result.reason).toBe(VALIDATION_ERRORS.UNKNOWN_OUTPUT_CHAIN); - }); + expect(result.passed).toBe(false); + expect(result.reason).toBe(VALIDATION_ERRORS.UNKNOWN_OUTPUT_CHAIN); + }); }); diff --git a/tests/unit/walletClientSwitch.test.ts b/tests/unit/walletClientSwitch.test.ts index c86b686..c853a04 100644 --- a/tests/unit/walletClientSwitch.test.ts +++ b/tests/unit/walletClientSwitch.test.ts @@ -3,55 +3,55 @@ import type { EIP1193Provider } from "viem"; import { createSwitchWalletChain } from "../../src/lib/utils/walletClient"; describe("switchWalletChain", () => { - it("uses walletClient.switchChain when available", async () => { - const getCurrentProvider = mock(async () => undefined); - const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); - const switchChain = mock(async () => undefined); - const walletClient = { switchChain } as unknown as Parameters[0]; - await switchWalletChain(walletClient, 8453); - expect(switchChain).toHaveBeenCalledWith({ id: 8453 }); - expect(getCurrentProvider).not.toHaveBeenCalled(); - }); + it("uses walletClient.switchChain when available", async () => { + const getCurrentProvider = mock(async () => undefined); + const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); + const switchChain = mock(async () => undefined); + const walletClient = { switchChain } as unknown as Parameters[0]; + await switchWalletChain(walletClient, 8453); + expect(switchChain).toHaveBeenCalledWith({ id: 8453 }); + expect(getCurrentProvider).not.toHaveBeenCalled(); + }); - it("falls back to provider wallet_switchEthereumChain", async () => { - const getCurrentProvider = mock(async () => undefined); - const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); - const request = mock(async () => null); - const walletClient = {} as unknown as Parameters[0]; - const provider = { request } as unknown as NonNullable< - Parameters[2] - >["provider"]; - await switchWalletChain(walletClient, 8453, { provider }); - expect(request).toHaveBeenCalledWith({ - method: "wallet_switchEthereumChain", - params: [{ chainId: "0x2105" }] - }); - expect(getCurrentProvider).not.toHaveBeenCalled(); - }); + it("falls back to provider wallet_switchEthereumChain", async () => { + const getCurrentProvider = mock(async () => undefined); + const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); + const request = mock(async () => null); + const walletClient = {} as unknown as Parameters[0]; + const provider = { request } as unknown as NonNullable< + Parameters[2] + >["provider"]; + await switchWalletChain(walletClient, 8453, { provider }); + expect(request).toHaveBeenCalledWith({ + method: "wallet_switchEthereumChain", + params: [{ chainId: "0x2105" }] + }); + expect(getCurrentProvider).not.toHaveBeenCalled(); + }); - it("falls back to injected getCurrentProvider when no provider is passed", async () => { - const request = mock(async () => null); - const provider = { request } as unknown as EIP1193Provider; - const getCurrentProvider = mock(async () => provider); - const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); - const walletClient = {} as unknown as Parameters[0]; + it("falls back to injected getCurrentProvider when no provider is passed", async () => { + const request = mock(async () => null); + const provider = { request } as unknown as EIP1193Provider; + const getCurrentProvider = mock(async () => provider); + const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); + const walletClient = {} as unknown as Parameters[0]; - await switchWalletChain(walletClient, 8453); + await switchWalletChain(walletClient, 8453); - expect(getCurrentProvider).toHaveBeenCalledTimes(1); - expect(request).toHaveBeenCalledWith({ - method: "wallet_switchEthereumChain", - params: [{ chainId: "0x2105" }] - }); - }); + expect(getCurrentProvider).toHaveBeenCalledTimes(1); + expect(request).toHaveBeenCalledWith({ + method: "wallet_switchEthereumChain", + params: [{ chainId: "0x2105" }] + }); + }); - it("throws when no provider can be resolved", async () => { - const getCurrentProvider = mock(async () => undefined); - const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); - const walletClient = {} as unknown as Parameters[0]; + it("throws when no provider can be resolved", async () => { + const getCurrentProvider = mock(async () => undefined); + const switchWalletChain = createSwitchWalletChain({ getCurrentProvider }); + const walletClient = {} as unknown as Parameters[0]; - await expect(switchWalletChain(walletClient, 8453)).rejects.toThrow( - "Wallet client does not support switchChain and no provider is available for chain 8453." - ); - }); + await expect(switchWalletChain(walletClient, 8453)).rejects.toThrow( + "Wallet client does not support switchChain and no provider is available for chain 8453." + ); + }); }); diff --git a/tsconfig.json b/tsconfig.json index f7ccfe4..8e0bd6d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,22 @@ { - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "module": "ESNext", - "moduleResolution": "bundler", - "target": "ESNext" - }, - "exclude": ["tests/e2e", "playwright.config.ts"] - // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias - // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files - // - // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes - // from the referenced tsconfig.json - TypeScript does not merge them in + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "module": "ESNext", + "moduleResolution": "bundler", + "target": "ESNext" + }, + "exclude": ["tests/e2e", "playwright.config.ts"] + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in } diff --git a/vite.config.ts b/vite.config.ts index 83ecf56..f12ffff 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,8 +3,8 @@ import { sveltekit } from "@sveltejs/kit/vite"; import { defineConfig } from "vite"; export default defineConfig({ - plugins: [tailwindcss(), sveltekit()], - optimizeDeps: { - exclude: ["@electric-sql/pglite"] - } + plugins: [tailwindcss(), sveltekit()], + optimizeDeps: { + exclude: ["@electric-sql/pglite"] + } }); diff --git a/wrangler.jsonc b/wrangler.jsonc index e787b50..e7829ef 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -1,9 +1,9 @@ { - "name": "intent", - "main": ".svelte-kit/cloudflare/_worker.js", - "compatibility_date": "2025-01-01", - "assets": { - "binding": "ASSETS", - "directory": ".svelte-kit/cloudflare" - } + "name": "intent", + "main": ".svelte-kit/cloudflare/_worker.js", + "compatibility_date": "2025-01-01", + "assets": { + "binding": "ASSETS", + "directory": ".svelte-kit/cloudflare" + } } From 60f0e2a01742ffb3684156295dc5747d15c2f474 Mon Sep 17 00:00:00 2001 From: azzahamdani Date: Tue, 10 Mar 2026 15:48:09 +0100 Subject: [PATCH 5/9] update the workflow inline because the repository is public and cannot access central repository (#30) * update the workflow inline because the repository is public and cannot access central repository * add the env vriable to the pipeline * add the env variables to the Deploy to Cloudflare Workers steps --- .github/workflows/deploy.yml | 135 ++++++++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 25 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 056159b..5c9a897 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,34 +11,119 @@ on: jobs: deploy-production: if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' - uses: lifinance/github-actions/.github/workflows/cloudflare-worker-deploy.yaml@main - with: - environment: production - build-command: "bun run build" - node-version: "20" - secrets: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + runs-on: ubuntu-latest + name: Deploy to Production + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build application + env: + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_MAINNET_ZONE_API_KEY }} + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_TESTNET_ZONE_API_KEY }} + PUBLIC_WALLET_CONNECT_PROJECT_ID: ${{ secrets.PUBLIC_WALLET_CONNECT_PROJECT_ID }} + run: bun run build + + - name: Deploy to Cloudflare Workers + uses: cloudflare/wrangler-action@v3 + env: + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_MAINNET_ZONE_API_KEY }} + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_TESTNET_ZONE_API_KEY }} + PUBLIC_WALLET_CONNECT_PROJECT_ID: ${{ secrets.PUBLIC_WALLET_CONNECT_PROJECT_ID }} + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + wranglerVersion: "4.71.0" + command: deploy --env production deploy-preview: if: github.event_name == 'pull_request' && github.event.action != 'closed' - uses: lifinance/github-actions/.github/workflows/cloudflare-worker-deploy.yaml@main - with: - environment: preview - build-command: "bun run build" - node-version: "20" - preview-name: lintent-pr-${{ github.event.pull_request.number }} - secrets: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + runs-on: ubuntu-latest + name: Deploy Preview + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build application + env: + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_MAINNET_ZONE_API_KEY }} + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_TESTNET_ZONE_API_KEY }} + PUBLIC_WALLET_CONNECT_PROJECT_ID: ${{ secrets.PUBLIC_WALLET_CONNECT_PROJECT_ID }} + run: bun run build + + - name: Deploy to Cloudflare Workers + id: deploy + uses: cloudflare/wrangler-action@v3 + env: + PRIVATE_POLYMER_MAINNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_MAINNET_ZONE_API_KEY }} + PRIVATE_POLYMER_TESTNET_ZONE_API_KEY: ${{ secrets.PRIVATE_POLYMER_TESTNET_ZONE_API_KEY }} + PUBLIC_WALLET_CONNECT_PROJECT_ID: ${{ secrets.PUBLIC_WALLET_CONNECT_PROJECT_ID }} + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + wranglerVersion: "4.71.0" + command: deploy --name lintent-pr-${{ github.event.pull_request.number }} + + - name: Post deployment comment + uses: actions/github-script@v7 + with: + script: | + const maxAttempts = 3; + const delayMs = 10000; + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + try { + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `🚀 **Preview deployed!**\n\n**Worker:** \`lintent-pr-${{ github.event.pull_request.number }}\`\n**URL:** ${{ steps.deploy.outputs.deployment-url }}` + }); + return; + } catch (error) { + core.warning(`Attempt ${attempt}/${maxAttempts} failed: ${error.message}`); + if (attempt === maxAttempts) throw error; + await new Promise(r => setTimeout(r, delayMs)); + } + } cleanup-preview: if: github.event_name == 'pull_request' && github.event.action == 'closed' - uses: lifinance/github-actions/.github/workflows/cloudflare-worker-deploy.yaml@main - with: - delete-preview: true - preview-name: lintent-pr-${{ github.event.pull_request.number }} - node-version: "20" - secrets: - CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} - CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + runs-on: ubuntu-latest + name: Cleanup Preview Worker + steps: + - name: Delete preview worker + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + wranglerVersion: "4.71.0" + command: delete --name lintent-pr-${{ github.event.pull_request.number }} --force From 5bab87651465cd826bd363822d23a620b520c934 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 10 Mar 2026 20:37:00 +0400 Subject: [PATCH 6/9] Throw bad DBs for adding new tokens. --- drizzle/0000_absent_moonstone.sql | 7 - drizzle/0000_brief_corsair.sql | 43 ++++ drizzle/0001_nifty_mephisto.sql | 6 - drizzle/0002_expand_intent_created_at.sql | 1 - drizzle/0003_unique_intent_order_id.sql | 1 - drizzle/0004_hesitant_quasimodo.sql | 21 -- drizzle/0004_store_transaction_receipts.sql | 7 - drizzle/meta/0000_snapshot.json | 169 ++++++++++++++- drizzle/meta/0001_snapshot.json | 99 --------- drizzle/meta/0004_snapshot.json | 227 -------------------- drizzle/meta/_journal.json | 32 +-- src/lib/migrations.json | 46 +--- 12 files changed, 222 insertions(+), 437 deletions(-) delete mode 100644 drizzle/0000_absent_moonstone.sql create mode 100644 drizzle/0000_brief_corsair.sql delete mode 100644 drizzle/0001_nifty_mephisto.sql delete mode 100644 drizzle/0002_expand_intent_created_at.sql delete mode 100644 drizzle/0003_unique_intent_order_id.sql delete mode 100644 drizzle/0004_hesitant_quasimodo.sql delete mode 100644 drizzle/0004_store_transaction_receipts.sql delete mode 100644 drizzle/meta/0001_snapshot.json delete mode 100644 drizzle/meta/0004_snapshot.json diff --git a/drizzle/0000_absent_moonstone.sql b/drizzle/0000_absent_moonstone.sql deleted file mode 100644 index fe9c33b..0000000 --- a/drizzle/0000_absent_moonstone.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE "intents" ( - "id" text PRIMARY KEY NOT NULL, - "order_id" text NOT NULL, - "intent_type" text NOT NULL, - "data" text NOT NULL, - "created_at" integer NOT NULL -); diff --git a/drizzle/0000_brief_corsair.sql b/drizzle/0000_brief_corsair.sql new file mode 100644 index 0000000..755927a --- /dev/null +++ b/drizzle/0000_brief_corsair.sql @@ -0,0 +1,43 @@ +DROP TABLE IF EXISTS "transaction_receipts"; +--> statement-breakpoint +DROP TABLE IF EXISTS "tokens"; +--> statement-breakpoint +DROP TABLE IF EXISTS "intents"; +--> statement-breakpoint +DROP TABLE IF EXISTS "fill_transactions"; +--> statement-breakpoint +CREATE TABLE "fill_transactions" ( + "id" text PRIMARY KEY NOT NULL, + "output_hash" text NOT NULL, + "tx_hash" text NOT NULL, + CONSTRAINT "fill_transactions_output_hash_unique" UNIQUE("output_hash") +); +--> statement-breakpoint +CREATE TABLE "intents" ( + "id" text PRIMARY KEY NOT NULL, + "order_id" text NOT NULL, + "intent_type" text NOT NULL, + "data" text NOT NULL, + "created_at" bigint NOT NULL, + CONSTRAINT "intents_order_id_unique" UNIQUE("order_id") +); +--> statement-breakpoint +CREATE TABLE "tokens" ( + "id" text PRIMARY KEY NOT NULL, + "address" text NOT NULL, + "name" text NOT NULL, + "chain_id" bigint NOT NULL, + "decimals" bigint NOT NULL, + "is_manual" boolean DEFAULT false NOT NULL, + "is_testnet" boolean DEFAULT false NOT NULL +); +--> statement-breakpoint +CREATE TABLE "transaction_receipts" ( + "id" text PRIMARY KEY NOT NULL, + "chain_id" bigint NOT NULL, + "tx_hash" text NOT NULL, + "receipt" text NOT NULL, + "created_at" bigint NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX "tokens_address_chain_idx" ON "tokens" USING btree ("address","chain_id"); diff --git a/drizzle/0001_nifty_mephisto.sql b/drizzle/0001_nifty_mephisto.sql deleted file mode 100644 index bef3c71..0000000 --- a/drizzle/0001_nifty_mephisto.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE "fill_transactions" ( - "id" text PRIMARY KEY NOT NULL, - "output_hash" text NOT NULL, - "tx_hash" text NOT NULL, - CONSTRAINT "fill_transactions_output_hash_unique" UNIQUE("output_hash") -); diff --git a/drizzle/0002_expand_intent_created_at.sql b/drizzle/0002_expand_intent_created_at.sql deleted file mode 100644 index 945724b..0000000 --- a/drizzle/0002_expand_intent_created_at.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "intents" ALTER COLUMN "created_at" TYPE bigint; diff --git a/drizzle/0003_unique_intent_order_id.sql b/drizzle/0003_unique_intent_order_id.sql deleted file mode 100644 index bfae5b2..0000000 --- a/drizzle/0003_unique_intent_order_id.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE UNIQUE INDEX IF NOT EXISTS "intents_order_id_unique" ON "intents" ("order_id"); diff --git a/drizzle/0004_hesitant_quasimodo.sql b/drizzle/0004_hesitant_quasimodo.sql deleted file mode 100644 index b636d66..0000000 --- a/drizzle/0004_hesitant_quasimodo.sql +++ /dev/null @@ -1,21 +0,0 @@ -CREATE TABLE "tokens" ( - "id" text PRIMARY KEY NOT NULL, - "address" text NOT NULL, - "name" text NOT NULL, - "chain_id" bigint NOT NULL, - "decimals" bigint NOT NULL, - "is_manual" boolean DEFAULT false NOT NULL, - "is_testnet" boolean DEFAULT false NOT NULL -); ---> statement-breakpoint -CREATE TABLE "transaction_receipts" ( - "id" text PRIMARY KEY NOT NULL, - "chain_id" bigint NOT NULL, - "tx_hash" text NOT NULL, - "receipt" text NOT NULL, - "created_at" bigint NOT NULL -); ---> statement-breakpoint -ALTER TABLE "intents" ALTER COLUMN "created_at" SET DATA TYPE bigint;--> statement-breakpoint -CREATE UNIQUE INDEX "tokens_address_chain_idx" ON "tokens" USING btree ("address","chain_id");--> statement-breakpoint -ALTER TABLE "intents" ADD CONSTRAINT "intents_order_id_unique" UNIQUE("order_id"); \ No newline at end of file diff --git a/drizzle/0004_store_transaction_receipts.sql b/drizzle/0004_store_transaction_receipts.sql deleted file mode 100644 index 939ed95..0000000 --- a/drizzle/0004_store_transaction_receipts.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE "transaction_receipts" ( - "id" text PRIMARY KEY NOT NULL, - "chain_id" bigint NOT NULL, - "tx_hash" text NOT NULL, - "receipt" text NOT NULL, - "created_at" bigint NOT NULL -); diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json index ee667f4..9f75d1e 100644 --- a/drizzle/meta/0000_snapshot.json +++ b/drizzle/meta/0000_snapshot.json @@ -1,9 +1,46 @@ { - "id": "acb031ae-9317-47af-b9af-c685b7c17bda", + "id": "8baee9a6-7db9-41f1-b049-9187bb2edafc", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { + "public.fill_transactions": { + "name": "fill_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "output_hash": { + "name": "output_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tx_hash": { + "name": "tx_hash", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "fill_transactions_output_hash_unique": { + "name": "fill_transactions_output_hash_unique", + "nullsNotDistinct": false, + "columns": ["output_hash"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, "public.intents": { "name": "intents", "schema": "", @@ -34,7 +71,135 @@ }, "created_at": { "name": "created_at", - "type": "integer", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "intents_order_id_unique": { + "name": "intents_order_id_unique", + "nullsNotDistinct": false, + "columns": ["order_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tokens": { + "name": "tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chain_id": { + "name": "chain_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "decimals": { + "name": "decimals", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "is_manual": { + "name": "is_manual", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_testnet": { + "name": "is_testnet", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "tokens_address_chain_idx": { + "name": "tokens_address_chain_idx", + "columns": [ + { + "expression": "address", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chain_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.transaction_receipts": { + "name": "transaction_receipts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "chain_id": { + "name": "chain_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tx_hash": { + "name": "tx_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "receipt": { + "name": "receipt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "bigint", "primaryKey": false, "notNull": true } diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json deleted file mode 100644 index 01b4650..0000000 --- a/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "id": "9f78f425-71cd-4f66-b756-5c8433118a62", - "prevId": "acb031ae-9317-47af-b9af-c685b7c17bda", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.fill_transactions": { - "name": "fill_transactions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "output_hash": { - "name": "output_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "tx_hash": { - "name": "tx_hash", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "fill_transactions_output_hash_unique": { - "name": "fill_transactions_output_hash_unique", - "nullsNotDistinct": false, - "columns": ["output_hash"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.intents": { - "name": "intents", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "order_id": { - "name": "order_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "intent_type": { - "name": "intent_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/drizzle/meta/0004_snapshot.json b/drizzle/meta/0004_snapshot.json deleted file mode 100644 index 7965093..0000000 --- a/drizzle/meta/0004_snapshot.json +++ /dev/null @@ -1,227 +0,0 @@ -{ - "id": "89d339b9-626a-4944-9de0-259fa3e6bbf0", - "prevId": "9f78f425-71cd-4f66-b756-5c8433118a62", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.fill_transactions": { - "name": "fill_transactions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "output_hash": { - "name": "output_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "tx_hash": { - "name": "tx_hash", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "fill_transactions_output_hash_unique": { - "name": "fill_transactions_output_hash_unique", - "nullsNotDistinct": false, - "columns": ["output_hash"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.intents": { - "name": "intents", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "order_id": { - "name": "order_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "intent_type": { - "name": "intent_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "intents_order_id_unique": { - "name": "intents_order_id_unique", - "nullsNotDistinct": false, - "columns": ["order_id"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.tokens": { - "name": "tokens", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "address": { - "name": "address", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "chain_id": { - "name": "chain_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "decimals": { - "name": "decimals", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "is_manual": { - "name": "is_manual", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "is_testnet": { - "name": "is_testnet", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - } - }, - "indexes": { - "tokens_address_chain_idx": { - "name": "tokens_address_chain_idx", - "columns": [ - { - "expression": "address", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "chain_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.transaction_receipts": { - "name": "transaction_receipts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "chain_id": { - "name": "chain_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "tx_hash": { - "name": "tx_hash", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "receipt": { - "name": "receipt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 8632d88..092c8b2 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -5,36 +5,8 @@ { "idx": 0, "version": "7", - "when": 1770712231202, - "tag": "0000_absent_moonstone", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1770803119280, - "tag": "0001_nifty_mephisto", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1770809000000, - "tag": "0002_expand_intent_created_at", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1770810000000, - "tag": "0003_unique_intent_order_id", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1773066106972, - "tag": "0004_hesitant_quasimodo", + "when": 1773159031946, + "tag": "0000_brief_corsair", "breakpoints": true } ] diff --git a/src/lib/migrations.json b/src/lib/migrations.json index 2cf776d..3699d71 100644 --- a/src/lib/migrations.json +++ b/src/lib/migrations.json @@ -1,44 +1,18 @@ [ { "sql": [ - "CREATE TABLE \"intents\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"order_id\" text NOT NULL,\n\t\"intent_type\" text NOT NULL,\n\t\"data\" text NOT NULL,\n\t\"created_at\" integer NOT NULL\n);\n" - ], - "bps": true, - "folderMillis": 1770712231202, - "hash": "3ec46f3cc562c5204f9e841d2ea2086d8994c80253445074b646b07900b30a9f" - }, - { - "sql": [ - "CREATE TABLE \"fill_transactions\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"output_hash\" text NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\tCONSTRAINT \"fill_transactions_output_hash_unique\" UNIQUE(\"output_hash\")\n);\n" - ], - "bps": true, - "folderMillis": 1770803119280, - "hash": "f963c9a03076fc9754b51c2850ad42f5edfdf19fb018a0616db37d935907b165" - }, - { - "sql": ["ALTER TABLE \"intents\" ALTER COLUMN \"created_at\" TYPE bigint;\n"], - "bps": true, - "folderMillis": 1770809000000, - "hash": "45484cce461ab6b6ac735465757bebec7d5bf488ed58c4288ebf1fd75d1881f5" - }, - { - "sql": [ - "CREATE UNIQUE INDEX IF NOT EXISTS \"intents_order_id_unique\" ON \"intents\" (\"order_id\");\n" - ], - "bps": true, - "folderMillis": 1770810000000, - "hash": "387946018137748e3a5dd66fca8a1da71ddabc4191a835a3254fad26c6b6d412" - }, - { - "sql": [ - "CREATE TABLE \"tokens\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"address\" text NOT NULL,\n\t\"name\" text NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"decimals\" bigint NOT NULL,\n\t\"is_manual\" boolean DEFAULT false NOT NULL,\n\t\"is_testnet\" boolean DEFAULT false NOT NULL\n);\n", + "DROP TABLE IF EXISTS \"transaction_receipts\";\n", + "\nDROP TABLE IF EXISTS \"tokens\";\n", + "\nDROP TABLE IF EXISTS \"intents\";\n", + "\nDROP TABLE IF EXISTS \"fill_transactions\";\n", + "\nCREATE TABLE \"fill_transactions\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"output_hash\" text NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\tCONSTRAINT \"fill_transactions_output_hash_unique\" UNIQUE(\"output_hash\")\n);\n", + "\nCREATE TABLE \"intents\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"order_id\" text NOT NULL,\n\t\"intent_type\" text NOT NULL,\n\t\"data\" text NOT NULL,\n\t\"created_at\" bigint NOT NULL,\n\tCONSTRAINT \"intents_order_id_unique\" UNIQUE(\"order_id\")\n);\n", + "\nCREATE TABLE \"tokens\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"address\" text NOT NULL,\n\t\"name\" text NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"decimals\" bigint NOT NULL,\n\t\"is_manual\" boolean DEFAULT false NOT NULL,\n\t\"is_testnet\" boolean DEFAULT false NOT NULL\n);\n", "\nCREATE TABLE \"transaction_receipts\" (\n\t\"id\" text PRIMARY KEY NOT NULL,\n\t\"chain_id\" bigint NOT NULL,\n\t\"tx_hash\" text NOT NULL,\n\t\"receipt\" text NOT NULL,\n\t\"created_at\" bigint NOT NULL\n);\n", - "\nALTER TABLE \"intents\" ALTER COLUMN \"created_at\" SET DATA TYPE bigint;", - "\nCREATE UNIQUE INDEX \"tokens_address_chain_idx\" ON \"tokens\" USING btree (\"address\",\"chain_id\");", - "\nALTER TABLE \"intents\" ADD CONSTRAINT \"intents_order_id_unique\" UNIQUE(\"order_id\");" + "\nCREATE UNIQUE INDEX \"tokens_address_chain_idx\" ON \"tokens\" USING btree (\"address\",\"chain_id\");\n" ], "bps": true, - "folderMillis": 1773066106972, - "hash": "486043322db64a03ff9040a7cf7062a1d452554261d63c9c406c782e1e45b76b" + "folderMillis": 1773159031946, + "hash": "b9ecf75ed8487a7746169ad49ce1564428a73e69f49e85cd702aaabbb03d72f6" } ] From af952ed87e5041570a3a991530e1f788f7572681 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 10 Mar 2026 20:44:02 +0400 Subject: [PATCH 7/9] Add deps in an attempt to get worker build to pass --- bun.lock | 602 ++++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 8 +- 2 files changed, 606 insertions(+), 4 deletions(-) diff --git a/bun.lock b/bun.lock index 5eec092..7c7ab35 100644 --- a/bun.lock +++ b/bun.lock @@ -5,15 +5,21 @@ "": { "name": "cat-swapper", "dependencies": { + "@base-org/account": "^2.5.1", + "@coinbase/wallet-sdk": "^4.3.6", "@electric-sql/pglite": "^0.3.15", "@lifi/intent": "0.0.3-alpha.1", "@metamask/sdk": "^0.34.0", + "@safe-global/safe-apps-provider": "~0.18.6", + "@safe-global/safe-apps-sdk": "^9.1.0", "@sveltejs/adapter-cloudflare": "^7.0.3", "@wagmi/connectors": "^7.2.1", "@wagmi/core": "^3.4.0", + "@walletconnect/ethereum-provider": "^2.21.1", "axios": "^1.9.0", "base64-js": "^1.5.1", "drizzle-orm": "^0.45.1", + "porto": "~0.2.35", "rxjs": "^7.8.2", "viem": "~2.45.1", "wagmi": "^3.5.0", @@ -53,6 +59,8 @@ "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], + "@base-org/account": ["@base-org/account@2.5.2", "", { "dependencies": { "@coinbase/cdp-sdk": "^1.0.0", "brotli-wasm": "^3.0.0", "clsx": "1.2.1", "eventemitter3": "5.0.1", "idb-keyval": "6.2.1", "ox": "0.6.9", "preact": "10.24.2", "viem": "^2.31.7", "zustand": "5.0.3" } }, "sha512-B3e0XiZWHXgCPLRXk0dDGA2WN8eFk/MDprqRX1Xl4PPx1LAdzynGcGUg6rnidMrIQ/GSL+oelWDHdGbWtCOOoA=="], + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.6.0", "", { "peerDependencies": { "unenv": "2.0.0-rc.19", "workerd": "^1.20250802.0" } }, "sha512-h7Txw0WbDuUbrvZwky6+x7ft+U/Gppfn/rWx6IdR+e9gjygozRJnV26Y2TOr3yrIFa6OsZqqR2lN+jWTrakHXg=="], @@ -69,6 +77,10 @@ "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20250807.0", "", {}, "sha512-Zbrz9egAfwmlkUaZ1tQ+19pt5eomCJ57mAviT1HCsvnSFP1MoffMbYiU/xUomuekHtx0aVO4EacZwchCgjSvmw=="], + "@coinbase/cdp-sdk": ["@coinbase/cdp-sdk@1.45.0", "", { "dependencies": { "@solana-program/system": "^0.10.0", "@solana-program/token": "^0.9.0", "@solana/kit": "^5.1.0", "@solana/web3.js": "^1.98.1", "abitype": "1.0.6", "axios": "^1.12.2", "axios-retry": "^4.5.0", "jose": "^6.0.8", "md5": "^2.3.0", "uncrypto": "^0.1.3", "viem": "^2.21.26", "zod": "^3.24.4" } }, "sha512-4fgGOhyN9g/pTDE9NtsKUapwFsubrk9wafz8ltmBqSwWqLZWfWxXkVmzMYYFAf+qeGf/X9JqJtmvDVaHFlXWlw=="], + + "@coinbase/wallet-sdk": ["@coinbase/wallet-sdk@4.3.7", "", { "dependencies": { "@noble/hashes": "^1.4.0", "clsx": "^1.2.1", "eventemitter3": "^5.0.1", "preact": "^10.24.2", "viem": "^2.27.2" } }, "sha512-z6e5XDw6EF06RqkeyEa+qD0dZ2ZbLci99vx3zwDY//XO8X7166tqKJrR2XlQnzVmtcUuJtCd5fCvr9Cu6zzX7w=="], + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], @@ -221,6 +233,12 @@ "@lifi/intent": ["@lifi/intent@0.0.3-alpha.1", "", { "dependencies": { "ky": "^1.12.0", "viem": "~2.45.1" } }, "sha512-dzEcS8U5buW7nLpkMmC0kj5R7EQC7l8l1mBd9IWr6R5/vSnSF3kO9zVaNQOmrbezSOS9TROrOpGDUWc847d/Uw=="], + "@lit-labs/ssr-dom-shim": ["@lit-labs/ssr-dom-shim@1.5.1", "", {}, "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA=="], + + "@lit/react": ["@lit/react@1.0.8", "", { "peerDependencies": { "@types/react": "17 || 18 || 19" } }, "sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw=="], + + "@lit/reactive-element": ["@lit/reactive-element@2.1.2", "", { "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0" } }, "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A=="], + "@metamask/json-rpc-engine": ["@metamask/json-rpc-engine@8.0.2", "", { "dependencies": { "@metamask/rpc-errors": "^6.2.1", "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^8.3.0" } }, "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA=="], "@metamask/json-rpc-middleware-stream": ["@metamask/json-rpc-middleware-stream@7.0.2", "", { "dependencies": { "@metamask/json-rpc-engine": "^8.0.2", "@metamask/safe-event-emitter": "^3.0.0", "@metamask/utils": "^8.3.0", "readable-stream": "^3.6.2" } }, "sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg=="], @@ -247,6 +265,8 @@ "@metamask/utils": ["@metamask/utils@8.5.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ=="], + "@msgpack/msgpack": ["@msgpack/msgpack@3.1.3", "", {}, "sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA=="], + "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], "@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], @@ -261,6 +281,8 @@ "@paulmillr/qr": ["@paulmillr/qr@0.2.1", "", {}, "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ=="], + "@phosphor-icons/webcomponents": ["@phosphor-icons/webcomponents@2.1.5", "", { "dependencies": { "lit": "^3" } }, "sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q=="], + "@playwright/test": ["@playwright/test@1.58.2", "", { "dependencies": { "playwright": "1.58.2" }, "bin": { "playwright": "cli.js" } }, "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA=="], "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], @@ -271,6 +293,24 @@ "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="], + "@reown/appkit": ["@reown/appkit@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-controllers": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-pay": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-polyfills": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-scaffold-ui": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-ui": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-utils": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-wallet": "1.8.17-wc-circular-dependencies-fix.0", "@walletconnect/universal-provider": "2.23.2", "bs58": "6.0.0", "semver": "7.7.2", "valtio": "2.1.7", "viem": ">=2.37.9" }, "optionalDependencies": { "@lit/react": "1.0.8" } }, "sha512-7JjEp+JNxRUDOa7CxOCbUbG8uYVo38ojc9FN/fuzJuJADUzKDaH287MLV9qI1ZyQyXA8qXvhXRqjtw+3xo2/7A=="], + + "@reown/appkit-common": ["@reown/appkit-common@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "big.js": "6.2.2", "dayjs": "1.11.13", "viem": ">=2.37.9" } }, "sha512-wf53EzDmCJ5ICtDY5B1MddVeCwoqDGPVmaxD4wQJLR9uanhBXfKq1sJou+Uj8lZCyI72Z+r9YlsePOlYH2Ge3A=="], + + "@reown/appkit-controllers": ["@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-wallet": "1.8.17-wc-circular-dependencies-fix.0", "@walletconnect/universal-provider": "2.23.2", "valtio": "2.1.7", "viem": ">=2.37.9" } }, "sha512-wY5yvMB0o2AwitwDHHO0u2tmqR+n3Crv0AHjIcY037PC3mhF9TPEUKqE9vlrFImQWQRxl0WRfuKfzmUAPxZExw=="], + + "@reown/appkit-pay": ["@reown/appkit-pay@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-controllers": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-ui": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-utils": "1.8.17-wc-circular-dependencies-fix.0", "lit": "3.3.0", "valtio": "2.1.7" } }, "sha512-sVE8UT7CDA8zsg3opvbGjSZHSnohOVPF77vP6Ln4G0+vfoiXNhZaZa89Pg0MDjh+KGy0OulWVUdXuZ9jJQFvPg=="], + + "@reown/appkit-polyfills": ["@reown/appkit-polyfills@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "buffer": "6.0.3" } }, "sha512-OyYavslCegfUlKu8Ah6BZhbqQrK7bImvUm+EKjjvnfNN9J0F9uWMFwbTpZxenBcfAI6cyaD9aTTUunMn5no1Og=="], + + "@reown/appkit-scaffold-ui": ["@reown/appkit-scaffold-ui@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-controllers": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-pay": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-ui": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-utils": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-wallet": "1.8.17-wc-circular-dependencies-fix.0", "lit": "3.3.0" } }, "sha512-f+SYFGDy+uY1EAvWcH6vZgga1bOuzBvYSKYiRX2QQy8INtZqwwiLLvS4cgm5Yp1WvYRal5RdfZkKl5qha498gw=="], + + "@reown/appkit-ui": ["@reown/appkit-ui@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@phosphor-icons/webcomponents": "2.1.5", "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-controllers": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-wallet": "1.8.17-wc-circular-dependencies-fix.0", "lit": "3.3.0", "qrcode": "1.5.3" } }, "sha512-E1u2ZVZV0iFDSgrgtdQTZAXNbI+Lakj8E8V+jJQ47JaEVKv9SROvPu2fVqfIrqHQF68NmAk1dnbYi4luOiM0Fg=="], + + "@reown/appkit-utils": ["@reown/appkit-utils@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-controllers": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-polyfills": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-wallet": "1.8.17-wc-circular-dependencies-fix.0", "@wallet-standard/wallet": "1.1.0", "@walletconnect/logger": "3.0.2", "@walletconnect/universal-provider": "2.23.2", "valtio": "2.1.7", "viem": ">=2.37.9" }, "optionalDependencies": { "@base-org/account": "2.4.0", "@safe-global/safe-apps-provider": "0.18.6", "@safe-global/safe-apps-sdk": "9.1.0" } }, "sha512-9El8sYbXDaMYxg4R6LujA965yYQGjNcPMXqympLtzNl1es5qkniW7eAdEpLmZrsaqNrfTaHT1G65wYy7sA595w=="], + + "@reown/appkit-wallet": ["@reown/appkit-wallet@1.8.17-wc-circular-dependencies-fix.0", "", { "dependencies": { "@reown/appkit-common": "1.8.17-wc-circular-dependencies-fix.0", "@reown/appkit-polyfills": "1.8.17-wc-circular-dependencies-fix.0", "@walletconnect/logger": "3.0.2", "zod": "3.22.4" } }, "sha512-s0RTVNtgPtXGs+eZELVvTu1FRLuN15MyhVS//3/4XafVQkBBJarciXk9pFP71xeSHRzjYR1lXHnVw28687cUvQ=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.2", "", { "os": "android", "cpu": "arm" }, "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.46.2", "", { "os": "android", "cpu": "arm64" }, "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ=="], @@ -311,6 +351,12 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.46.2", "", { "os": "win32", "cpu": "x64" }, "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg=="], + "@safe-global/safe-apps-provider": ["@safe-global/safe-apps-provider@0.18.6", "", { "dependencies": { "@safe-global/safe-apps-sdk": "^9.1.0", "events": "^3.3.0" } }, "sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q=="], + + "@safe-global/safe-apps-sdk": ["@safe-global/safe-apps-sdk@9.1.0", "", { "dependencies": { "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", "viem": "^2.1.1" } }, "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q=="], + + "@safe-global/safe-gateway-typescript-sdk": ["@safe-global/safe-gateway-typescript-sdk@3.23.1", "", {}, "sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw=="], + "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], "@scure/bip32": ["@scure/bip32@1.7.0", "", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], @@ -321,6 +367,92 @@ "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="], + "@solana-program/system": ["@solana-program/system@0.10.0", "", { "peerDependencies": { "@solana/kit": "^5.0" } }, "sha512-Go+LOEZmqmNlfr+Gjy5ZWAdY5HbYzk2RBewD9QinEU/bBSzpFfzqDRT55JjFRBGJUvMgf3C2vfXEGT4i8DSI4g=="], + + "@solana-program/token": ["@solana-program/token@0.9.0", "", { "peerDependencies": { "@solana/kit": "^5.0" } }, "sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA=="], + + "@solana/accounts": ["@solana/accounts@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/rpc-spec": "5.5.1", "@solana/rpc-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ=="], + + "@solana/addresses": ["@solana/addresses@5.5.1", "", { "dependencies": { "@solana/assertions": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/nominal-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA=="], + + "@solana/assertions": ["@solana/assertions@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q=="], + + "@solana/buffer-layout": ["@solana/buffer-layout@4.0.1", "", { "dependencies": { "buffer": "~6.0.3" } }, "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA=="], + + "@solana/codecs": ["@solana/codecs@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/codecs-data-structures": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/options": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g=="], + + "@solana/codecs-core": ["@solana/codecs-core@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw=="], + + "@solana/codecs-data-structures": ["@solana/codecs-data-structures@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w=="], + + "@solana/codecs-numbers": ["@solana/codecs-numbers@2.3.0", "", { "dependencies": { "@solana/codecs-core": "2.3.0", "@solana/errors": "2.3.0" }, "peerDependencies": { "typescript": ">=5.3.3" } }, "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg=="], + + "@solana/codecs-strings": ["@solana/codecs-strings@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "fastestsmallesttextencoderdecoder": "^1.0.22", "typescript": "^5.0.0" }, "optionalPeers": ["fastestsmallesttextencoderdecoder", "typescript"] }, "sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A=="], + + "@solana/errors": ["@solana/errors@5.5.1", "", { "dependencies": { "chalk": "5.6.2", "commander": "14.0.2" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "errors": "bin/cli.mjs" } }, "sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg=="], + + "@solana/fast-stable-stringify": ["@solana/fast-stable-stringify@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-Ni7s2FN33zTzhTFgRjEbOVFO+UAmK8qi3Iu0/GRFYK4jN696OjKHnboSQH/EacQ+yGqS54bfxf409wU5dsLLCw=="], + + "@solana/functional": ["@solana/functional@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-tTHoJcEQq3gQx5qsdsDJ0LEJeFzwNpXD80xApW9o/PPoCNimI3SALkZl+zNW8VnxRrV3l3yYvfHWBKe/X3WG3w=="], + + "@solana/instruction-plans": ["@solana/instruction-plans@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/instructions": "5.5.1", "@solana/keys": "5.5.1", "@solana/promises": "5.5.1", "@solana/transaction-messages": "5.5.1", "@solana/transactions": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-7z3CB7YMcFKuVvgcnNY8bY6IsZ8LG61Iytbz7HpNVGX2u1RthOs1tRW8luTzSG1MPL0Ox7afyAVMYeFqSPHnaQ=="], + + "@solana/instructions": ["@solana/instructions@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-h0G1CG6S+gUUSt0eo6rOtsaXRBwCq1+Js2a+Ps9Bzk9q7YHNFA75/X0NWugWLgC92waRp66hrjMTiYYnLBoWOQ=="], + + "@solana/keys": ["@solana/keys@5.5.1", "", { "dependencies": { "@solana/assertions": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/nominal-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-KRD61cL7CRL+b4r/eB9dEoVxIf/2EJ1Pm1DmRYhtSUAJD2dJ5Xw8QFuehobOGm9URqQ7gaQl+Fkc1qvDlsWqKg=="], + + "@solana/kit": ["@solana/kit@5.5.1", "", { "dependencies": { "@solana/accounts": "5.5.1", "@solana/addresses": "5.5.1", "@solana/codecs": "5.5.1", "@solana/errors": "5.5.1", "@solana/functional": "5.5.1", "@solana/instruction-plans": "5.5.1", "@solana/instructions": "5.5.1", "@solana/keys": "5.5.1", "@solana/offchain-messages": "5.5.1", "@solana/plugin-core": "5.5.1", "@solana/programs": "5.5.1", "@solana/rpc": "5.5.1", "@solana/rpc-api": "5.5.1", "@solana/rpc-parsed-types": "5.5.1", "@solana/rpc-spec-types": "5.5.1", "@solana/rpc-subscriptions": "5.5.1", "@solana/rpc-types": "5.5.1", "@solana/signers": "5.5.1", "@solana/sysvars": "5.5.1", "@solana/transaction-confirmation": "5.5.1", "@solana/transaction-messages": "5.5.1", "@solana/transactions": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-irKUGiV2yRoyf+4eGQ/ZeCRxa43yjFEL1DUI5B0DkcfZw3cr0VJtVJnrG8OtVF01vT0OUfYOcUn6zJW5TROHvQ=="], + + "@solana/nominal-types": ["@solana/nominal-types@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ=="], + + "@solana/offchain-messages": ["@solana/offchain-messages@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-data-structures": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/keys": "5.5.1", "@solana/nominal-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-g+xHH95prTU+KujtbOzj8wn+C7ZNoiLhf3hj6nYq3MTyxOXtBEysguc97jJveUZG0K97aIKG6xVUlMutg5yxhw=="], + + "@solana/options": ["@solana/options@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/codecs-data-structures": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A=="], + + "@solana/plugin-core": ["@solana/plugin-core@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-VUZl30lDQFJeiSyNfzU1EjYt2QZvoBFKEwjn1lilUJw7KgqD5z7mbV7diJhT+dLFs36i0OsjXvq5kSygn8YJ3A=="], + + "@solana/programs": ["@solana/programs@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-7U9kn0Jsx1NuBLn5HRTFYh78MV4XN145Yc3WP/q5BlqAVNlMoU9coG5IUTJIG847TUqC1lRto3Dnpwm6T4YRpA=="], + + "@solana/promises": ["@solana/promises@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-T9lfuUYkGykJmppEcssNiCf6yiYQxJkhiLPP+pyAc2z84/7r3UVIb2tNJk4A9sucS66pzJnVHZKcZVGUUp6wzA=="], + + "@solana/rpc": ["@solana/rpc@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/fast-stable-stringify": "5.5.1", "@solana/functional": "5.5.1", "@solana/rpc-api": "5.5.1", "@solana/rpc-spec": "5.5.1", "@solana/rpc-spec-types": "5.5.1", "@solana/rpc-transformers": "5.5.1", "@solana/rpc-transport-http": "5.5.1", "@solana/rpc-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-ku8zTUMrkCWci66PRIBC+1mXepEnZH/q1f3ck0kJZ95a06bOTl5KU7HeXWtskkyefzARJ5zvCs54AD5nxjQJ+A=="], + + "@solana/rpc-api": ["@solana/rpc-api@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/keys": "5.5.1", "@solana/rpc-parsed-types": "5.5.1", "@solana/rpc-spec": "5.5.1", "@solana/rpc-transformers": "5.5.1", "@solana/rpc-types": "5.5.1", "@solana/transaction-messages": "5.5.1", "@solana/transactions": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-XWOQQPhKl06Vj0xi3RYHAc6oEQd8B82okYJ04K7N0Vvy3J4PN2cxeK7klwkjgavdcN9EVkYCChm2ADAtnztKnA=="], + + "@solana/rpc-parsed-types": ["@solana/rpc-parsed-types@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-HEi3G2nZqGEsa3vX6U0FrXLaqnUCg4SKIUrOe8CezD+cSFbRTOn3rCLrUmJrhVyXlHoQVaRO9mmeovk31jWxJg=="], + + "@solana/rpc-spec": ["@solana/rpc-spec@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/rpc-spec-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q=="], + + "@solana/rpc-spec-types": ["@solana/rpc-spec-types@5.5.1", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw=="], + + "@solana/rpc-subscriptions": ["@solana/rpc-subscriptions@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/fast-stable-stringify": "5.5.1", "@solana/functional": "5.5.1", "@solana/promises": "5.5.1", "@solana/rpc-spec-types": "5.5.1", "@solana/rpc-subscriptions-api": "5.5.1", "@solana/rpc-subscriptions-channel-websocket": "5.5.1", "@solana/rpc-subscriptions-spec": "5.5.1", "@solana/rpc-transformers": "5.5.1", "@solana/rpc-types": "5.5.1", "@solana/subscribable": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-CTMy5bt/6mDh4tc6vUJms9EcuZj3xvK0/xq8IQ90rhkpYvate91RjBP+egvjgSayUg9yucU9vNuUpEjz4spM7w=="], + + "@solana/rpc-subscriptions-api": ["@solana/rpc-subscriptions-api@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/keys": "5.5.1", "@solana/rpc-subscriptions-spec": "5.5.1", "@solana/rpc-transformers": "5.5.1", "@solana/rpc-types": "5.5.1", "@solana/transaction-messages": "5.5.1", "@solana/transactions": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-5Oi7k+GdeS8xR2ly1iuSFkAv6CZqwG0Z6b1QZKbEgxadE1XGSDrhM2cn59l+bqCozUWCqh4c/A2znU/qQjROlw=="], + + "@solana/rpc-subscriptions-channel-websocket": ["@solana/rpc-subscriptions-channel-websocket@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/functional": "5.5.1", "@solana/rpc-subscriptions-spec": "5.5.1", "@solana/subscribable": "5.5.1", "ws": "^8.19.0" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-7tGfBBrYY8TrngOyxSHoCU5shy86iA9SRMRrPSyBhEaZRAk6dnbdpmUTez7gtdVo0BCvh9nzQtUycKWSS7PnFQ=="], + + "@solana/rpc-subscriptions-spec": ["@solana/rpc-subscriptions-spec@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/promises": "5.5.1", "@solana/rpc-spec-types": "5.5.1", "@solana/subscribable": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-iq+rGq5fMKP3/mKHPNB6MC8IbVW41KGZg83Us/+LE3AWOTWV1WT20KT2iH1F1ik9roi42COv/TpoZZvhKj45XQ=="], + + "@solana/rpc-transformers": ["@solana/rpc-transformers@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/functional": "5.5.1", "@solana/nominal-types": "5.5.1", "@solana/rpc-spec-types": "5.5.1", "@solana/rpc-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-OsWqLCQdcrRJKvHiMmwFhp9noNZ4FARuMkHT5us3ustDLXaxOjF0gfqZLnMkulSLcKt7TGXqMhBV+HCo7z5M8Q=="], + + "@solana/rpc-transport-http": ["@solana/rpc-transport-http@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1", "@solana/rpc-spec": "5.5.1", "@solana/rpc-spec-types": "5.5.1", "undici-types": "^7.19.2" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-yv8GoVSHqEV0kUJEIhkdOVkR2SvJ6yoWC51cJn2rSV7plr6huLGe0JgujCmB7uZhhaLbcbP3zxXxu9sOjsi7Fg=="], + + "@solana/rpc-types": ["@solana/rpc-types@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/nominal-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA=="], + + "@solana/signers": ["@solana/signers@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1", "@solana/instructions": "5.5.1", "@solana/keys": "5.5.1", "@solana/nominal-types": "5.5.1", "@solana/offchain-messages": "5.5.1", "@solana/transaction-messages": "5.5.1", "@solana/transactions": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-FY0IVaBT2kCAze55vEieR6hag4coqcuJ31Aw3hqRH7mv6sV8oqwuJmUrx+uFwOp1gwd5OEAzlv6N4hOOple4sQ=="], + + "@solana/subscribable": ["@solana/subscribable@5.5.1", "", { "dependencies": { "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-9K0PsynFq0CsmK1CDi5Y2vUIJpCqkgSS5yfDN0eKPgHqEptLEaia09Kaxc90cSZDZU5mKY/zv1NBmB6Aro9zQQ=="], + + "@solana/sysvars": ["@solana/sysvars@5.5.1", "", { "dependencies": { "@solana/accounts": "5.5.1", "@solana/codecs": "5.5.1", "@solana/errors": "5.5.1", "@solana/rpc-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA=="], + + "@solana/transaction-confirmation": ["@solana/transaction-confirmation@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/keys": "5.5.1", "@solana/promises": "5.5.1", "@solana/rpc": "5.5.1", "@solana/rpc-subscriptions": "5.5.1", "@solana/rpc-types": "5.5.1", "@solana/transaction-messages": "5.5.1", "@solana/transactions": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-j4mKlYPHEyu+OD7MBt3jRoX4ScFgkhZC6H65on4Fux6LMScgivPJlwnKoZMnsgxFgWds0pl+BYzSiALDsXlYtw=="], + + "@solana/transaction-messages": ["@solana/transaction-messages@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-data-structures": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/errors": "5.5.1", "@solana/functional": "5.5.1", "@solana/instructions": "5.5.1", "@solana/nominal-types": "5.5.1", "@solana/rpc-types": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-aXyhMCEaAp3M/4fP0akwBBQkFPr4pfwoC5CLDq999r/FUwDax2RE/h4Ic7h2Xk+JdcUwsb+rLq85Y52hq84XvQ=="], + + "@solana/transactions": ["@solana/transactions@5.5.1", "", { "dependencies": { "@solana/addresses": "5.5.1", "@solana/codecs-core": "5.5.1", "@solana/codecs-data-structures": "5.5.1", "@solana/codecs-numbers": "5.5.1", "@solana/codecs-strings": "5.5.1", "@solana/errors": "5.5.1", "@solana/functional": "5.5.1", "@solana/instructions": "5.5.1", "@solana/keys": "5.5.1", "@solana/nominal-types": "5.5.1", "@solana/rpc-types": "5.5.1", "@solana/transaction-messages": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-8hHtDxtqalZ157pnx6p8k10D7J/KY/biLzfgh9R09VNLLY3Fqi7kJvJCr7M2ik3oRll56pxhraAGCC9yIT6eOA=="], + + "@solana/web3.js": ["@solana/web3.js@1.98.4", "", { "dependencies": { "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@solana/buffer-layout": "^4.0.1", "@solana/codecs-numbers": "^2.1.0", "agentkeepalive": "^4.5.0", "bn.js": "^5.2.1", "borsh": "^0.7.0", "bs58": "^4.0.1", "buffer": "6.0.3", "fast-stable-stringify": "^1.0.0", "jayson": "^4.1.1", "node-fetch": "^2.7.0", "rpc-websockets": "^9.0.2", "superstruct": "^2.0.2" } }, "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw=="], + "@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="], "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], @@ -335,6 +467,8 @@ "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@5.0.0", "", { "dependencies": { "debug": "^4.4.1" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", "vite": "^6.3.0 || ^7.0.0" } }, "sha512-iwQ8Z4ET6ZFSt/gC+tVfcsSBHwsqc6RumSaiLUkAurW3BCpJam65cmHw0oOlDMTO0u+PZi9hilBRYN+LZNHTUQ=="], + "@swc/helpers": ["@swc/helpers@0.5.19", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.11", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.11" } }, "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.11", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.11", "@tailwindcss/oxide-darwin-arm64": "4.1.11", "@tailwindcss/oxide-darwin-x64": "4.1.11", "@tailwindcss/oxide-freebsd-x64": "4.1.11", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", "@tailwindcss/oxide-linux-x64-musl": "4.1.11", "@tailwindcss/oxide-wasm32-wasi": "4.1.11", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" } }, "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg=="], @@ -371,6 +505,8 @@ "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="], + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], + "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], @@ -383,6 +519,14 @@ "@types/node": ["@types/node@25.2.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ=="], + "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], + + "@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], + + "@types/ws": ["@types/ws@7.4.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.39.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/type-utils": "8.39.0", "@typescript-eslint/utils": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.39.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.39.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", "@typescript-eslint/typescript-estree": "8.39.0", "@typescript-eslint/visitor-keys": "8.39.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg=="], @@ -407,6 +551,54 @@ "@wagmi/core": ["@wagmi/core@3.4.0", "", { "dependencies": { "eventemitter3": "5.0.1", "mipd": "0.0.7", "zustand": "5.0.0" }, "peerDependencies": { "@tanstack/query-core": ">=5.0.0", "ox": ">=0.11.1", "typescript": ">=5.7.3", "viem": "2.x" }, "optionalPeers": ["@tanstack/query-core", "ox", "typescript"] }, "sha512-EU5gDsUp5t7+cuLv12/L8hfyWfCIKsBNiiBqpOqxZJxvAcAiQk4xFe2jMgaQPqApc3Omvxrk032M8AQ4N0cQeg=="], + "@wallet-standard/base": ["@wallet-standard/base@1.1.0", "", {}, "sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ=="], + + "@wallet-standard/wallet": ["@wallet-standard/wallet@1.1.0", "", { "dependencies": { "@wallet-standard/base": "^1.1.0" } }, "sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg=="], + + "@walletconnect/core": ["@walletconnect/core@2.23.8", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.8", "@walletconnect/utils": "2.23.8", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.44.0", "events": "3.3.0", "uint8arrays": "3.1.1" } }, "sha512-559+fA6Hh9CkEIOtrWKdDWoa3HL47glDF7D75LbqQzv4v325KXq24KEsjzDPBYr7pI49gQo7P2HpPnY1ax+8Aw=="], + + "@walletconnect/environment": ["@walletconnect/environment@1.0.1", "", { "dependencies": { "tslib": "1.14.1" } }, "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg=="], + + "@walletconnect/ethereum-provider": ["@walletconnect/ethereum-provider@2.23.8", "", { "dependencies": { "@reown/appkit": "1.8.17-wc-circular-dependencies-fix.0", "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/sign-client": "2.23.8", "@walletconnect/types": "2.23.8", "@walletconnect/universal-provider": "2.23.8", "@walletconnect/utils": "2.23.8", "events": "3.3.0" } }, "sha512-nRUWmx8ihUmqVGwQD2PHlJ7+TFT4AZPSR5ssghosVHBt8kpjgtUbE7ej/bYAmmnerDKLyYGrqWtHwjaNBPJHqA=="], + + "@walletconnect/events": ["@walletconnect/events@1.0.1", "", { "dependencies": { "keyvaluestorage-interface": "^1.0.0", "tslib": "1.14.1" } }, "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ=="], + + "@walletconnect/heartbeat": ["@walletconnect/heartbeat@1.2.2", "", { "dependencies": { "@walletconnect/events": "^1.0.1", "@walletconnect/time": "^1.0.2", "events": "^3.3.0" } }, "sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw=="], + + "@walletconnect/jsonrpc-http-connection": ["@walletconnect/jsonrpc-http-connection@1.0.8", "", { "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.6", "@walletconnect/safe-json": "^1.0.1", "cross-fetch": "^3.1.4", "events": "^3.3.0" } }, "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw=="], + + "@walletconnect/jsonrpc-provider": ["@walletconnect/jsonrpc-provider@1.0.14", "", { "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.8", "@walletconnect/safe-json": "^1.0.2", "events": "^3.3.0" } }, "sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow=="], + + "@walletconnect/jsonrpc-types": ["@walletconnect/jsonrpc-types@1.0.4", "", { "dependencies": { "events": "^3.3.0", "keyvaluestorage-interface": "^1.0.0" } }, "sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ=="], + + "@walletconnect/jsonrpc-utils": ["@walletconnect/jsonrpc-utils@1.0.8", "", { "dependencies": { "@walletconnect/environment": "^1.0.1", "@walletconnect/jsonrpc-types": "^1.0.3", "tslib": "1.14.1" } }, "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw=="], + + "@walletconnect/jsonrpc-ws-connection": ["@walletconnect/jsonrpc-ws-connection@1.0.16", "", { "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.6", "@walletconnect/safe-json": "^1.0.2", "events": "^3.3.0", "ws": "^7.5.1" } }, "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q=="], + + "@walletconnect/keyvaluestorage": ["@walletconnect/keyvaluestorage@1.1.1", "", { "dependencies": { "@walletconnect/safe-json": "^1.0.1", "idb-keyval": "^6.2.1", "unstorage": "^1.9.0" }, "peerDependencies": { "@react-native-async-storage/async-storage": "1.x" }, "optionalPeers": ["@react-native-async-storage/async-storage"] }, "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA=="], + + "@walletconnect/logger": ["@walletconnect/logger@3.0.2", "", { "dependencies": { "@walletconnect/safe-json": "^1.0.2", "pino": "10.0.0" } }, "sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA=="], + + "@walletconnect/relay-api": ["@walletconnect/relay-api@1.0.11", "", { "dependencies": { "@walletconnect/jsonrpc-types": "^1.0.2" } }, "sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q=="], + + "@walletconnect/relay-auth": ["@walletconnect/relay-auth@1.1.0", "", { "dependencies": { "@noble/curves": "1.8.0", "@noble/hashes": "1.7.0", "@walletconnect/safe-json": "^1.0.1", "@walletconnect/time": "^1.0.2", "uint8arrays": "^3.0.0" } }, "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ=="], + + "@walletconnect/safe-json": ["@walletconnect/safe-json@1.0.2", "", { "dependencies": { "tslib": "1.14.1" } }, "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA=="], + + "@walletconnect/sign-client": ["@walletconnect/sign-client@2.23.8", "", { "dependencies": { "@walletconnect/core": "2.23.8", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/logger": "3.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.8", "@walletconnect/utils": "2.23.8", "events": "3.3.0" } }, "sha512-7DtFDQZwOK4E9q+TKWL819d01dpNHA3jMcntSsQqSLNU34orbkDB/BJzW4nyWZ6H9DuGHRvibJA9wvfXjOCWBw=="], + + "@walletconnect/time": ["@walletconnect/time@1.0.2", "", { "dependencies": { "tslib": "1.14.1" } }, "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g=="], + + "@walletconnect/types": ["@walletconnect/types@2.23.8", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "events": "3.3.0" } }, "sha512-OI/0Z7/8r11EDU9bBPy5nixYgsk6SrTcOvWe9r7Nf2WvkMcPLgV7aS8rb6+nInRmDPfXuyTgzdAox0rtmfJMzg=="], + + "@walletconnect/universal-provider": ["@walletconnect/universal-provider@2.23.8", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/sign-client": "2.23.8", "@walletconnect/types": "2.23.8", "@walletconnect/utils": "2.23.8", "es-toolkit": "1.44.0", "events": "3.3.0" } }, "sha512-TFn2TNhp5vlbV2HqPU/LfkEIYZEop4WDCTTZKw/RU4DbM1e1+etmvTr5JA+8dkZU7ee48mVUDodY0zQedP+KZA=="], + + "@walletconnect/utils": ["@walletconnect/utils@2.23.8", "", { "dependencies": { "@msgpack/msgpack": "3.1.3", "@noble/ciphers": "1.3.0", "@noble/curves": "1.9.7", "@noble/hashes": "1.8.0", "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.8", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", "detect-browser": "5.3.0", "ox": "0.9.3", "uint8arrays": "3.1.1" } }, "sha512-vJrRrZFZANWmnEEnWnfVSnpQ+jdjqBb5fqSgp0VGeRX3pNr2KAHJ0TwNnEN+fbhR76JxuFrpcY7HJUT7DHDJ7w=="], + + "@walletconnect/window-getters": ["@walletconnect/window-getters@1.0.1", "", { "dependencies": { "tslib": "1.14.1" } }, "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q=="], + + "@walletconnect/window-metadata": ["@walletconnect/window-metadata@1.0.1", "", { "dependencies": { "@walletconnect/window-getters": "^1.0.1", "tslib": "1.14.1" } }, "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA=="], + "abitype": ["abitype@1.2.3", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" } }, "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg=="], "acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], @@ -415,6 +607,8 @@ "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], + "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], @@ -423,30 +617,52 @@ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="], + "axios-retry": ["axios-retry@4.5.0", "", { "dependencies": { "is-retry-allowed": "^2.2.0" }, "peerDependencies": { "axios": "0.x || 1.x" } }, "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ=="], + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "base-x": ["base-x@5.0.1", "", {}, "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "big.js": ["big.js@6.2.2", "", {}, "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ=="], + "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], + "blakejs": ["blakejs@1.2.1", "", {}, "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ=="], + + "bn.js": ["bn.js@5.2.3", "", {}, "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w=="], + + "borsh": ["borsh@0.7.0", "", { "dependencies": { "bn.js": "^5.2.0", "bs58": "^4.0.0", "text-encoding-utf-8": "^1.0.2" } }, "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA=="], + "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "brotli-wasm": ["brotli-wasm@3.0.1", "", {}, "sha512-U3K72/JAi3jITpdhZBqzSUq+DUY697tLxOuFXB+FpAE/Ug+5C3VZrv4uA674EUZHxNAuQ9wETXNqQkxZD6oL4A=="], + + "bs58": ["bs58@6.0.0", "", { "dependencies": { "base-x": "^5.0.0" } }, "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw=="], + + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "bufferutil": ["bufferutil@4.1.0", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw=="], @@ -461,8 +677,12 @@ "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "charenc": ["charenc@0.0.2", "", {}, "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], @@ -471,6 +691,8 @@ "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="], + "cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], @@ -491,6 +713,8 @@ "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + "cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="], + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], "crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="], @@ -499,12 +723,22 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="], + + "crypt": ["crypt@0.0.2", "", {}, "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="], + "cssesc": ["cssesc@3.0.0", "", { "bin": "bin/cssesc" }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="], + "dayjs": ["dayjs@1.11.13", "", {}, "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="], + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], @@ -513,14 +747,20 @@ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "delay": ["delay@5.0.0", "", {}, "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + "detect-browser": ["detect-browser@5.3.0", "", {}, "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w=="], "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], "devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="], + "dijkstrajs": ["dijkstrajs@1.0.3", "", {}, "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="], + "dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="], "drizzle-kit": ["drizzle-kit@0.31.9", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-GViD3IgsXn7trFyBUUHyTFBpH/FsHTxYJ66qdbVggxef4UBPHRYxQaRzYLTuekYnk9i5FIEL9pbBIwMqX/Uwrg=="], @@ -533,6 +773,8 @@ "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "encode-utf8": ["encode-utf8@1.0.3", "", {}, "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw=="], + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], "engine.io-client": ["engine.io-client@6.6.4", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3", "xmlhttprequest-ssl": "~2.1.1" } }, "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw=="], @@ -553,6 +795,12 @@ "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + "es-toolkit": ["es-toolkit@1.44.0", "", {}, "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg=="], + + "es6-promise": ["es6-promise@4.2.8", "", {}, "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="], + + "es6-promisify": ["es6-promisify@5.0.0", "", { "dependencies": { "es6-promise": "^4.0.3" } }, "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ=="], + "esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": "bin/esbuild" }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -591,12 +839,16 @@ "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], "extension-port-stream": ["extension-port-stream@3.0.0", "", { "dependencies": { "readable-stream": "^3.6.2 || ^4.4.2", "webextension-polyfill": ">=0.10.0 <1.0" } }, "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw=="], + "eyes": ["eyes@0.1.8", "", {}, "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-glob": ["fast-glob@3.3.3", "", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], @@ -607,6 +859,8 @@ "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + "fast-stable-stringify": ["fast-stable-stringify@1.0.0", "", {}, "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag=="], + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="], @@ -633,6 +887,8 @@ "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], @@ -653,6 +909,8 @@ "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], + "h3": ["h3@1.15.6", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], @@ -663,8 +921,16 @@ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hono": ["hono@4.12.7", "", {}, "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw=="], + + "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], + "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], + "idb-keyval": ["idb-keyval@6.2.1", "", {}, "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], @@ -673,10 +939,14 @@ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], + "is-arguments": ["is-arguments@1.2.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA=="], "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], + "is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="], + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -693,6 +963,8 @@ "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + "is-retry-allowed": ["is-retry-allowed@2.2.0", "", {}, "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg=="], + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], @@ -701,10 +973,16 @@ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "isomorphic-ws": ["isomorphic-ws@4.0.1", "", { "peerDependencies": { "ws": "*" } }, "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w=="], + "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], + "jayson": ["jayson@4.3.0", "", { "dependencies": { "@types/connect": "^3.4.33", "@types/node": "^12.12.54", "@types/ws": "^7.4.4", "commander": "^2.20.3", "delay": "^5.0.0", "es6-promisify": "^5.0.0", "eyes": "^0.1.8", "isomorphic-ws": "^4.0.1", "json-stringify-safe": "^5.0.1", "stream-json": "^1.9.1", "uuid": "^8.3.2", "ws": "^7.5.10" }, "bin": { "jayson": "bin/jayson.js" } }, "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ=="], + "jiti": ["jiti@2.5.1", "", { "bin": "lib/jiti-cli.mjs" }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="], + "jose": ["jose@6.2.1", "", {}, "sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw=="], + "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], @@ -713,8 +991,12 @@ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + "keyvaluestorage-interface": ["keyvaluestorage-interface@1.0.0", "", {}, "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g=="], + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], "known-css-properties": ["known-css-properties@0.37.0", "", {}, "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ=="], @@ -751,6 +1033,12 @@ "listr2": ["listr2@8.3.3", "", { "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ=="], + "lit": ["lit@3.3.0", "", { "dependencies": { "@lit/reactive-element": "^2.1.0", "lit-element": "^4.2.0", "lit-html": "^3.3.0" } }, "sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw=="], + + "lit-element": ["lit-element@4.2.2", "", { "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0", "@lit/reactive-element": "^2.1.0", "lit-html": "^3.3.0" } }, "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w=="], + + "lit-html": ["lit-html@3.3.2", "", { "dependencies": { "@types/trusted-types": "^2.0.2" } }, "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw=="], + "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], @@ -759,10 +1047,14 @@ "log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="], + "lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="], + "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "md5": ["md5@2.3.0", "", { "dependencies": { "charenc": "0.0.2", "crypt": "0.0.2", "is-buffer": "~1.1.6" } }, "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "micro-ftch": ["micro-ftch@0.3.1", "", {}, "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg=="], @@ -795,6 +1087,8 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], + "nano-spawn": ["nano-spawn@1.0.3", "", {}, "sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA=="], "nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], @@ -803,12 +1097,22 @@ "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + "node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + "obj-multiplex": ["obj-multiplex@1.0.0", "", { "dependencies": { "end-of-stream": "^1.4.0", "once": "^1.4.0", "readable-stream": "^2.3.3" } }, "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA=="], + "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], @@ -819,12 +1123,14 @@ "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - "ox": ["ox@0.11.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" } }, "sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw=="], + "ox": ["ox@0.6.9", "", { "dependencies": { "@adraffy/ens-normalize": "^1.10.1", "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@scure/bip32": "^1.5.0", "@scure/bip39": "^1.4.0", "abitype": "^1.0.6", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug=="], "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -841,12 +1147,22 @@ "pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="], + "pino": ["pino@10.0.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "slow-redact": "^0.3.0", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA=="], + + "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], + + "pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="], + "playwright": ["playwright@1.58.2", "", { "dependencies": { "playwright-core": "1.58.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A=="], "playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="], + "pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="], + "pony-cause": ["pony-cause@2.1.11", "", {}, "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg=="], + "porto": ["porto@0.2.37", "", { "dependencies": { "hono": "^4.10.3", "idb-keyval": "^6.2.1", "mipd": "^0.0.7", "ox": "^0.9.6", "zod": "^4.1.5", "zustand": "^5.0.1" }, "peerDependencies": { "@tanstack/react-query": ">=5.59.0", "@wagmi/core": ">=2.16.3", "expo-auth-session": ">=7.0.8", "expo-crypto": ">=15.0.7", "expo-web-browser": ">=15.0.8", "react": ">=18", "react-native": ">=0.81.4", "typescript": ">=5.4.0", "viem": ">=2.37.0", "wagmi": ">=2.0.0" }, "optionalPeers": ["@tanstack/react-query", "expo-auth-session", "expo-crypto", "expo-web-browser", "react", "react-native", "typescript", "wagmi"], "bin": { "porto": "dist/cli/bin/index.js" } }, "sha512-l3IOUvf5O9rM82VW7v/R5Y2X2niU1kmfXMYYPr/VLMvtKKySr7PiAO3TXWjGft5PV17800VnMCmEaRuxA+N4ug=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], @@ -859,6 +1175,8 @@ "postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="], + "preact": ["preact@10.24.2", "", {}, "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q=="], + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], "prettier": ["prettier@3.4.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ=="], @@ -869,22 +1187,38 @@ "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + + "proxy-compare": ["proxy-compare@3.0.1", "", {}, "sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q=="], + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + "qrcode": ["qrcode@1.5.3", "", { "dependencies": { "dijkstrajs": "^1.0.1", "encode-utf8": "^1.0.3", "pngjs": "^5.0.0", "yargs": "^15.3.1" }, "bin": { "qrcode": "bin/qrcode" } }, "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], + + "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], + "regexparam": ["regexparam@3.0.0", "", {}, "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], @@ -897,6 +1231,8 @@ "rollup": ["rollup@4.46.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.46.2", "@rollup/rollup-android-arm64": "4.46.2", "@rollup/rollup-darwin-arm64": "4.46.2", "@rollup/rollup-darwin-x64": "4.46.2", "@rollup/rollup-freebsd-arm64": "4.46.2", "@rollup/rollup-freebsd-x64": "4.46.2", "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", "@rollup/rollup-linux-arm-musleabihf": "4.46.2", "@rollup/rollup-linux-arm64-gnu": "4.46.2", "@rollup/rollup-linux-arm64-musl": "4.46.2", "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", "@rollup/rollup-linux-ppc64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-gnu": "4.46.2", "@rollup/rollup-linux-riscv64-musl": "4.46.2", "@rollup/rollup-linux-s390x-gnu": "4.46.2", "@rollup/rollup-linux-x64-gnu": "4.46.2", "@rollup/rollup-linux-x64-musl": "4.46.2", "@rollup/rollup-win32-arm64-msvc": "4.46.2", "@rollup/rollup-win32-ia32-msvc": "4.46.2", "@rollup/rollup-win32-x64-msvc": "4.46.2", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg=="], + "rpc-websockets": ["rpc-websockets@9.3.5", "", { "dependencies": { "@swc/helpers": "^0.5.11", "@types/uuid": "^10.0.0", "@types/ws": "^8.2.2", "buffer": "^6.0.3", "eventemitter3": "^5.0.1", "uuid": "^11.0.0", "ws": "^8.5.0" }, "optionalDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^6.0.0" } }, "sha512-4mAmr+AEhPYJ9TmDtxF3r3ZcbWy7W8kvZ4PoZYw/Xgp2J7WixjwTgiQZsoTDvch5nimmg3Ay6/0Kuh9oIvVs9A=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], @@ -907,8 +1243,12 @@ "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], @@ -927,18 +1267,28 @@ "slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="], + "slow-redact": ["slow-redact@0.3.2", "", {}, "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw=="], + "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], + "sonic-boom": ["sonic-boom@4.2.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], + "stream-chain": ["stream-chain@2.2.5", "", {}, "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA=="], + + "stream-json": ["stream-json@1.9.1", "", { "dependencies": { "stream-chain": "^2.2.5" } }, "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw=="], + "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], @@ -949,6 +1299,8 @@ "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "superstruct": ["superstruct@2.0.2", "", {}, "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "svelte": ["svelte@5.38.0", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-cWF1Oc2IM/QbktdK89u5lt9MdKxRtQnRKnf2tq6KOhYuhLOd2hbMuTiJ+vWMzAeMDe81AzbCgLd4GVtOJ4fDRg=="], @@ -963,6 +1315,10 @@ "tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="], + "text-encoding-utf-8": ["text-encoding-utf-8@1.0.2", "", {}, "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg=="], + + "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], + "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -983,12 +1339,18 @@ "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], + "uint8arrays": ["uint8arrays@3.1.1", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg=="], + + "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], + "undici": ["undici@7.13.0", "", {}, "sha512-l+zSMssRqrzDcb3fjMkjjLGmuiiK2pMIcV++mJaAc9vhjSGpvM7h43QgP+OAMb1GImHmbPyG2tBXeuyG5iY4gA=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="], + "unstorage": ["unstorage@1.17.4", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], "use-sync-external-store": ["use-sync-external-store@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw=="], @@ -1001,6 +1363,8 @@ "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "valtio": ["valtio@2.1.7", "", { "dependencies": { "proxy-compare": "^3.0.1" }, "peerDependencies": { "@types/react": ">=18.0.0", "react": ">=18.0.0" }, "optionalPeers": ["@types/react", "react"] }, "sha512-DwJhCDpujuQuKdJ2H84VbTjEJJteaSmqsuUltsfbfdbotVfNeTE4K/qc/Wi57I9x8/2ed4JNdjEna7O6PfavRg=="], + "viem": ["viem@2.45.1", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.2.3", "isows": "1.0.7", "ox": "0.11.3", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" } }, "sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA=="], "vite": ["vite@7.1.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx"], "bin": "bin/vite.js" }, "sha512-yJ+Mp7OyV+4S+afWo+QyoL9jFWD11QFH0i5i7JypnfTcA1rmgxCbiA8WwAICDEtZ1Z1hzrVhN8R8rGTqkTY8ZQ=="], @@ -1017,6 +1381,8 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], + "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], @@ -1035,10 +1401,16 @@ "xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="], + "y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "yaml": ["yaml@2.8.1", "", { "bin": "bin.mjs" }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + + "yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], @@ -1047,9 +1419,21 @@ "zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="], - "zod": ["zod@3.22.4", "", {}, "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "zustand": ["zustand@5.0.3", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg=="], + + "@base-org/account/clsx": ["clsx@1.2.1", "", {}, "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="], - "zustand": ["zustand@5.0.0", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ=="], + "@coinbase/cdp-sdk/abitype": ["abitype@1.0.6", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3 >=3.22.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A=="], + + "@coinbase/cdp-sdk/axios": ["axios@1.13.6", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ=="], + + "@coinbase/cdp-sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@coinbase/wallet-sdk/clsx": ["clsx@1.2.1", "", {}, "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="], + + "@coinbase/wallet-sdk/preact": ["preact@10.28.4", "", {}, "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ=="], "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], @@ -1071,12 +1455,96 @@ "@poppinss/dumper/supports-color": ["supports-color@10.1.0", "", {}, "sha512-GBuewsPrhJPftT+fqDa9oI/zc5HNsG9nREqwzoSFDOIqf0NggOZbHQj2TE1P1CDJK8ZogFnlZY9hWoUiur7I/A=="], + "@reown/appkit/@walletconnect/universal-provider": ["@walletconnect/universal-provider@2.23.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/sign-client": "2.23.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "es-toolkit": "1.39.3", "events": "3.3.0" } }, "sha512-vs9iorPUAiVesFJ95O6XvLjmRgF+B2TspxJNL90ZULbrkRw4JFsmaRdb965PZKc+s182k1MkS/MQ0o964xRcEw=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider": ["@walletconnect/universal-provider@2.23.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/sign-client": "2.23.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "es-toolkit": "1.39.3", "events": "3.3.0" } }, "sha512-vs9iorPUAiVesFJ95O6XvLjmRgF+B2TspxJNL90ZULbrkRw4JFsmaRdb965PZKc+s182k1MkS/MQ0o964xRcEw=="], + + "@reown/appkit-utils/@base-org/account": ["@base-org/account@2.4.0", "", { "dependencies": { "@coinbase/cdp-sdk": "^1.0.0", "@noble/hashes": "1.4.0", "clsx": "1.2.1", "eventemitter3": "5.0.1", "idb-keyval": "6.2.1", "ox": "0.6.9", "preact": "10.24.2", "viem": "^2.31.7", "zustand": "5.0.3" } }, "sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug=="], + + "@reown/appkit-utils/@walletconnect/universal-provider": ["@walletconnect/universal-provider@2.23.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/sign-client": "2.23.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "es-toolkit": "1.39.3", "events": "3.3.0" } }, "sha512-vs9iorPUAiVesFJ95O6XvLjmRgF+B2TspxJNL90ZULbrkRw4JFsmaRdb965PZKc+s182k1MkS/MQ0o964xRcEw=="], + + "@reown/appkit-wallet/zod": ["zod@3.22.4", "", {}, "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg=="], + "@scure/bip32/@noble/curves": ["@noble/curves@1.9.6", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA=="], + "@solana/codecs/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/codecs-data-structures/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/codecs-numbers/@solana/codecs-core": ["@solana/codecs-core@2.3.0", "", { "dependencies": { "@solana/errors": "2.3.0" }, "peerDependencies": { "typescript": ">=5.3.3" } }, "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw=="], + + "@solana/codecs-numbers/@solana/errors": ["@solana/errors@2.3.0", "", { "dependencies": { "chalk": "^5.4.1", "commander": "^14.0.0" }, "peerDependencies": { "typescript": ">=5.3.3" }, "bin": { "errors": "bin/cli.mjs" } }, "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ=="], + + "@solana/codecs-strings/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/errors/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "@solana/errors/commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], + + "@solana/offchain-messages/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/options/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/rpc-subscriptions-channel-websocket/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + + "@solana/rpc-transport-http/undici-types": ["undici-types@7.22.0", "", {}, "sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw=="], + + "@solana/rpc-types/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/transaction-messages/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/transactions/@solana/codecs-numbers": ["@solana/codecs-numbers@5.5.1", "", { "dependencies": { "@solana/codecs-core": "5.5.1", "@solana/errors": "5.5.1" }, "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw=="], + + "@solana/web3.js/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@solana/web3.js/bs58": ["bs58@4.0.1", "", { "dependencies": { "base-x": "^3.0.2" } }, "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw=="], + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@wagmi/core/ox": ["ox@0.11.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" } }, "sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw=="], + + "@wagmi/core/zustand": ["zustand@5.0.0", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ=="], + + "@walletconnect/environment/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@walletconnect/events/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@walletconnect/jsonrpc-http-connection/cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], + + "@walletconnect/jsonrpc-utils/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@walletconnect/jsonrpc-ws-connection/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + + "@walletconnect/keyvaluestorage/idb-keyval": ["idb-keyval@6.2.2", "", {}, "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg=="], + + "@walletconnect/relay-auth/@noble/curves": ["@noble/curves@1.8.0", "", { "dependencies": { "@noble/hashes": "1.7.0" } }, "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ=="], + + "@walletconnect/relay-auth/@noble/hashes": ["@noble/hashes@1.7.0", "", {}, "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w=="], + + "@walletconnect/safe-json/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@walletconnect/time/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@walletconnect/utils/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@walletconnect/utils/ox": ["ox@0.9.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg=="], + + "@walletconnect/window-getters/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "@walletconnect/window-metadata/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "borsh/bs58": ["bs58@4.0.1", "", { "dependencies": { "base-x": "^3.0.2" } }, "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw=="], + + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + "eciesjs/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], "ethereum-cryptography/@noble/curves": ["@noble/curves@1.4.2", "", { "dependencies": { "@noble/hashes": "1.4.0" } }, "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw=="], @@ -1089,6 +1557,14 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "h3/ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "jayson/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + + "jayson/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "jayson/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "lint-staged/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "log-update/slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], @@ -1103,22 +1579,50 @@ "obj-multiplex/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + "ofetch/ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "ox/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + "porto/idb-keyval": ["idb-keyval@6.2.2", "", {}, "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg=="], + + "porto/ox": ["ox@0.9.17", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-rKAnhzhRU3Xh3hiko+i1ZxywZ55eWQzeS/Q4HRKLx2PqfHOolisZHErSsJVipGlmQKHW5qwOED/GighEw9dbLg=="], + + "porto/zustand": ["zustand@5.0.11", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg=="], + "postcss-load-config/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="], "postcss-load-config/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + "rpc-websockets/@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "rpc-websockets/utf-8-validate": ["utf-8-validate@6.0.6", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA=="], + + "rpc-websockets/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + + "unstorage/ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "viem/ox": ["ox@0.11.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" } }, "sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw=="], + "wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": "bin/esbuild" }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "youch/cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + "@coinbase/cdp-sdk/axios/form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], @@ -1169,8 +1673,50 @@ "@metamask/sdk/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/sign-client": ["@walletconnect/sign-client@2.23.2", "", { "dependencies": { "@walletconnect/core": "2.23.2", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/logger": "3.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "events": "3.3.0" } }, "sha512-LL5KgmJHvY5NqQn+ZHQJLia1p6fpUWXHtiG97S5rNfyuPx6gT/Jkkwqc2LwdmAjFkr61t8zTagHC9ETq203mNA=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/types": ["@walletconnect/types@2.23.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "events": "3.3.0" } }, "sha512-5dxBCdUM+4Dqe1/A7uqkm2tWPXce4UUGSr+ImfI0YjwEExQS8+TzdOlhMt3n32ncnBCllU5paG+fsndT06R0iw=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils": ["@walletconnect/utils@2.23.2", "", { "dependencies": { "@msgpack/msgpack": "3.1.2", "@noble/ciphers": "1.3.0", "@noble/curves": "1.9.7", "@noble/hashes": "1.8.0", "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", "bs58": "6.0.0", "detect-browser": "5.3.0", "ox": "0.9.3", "uint8arrays": "3.1.1" } }, "sha512-ReSjU3kX+3i3tYJQZbVfetY5SSUL+iM6uiIVVD1PJalePa/5A40VgLVRTF7sDCJTIFfpf3Mt4bFjeaYuoxWtIw=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/es-toolkit": ["es-toolkit@1.39.3", "", {}, "sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww=="], + + "@reown/appkit-utils/@base-org/account/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="], + + "@reown/appkit-utils/@base-org/account/clsx": ["clsx@1.2.1", "", {}, "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/sign-client": ["@walletconnect/sign-client@2.23.2", "", { "dependencies": { "@walletconnect/core": "2.23.2", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/logger": "3.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "events": "3.3.0" } }, "sha512-LL5KgmJHvY5NqQn+ZHQJLia1p6fpUWXHtiG97S5rNfyuPx6gT/Jkkwqc2LwdmAjFkr61t8zTagHC9ETq203mNA=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/types": ["@walletconnect/types@2.23.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "events": "3.3.0" } }, "sha512-5dxBCdUM+4Dqe1/A7uqkm2tWPXce4UUGSr+ImfI0YjwEExQS8+TzdOlhMt3n32ncnBCllU5paG+fsndT06R0iw=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils": ["@walletconnect/utils@2.23.2", "", { "dependencies": { "@msgpack/msgpack": "3.1.2", "@noble/ciphers": "1.3.0", "@noble/curves": "1.9.7", "@noble/hashes": "1.8.0", "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", "bs58": "6.0.0", "detect-browser": "5.3.0", "ox": "0.9.3", "uint8arrays": "3.1.1" } }, "sha512-ReSjU3kX+3i3tYJQZbVfetY5SSUL+iM6uiIVVD1PJalePa/5A40VgLVRTF7sDCJTIFfpf3Mt4bFjeaYuoxWtIw=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/es-toolkit": ["es-toolkit@1.39.3", "", {}, "sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client": ["@walletconnect/sign-client@2.23.2", "", { "dependencies": { "@walletconnect/core": "2.23.2", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/logger": "3.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "events": "3.3.0" } }, "sha512-LL5KgmJHvY5NqQn+ZHQJLia1p6fpUWXHtiG97S5rNfyuPx6gT/Jkkwqc2LwdmAjFkr61t8zTagHC9ETq203mNA=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/types": ["@walletconnect/types@2.23.2", "", { "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "events": "3.3.0" } }, "sha512-5dxBCdUM+4Dqe1/A7uqkm2tWPXce4UUGSr+ImfI0YjwEExQS8+TzdOlhMt3n32ncnBCllU5paG+fsndT06R0iw=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils": ["@walletconnect/utils@2.23.2", "", { "dependencies": { "@msgpack/msgpack": "3.1.2", "@noble/ciphers": "1.3.0", "@noble/curves": "1.9.7", "@noble/hashes": "1.8.0", "@scure/base": "1.2.6", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "blakejs": "1.2.1", "bs58": "6.0.0", "detect-browser": "5.3.0", "ox": "0.9.3", "uint8arrays": "3.1.1" } }, "sha512-ReSjU3kX+3i3tYJQZbVfetY5SSUL+iM6uiIVVD1PJalePa/5A40VgLVRTF7sDCJTIFfpf3Mt4bFjeaYuoxWtIw=="], + + "@reown/appkit/@walletconnect/universal-provider/es-toolkit": ["es-toolkit@1.39.3", "", {}, "sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww=="], + + "@solana/codecs-numbers/@solana/errors/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "@solana/web3.js/bs58/base-x": ["base-x@3.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA=="], + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@walletconnect/utils/ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + + "borsh/bs58/base-x": ["base-x@3.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA=="], + + "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ethereum-cryptography/@scure/bip32/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="], "ethereum-cryptography/@scure/bip39/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="], @@ -1181,6 +1727,8 @@ "obj-multiplex/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "unstorage/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], @@ -1230,5 +1778,53 @@ "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="], "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], + + "yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.23.2", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.39.3", "events": "3.3.0", "uint8arrays": "3.1.1" } }, "sha512-KkaTELRu8t/mt3J9doCQ1fBGCbYsCNfpo2JpKdCwKQR7PVjVKeVpYQK/blVkA5m6uLPpBtVRbOMKjnHW1m7JLw=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/@msgpack/msgpack": ["@msgpack/msgpack@3.1.2", "", {}, "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/ox": ["ox@0.9.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.23.2", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.39.3", "events": "3.3.0", "uint8arrays": "3.1.1" } }, "sha512-KkaTELRu8t/mt3J9doCQ1fBGCbYsCNfpo2JpKdCwKQR7PVjVKeVpYQK/blVkA5m6uLPpBtVRbOMKjnHW1m7JLw=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/@msgpack/msgpack": ["@msgpack/msgpack@3.1.2", "", {}, "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/ox": ["ox@0.9.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.23.2", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "3.0.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.23.2", "@walletconnect/utils": "2.23.2", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.39.3", "events": "3.3.0", "uint8arrays": "3.1.1" } }, "sha512-KkaTELRu8t/mt3J9doCQ1fBGCbYsCNfpo2JpKdCwKQR7PVjVKeVpYQK/blVkA5m6uLPpBtVRbOMKjnHW1m7JLw=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@msgpack/msgpack": ["@msgpack/msgpack@3.1.2", "", {}, "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/ox": ["ox@0.9.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg=="], + + "@solana/web3.js/bs58/base-x/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "borsh/bs58/base-x/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + + "@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + + "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + + "yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], } } diff --git a/package.json b/package.json index db2e3fd..8c9dd76 100644 --- a/package.json +++ b/package.json @@ -46,15 +46,21 @@ "vite": "^7.1.1" }, "dependencies": { - "@lifi/intent": "0.0.3-alpha.1", + "@base-org/account": "^2.5.1", + "@coinbase/wallet-sdk": "^4.3.6", "@electric-sql/pglite": "^0.3.15", + "@lifi/intent": "0.0.3-alpha.1", "@metamask/sdk": "^0.34.0", + "@safe-global/safe-apps-provider": "~0.18.6", + "@safe-global/safe-apps-sdk": "^9.1.0", "@sveltejs/adapter-cloudflare": "^7.0.3", "@wagmi/connectors": "^7.2.1", "@wagmi/core": "^3.4.0", + "@walletconnect/ethereum-provider": "^2.21.1", "axios": "^1.9.0", "base64-js": "^1.5.1", "drizzle-orm": "^0.45.1", + "porto": "~0.2.35", "rxjs": "^7.8.2", "viem": "~2.45.1", "wagmi": "^3.5.0" From 322e58b60fc0a56aef58d86644e0d3dedbc40502 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 10 Mar 2026 20:46:04 +0400 Subject: [PATCH 8/9] Update wrangler for crypto --- wrangler.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrangler.toml b/wrangler.toml index 73bbe8e..d00003a 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,6 +1,6 @@ name = "lintent-worker" main = ".svelte-kit/cloudflare/_worker.js" -compatibility_date = "2024-03-06" +compatibility_date = "2026-03-06" compatibility_flags = ["nodejs_compat"] # account_id is NOT set here — passed via CLOUDFLARE_ACCOUNT_ID in CI From d30052f61843fa6e554c794b6bd3028dd8236107 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 10 Mar 2026 20:51:33 +0400 Subject: [PATCH 9/9] Fix db crash --- src/lib/db.ts | 7 ++++--- src/lib/screens/IssueIntent.svelte | 21 ++++++++++++++++++--- src/lib/screens/ManageDeposit.svelte | 7 ++++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/lib/db.ts b/src/lib/db.ts index 2640e07..23116dc 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -10,7 +10,7 @@ let initDbPromise: Promise | undefined> | null = null async function migrateDb(instance: ReturnType) { // dialect and session will appear to not exist...but they do on the pglite drizzle instance - // @ts-ignore + // @ts-expect-error pglite drizzle exposes migrate internals not present in the public type await instance.dialect.migrate(migrations, instance.session, { migrationsTable: "drizzle_migrations" } satisfies Omit); @@ -26,11 +26,12 @@ export async function initDb() { const pglite = new PGlite("idb://orders"); // Create a Drizzle instance over the opened SQLite-compatible database - db = drizzle(pglite); + const instance = drizzle(pglite); // Run migrations so tables are created on first load - await migrateDb(db); + await migrateDb(instance); + db = instance; return db; })().catch((error) => { initDbPromise = null; diff --git a/src/lib/screens/IssueIntent.svelte b/src/lib/screens/IssueIntent.svelte index 5a7f32f..105c6a1 100644 --- a/src/lib/screens/IssueIntent.svelte +++ b/src/lib/screens/IssueIntent.svelte @@ -89,7 +89,12 @@ } for (let i = 0; i < store.inputTokens.length; ++i) { const { token, amount } = store.inputTokens[i]; - store.allowances[token.chainId][token.address].then((a) => { + const allowancePromise = store.allowances[token.chainId]?.[token.address]; + if (!allowancePromise) { + allowanceCheck = false; + continue; + } + allowancePromise.then((a) => { allowanceCheck = allowanceCheck && a >= amount; }); } @@ -103,7 +108,12 @@ } for (let i = 0; i < store.inputTokens.length; ++i) { const { token, amount } = store.inputTokens[i]; - store.balances[token.chainId][token.address].then((b) => { + const balancePromise = store.balances[token.chainId]?.[token.address]; + if (!balancePromise) { + balanceCheckWallet = false; + continue; + } + balancePromise.then((b) => { balanceCheckWallet = balanceCheckWallet && b >= amount; }); } @@ -117,7 +127,12 @@ } for (let i = 0; i < store.inputTokens.length; ++i) { const { token, amount } = store.inputTokens[i]; - store.compactBalances[token.chainId][token.address].then((b) => { + const compactBalancePromise = store.compactBalances[token.chainId]?.[token.address]; + if (!compactBalancePromise) { + balanceCheckCompact = false; + continue; + } + compactBalancePromise.then((b) => { balanceCheckCompact = balanceCheckCompact && b >= amount; }); } diff --git a/src/lib/screens/ManageDeposit.svelte b/src/lib/screens/ManageDeposit.svelte index 0f90551..1e59847 100644 --- a/src/lib/screens/ManageDeposit.svelte +++ b/src/lib/screens/ManageDeposit.svelte @@ -52,7 +52,12 @@ allowance = 0n; return; } - store.allowances[token.chainId][token.address].then((a) => { + const allowancePromise = store.allowances[token.chainId]?.[token.address]; + if (!allowancePromise) { + allowance = 0n; + return; + } + allowancePromise.then((a) => { allowance = a; }); });