diff --git a/package.json b/package.json index f92cc8a..503c230 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,10 @@ "preview": "vite preview", "prepare": "husky", "test": "bun run test:all", - "test:unit": "bun test tests/unit tests/db.test.ts --coverage", - "test:e2e": "bunx playwright test", - "test:e2e:headed": "bunx playwright test --headed", - "test:e2e:ui": "bunx playwright test --ui", + "test:unit": "svelte-kit sync && bun test tests/unit tests/db.test.ts --coverage", + "test:e2e": "svelte-kit sync && bunx playwright test", + "test:e2e:headed": "svelte-kit sync && bunx playwright test --headed", + "test:e2e:ui": "svelte-kit sync && bunx playwright test --ui", "test:all": "bun run test:unit && bun run test:e2e", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", diff --git a/src/lib/components/GetQuote.svelte b/src/lib/components/GetQuote.svelte index 8b68565..ef742c2 100644 --- a/src/lib/components/GetQuote.svelte +++ b/src/lib/components/GetQuote.svelte @@ -2,28 +2,44 @@ import { OrderServer } from "$lib/libraries/orderServer"; import type { TokenContext } from "$lib/state.svelte"; import { interval } from "rxjs"; + import { getAddress } from "viem"; let { exclusiveFor = $bindable(), + useExclusiveForQuoteRequest = false, inputTokens, outputTokens = $bindable(), account, mainnet }: { exclusiveFor: string; + useExclusiveForQuoteRequest?: boolean; inputTokens: TokenContext[]; outputTokens: TokenContext[]; account: () => `0x${string}`; mainnet: boolean; } = $props(); + const toChecksumAddress = (value: string): `0x${string}` | undefined => { + try { + return getAddress(value); + } catch { + return undefined; + } + }; + const orderServer = $derived(new OrderServer(mainnet)); async function getQuoteAndSet() { try { + const requestedExclusiveFor = useExclusiveForQuoteRequest + ? toChecksumAddress(exclusiveFor) + : undefined; + const response = await orderServer.getQuotes({ user: account(), userChain: inputTokens[0].token.chain, + exclusiveFor: requestedExclusiveFor, inputs: inputTokens.map(({ token, amount }) => { return { sender: account(), diff --git a/src/lib/components/ui/ScreenFrame.svelte b/src/lib/components/ui/ScreenFrame.svelte index 1cd9eef..b9b30ed 100644 --- a/src/lib/components/ui/ScreenFrame.svelte +++ b/src/lib/components/ui/ScreenFrame.svelte @@ -17,8 +17,12 @@
-

{title}

-

{description}

