Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 16 additions & 0 deletions src/lib/components/GetQuote.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
8 changes: 6 additions & 2 deletions src/lib/components/ui/ScreenFrame.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@
</script>

<div class={["h-[29rem] w-[25rem] flex-shrink-0 snap-center snap-always p-4", contentClass]}>
<h1 class="mb-1 w-full text-center text-2xl font-medium text-gray-900">{title}</h1>
<p class="mb-2 text-center text-xs leading-relaxed text-gray-500">{description}</p>
{#if title}
<h1 class="mb-1 w-full text-center text-2xl font-medium text-gray-900">{title}</h1>
{/if}
{#if description}
<p class="mb-2 text-center text-xs leading-relaxed text-gray-500">{description}</p>
{/if}
<div class={bodyClass}>
{@render children?.()}
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/lib/libraries/intentList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
28 changes: 26 additions & 2 deletions src/lib/libraries/orderServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type GetQuoteOptions = {
amount: bigint;
}[];
minValidUntil?: number;
exclusiveFor?: `0x${string}`;
};

type GetQuoteResponse = {
Expand Down Expand Up @@ -197,11 +198,33 @@ export class OrderServer {
* @returns The response data containing the quotes
*/
async getQuotes(options: GetQuoteOptions): Promise<GetQuoteResponse> {
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",
Expand All @@ -225,6 +248,7 @@ export class OrderServer {
},
supportedTypes: ["oif-escrow-v0"]
};
if (exclusiveFor) rq.metadata = { exclusiveFor };

try {
return await this.postWithRetry<GetQuoteResponse>("/quote/request", rq, {
Expand Down
35 changes: 19 additions & 16 deletions src/lib/screens/ConnectWallet.svelte
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
<script lang="ts">
import AwaitButton from "$lib/components/AwaitButton.svelte";
import ScreenFrame from "$lib/components/ui/ScreenFrame.svelte";

let { onboard }: { onboard: any } = $props();
let connecting = $state(false);

const connectWallet = async () => {
try {
connecting = true;
await onboard.connectWallet();
} finally {
connecting = false;
}
};
</script>

<ScreenFrame
title="Connect Wallet"
description="Connect your wallet to continue with intent issuance and filling."
contentClass="px-10"
bodyClass="mb-14 flex h-[22rem] flex-col items-center justify-center align-middle"
>
<AwaitButton buttonFunction={() => onboard.connectWallet()} fullWidth baseClass={["h-full"]}>
{#snippet name()}
Connect Wallet
{/snippet}
{#snippet awaiting()}
Waiting for wallet...
{/snippet}
</AwaitButton>
<div></div>
<ScreenFrame title="" description="" contentClass="px-0" bodyClass="h-full">
<button
type="button"
class="h-full w-full cursor-pointer text-base font-semibold text-gray-700 hover:text-sky-700 disabled:cursor-not-allowed disabled:text-gray-400"
disabled={connecting}
onclick={connectWallet}
>
{connecting ? "Waiting for wallet..." : "Connect Wallet"}
</button>
</ScreenFrame>
16 changes: 13 additions & 3 deletions src/lib/screens/IssueIntent.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
<div class="w-20">
<GetQuote
bind:exclusiveFor={store.exclusiveFor}
useExclusiveForQuoteRequest={store.useExclusiveForQuoteRequest}
mainnet={store.mainnet}
inputTokens={store.inputTokens}
bind:outputTokens={store.outputTokens}
Expand Down Expand Up @@ -250,7 +251,7 @@
</SectionCard>

<SectionCard compact>
<div class="flex items-center gap-2">
<div class="flex flex-col gap-2">
<div class="flex items-center gap-1">
<span class="text-[11px] font-semibold text-gray-500">Verifier</span>
{#if sameChain}
Expand All @@ -264,8 +265,7 @@
</FormControl>
{/if}
</div>
<div class="h-5 w-px bg-gray-200"></div>
<div class="flex min-w-0 flex-1 items-center gap-1">
<div class="flex min-w-0 items-center gap-1">
<span class="text-[11px] font-semibold whitespace-nowrap text-gray-500">Exclusive</span>
<FormControl
type="text"
Expand All @@ -274,6 +274,16 @@
placeholder="0x... (optional)"
bind:value={store.exclusiveFor}
/>
<label
class="flex items-center gap-1 text-[11px] font-semibold whitespace-nowrap text-gray-500"
>
<input
type="checkbox"
class="h-3.5 w-3.5 rounded border-gray-300 text-sky-600 focus:ring-sky-300"
bind:checked={store.useExclusiveForQuoteRequest}
/>
Lock Exclusive
</label>
</div>
</div>
</SectionCard>
Expand Down
1 change: 1 addition & 0 deletions src/lib/state.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ class Store {
allocatorId = $state<availableAllocators>(ALWAYS_OK_ALLOCATOR);
verifier = $state<Verifier>("polymer");
exclusiveFor: string = $state("");
useExclusiveForQuoteRequest = $state(false);

invalidateWalletReadCache(scope: "all" | "balance" | "allowance" | "compact" = "all") {
if (scope === "all" || scope === "balance") invalidateRpcPrefix("balance:");
Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/orderLib.ts
Original file line number Diff line number Diff line change
@@ -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(
Expand Down
20 changes: 14 additions & 6 deletions src/lib/utils/web3-onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down