+ {#if title} +

{title}

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

{description}

+ {/if}
{@render children?.()}
diff --git a/src/lib/libraries/intentList.ts b/src/lib/libraries/intentList.ts index b2110c8..415b7ae 100644 --- a/src/lib/libraries/intentList.ts +++ b/src/lib/libraries/intentList.ts @@ -7,9 +7,9 @@ import { INPUT_SETTLER_COMPACT_LIFI, MULTICHAIN_INPUT_SETTLER_ESCROW, MULTICHAIN_INPUT_SETTLER_COMPACT -} from "$lib/config"; -import { orderToIntent } from "$lib/libraries/intent"; -import { bytes32ToAddress, idToToken } from "$lib/utils/convert"; +} from "../config"; +import { orderToIntent } from "./intent"; +import { bytes32ToAddress, idToToken } from "../utils/convert"; import type { OrderContainer, StandardOrder, MultichainOrder } from "../../types"; export type Chip = { diff --git a/src/lib/libraries/orderServer.ts b/src/lib/libraries/orderServer.ts index c4749c1..c16c1e3 100644 --- a/src/lib/libraries/orderServer.ts +++ b/src/lib/libraries/orderServer.ts @@ -62,6 +62,7 @@ type GetQuoteOptions = { amount: bigint; }[]; minValidUntil?: number; + exclusiveFor?: `0x${string}`; }; type GetQuoteResponse = { @@ -197,11 +198,33 @@ export class OrderServer { * @returns The response data containing the quotes */ async getQuotes(options: GetQuoteOptions): Promise { - const { user, userChain, inputs, outputs, minValidUntil } = options; + const { user, userChain, inputs, outputs, minValidUntil, exclusiveFor } = options; const lockType: undefined | { kind: "the-compact" } = undefined; - const rq = { + const rq: { + user: string; + intent: { + intentType: "oif-swap"; + inputs: { + user: string; + asset: string; + amount: string; + lock: { kind: "the-compact" } | undefined; + }[]; + outputs: { + receiver: string; + asset: string; + amount: string; + }[]; + swapType: "exact-input"; + minValidUntil: number | undefined; + }; + supportedTypes: ["oif-escrow-v0"]; + metadata?: { + exclusiveFor: `0x${string}`; + }; + } = { user: getInteropableAddress(user, chainMap[userChain].id), intent: { intentType: "oif-swap", @@ -225,6 +248,7 @@ export class OrderServer { }, supportedTypes: ["oif-escrow-v0"] }; + if (exclusiveFor) rq.metadata = { exclusiveFor }; try { return await this.postWithRetry("/quote/request", rq, { diff --git a/src/lib/screens/ConnectWallet.svelte b/src/lib/screens/ConnectWallet.svelte index f41d17a..1279c99 100644 --- a/src/lib/screens/ConnectWallet.svelte +++ b/src/lib/screens/ConnectWallet.svelte @@ -1,23 +1,26 @@ - - onboard.connectWallet()} fullWidth baseClass={["h-full"]}> - {#snippet name()} - Connect Wallet - {/snippet} - {#snippet awaiting()} - Waiting for wallet... - {/snippet} - -
+ + diff --git a/src/lib/screens/IssueIntent.svelte b/src/lib/screens/IssueIntent.svelte index d20598f..1eee3da 100644 --- a/src/lib/screens/IssueIntent.svelte +++ b/src/lib/screens/IssueIntent.svelte @@ -181,6 +181,7 @@
-
+
Verifier {#if sameChain} @@ -264,8 +265,7 @@ {/if}
-
-
+
Exclusive +
diff --git a/src/lib/state.svelte.ts b/src/lib/state.svelte.ts index 37048e6..8df7dca 100644 --- a/src/lib/state.svelte.ts +++ b/src/lib/state.svelte.ts @@ -252,6 +252,7 @@ class Store { 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:"); diff --git a/src/lib/utils/orderLib.ts b/src/lib/utils/orderLib.ts index 90f0175..8fe8143 100644 --- a/src/lib/utils/orderLib.ts +++ b/src/lib/utils/orderLib.ts @@ -1,6 +1,6 @@ import { encodeAbiParameters, encodePacked, keccak256, parseAbiParameters } from "viem"; import type { MandateOutput, MultichainOrder, StandardOrder } from "../../types"; -import { type chain, chainMap, POLYMER_ORACLE, WORMHOLE_ORACLE } from "$lib/config"; +import { type chain, chainMap, POLYMER_ORACLE, WORMHOLE_ORACLE } from "../config"; export function getOutputHash(output: MandateOutput) { return keccak256( diff --git a/src/lib/utils/web3-onboard.ts b/src/lib/utils/web3-onboard.ts index 6ccd4ad..5ca6309 100644 --- a/src/lib/utils/web3-onboard.ts +++ b/src/lib/utils/web3-onboard.ts @@ -4,18 +4,26 @@ import injectedWalletsModule from "@web3-onboard/injected-wallets"; import zealWalletModule from "@web3-onboard/zeal"; import coinbaseWalletModule from "@web3-onboard/coinbase"; import walletConnectModule from "@web3-onboard/walletconnect"; -import { PUBLIC_WALLET_CONNECT_PROJECT_ID } from "$env/static/public"; +import { env } from "$env/dynamic/public"; import { chainMap } from "../config"; const injected = injectedWalletsModule(); const zealWalletSdk = zealWalletModule(); const coinbaseWalletSdk = coinbaseWalletModule(); -const walletConnect = walletConnectModule({ - projectId: PUBLIC_WALLET_CONNECT_PROJECT_ID, - dappUrl: "lintent.org" -}); +const walletConnectProjectId = env.PUBLIC_WALLET_CONNECT_PROJECT_ID; +const walletConnect = walletConnectProjectId + ? walletConnectModule({ + projectId: walletConnectProjectId, + dappUrl: "lintent.org" + }) + : undefined; -const wallets = [injected, walletConnect, zealWalletSdk, coinbaseWalletSdk]; +const wallets = [ + injected, + zealWalletSdk, + coinbaseWalletSdk, + ...(walletConnect ? [walletConnect] : []) +]; const getChains = () => { return Object.values(chainMap).map((v) => {