diff --git a/src/features/gift/actors/giftMakerRootMachine.ts b/src/features/gift/actors/giftMakerRootMachine.ts index 03538476..2a18cb27 100644 --- a/src/features/gift/actors/giftMakerRootMachine.ts +++ b/src/features/gift/actors/giftMakerRootMachine.ts @@ -1,4 +1,4 @@ -import { errors } from "@defuse-protocol/internal-utils" +import { errors, solverRelay } from "@defuse-protocol/internal-utils" import { type ActorRefFrom, type DoneActorEvent, @@ -12,7 +12,6 @@ import { } from "xstate" import type { SignerCredentials } from "../../../core/formatters" import { logger } from "../../../logger" -import { waitForIntentSettlement } from "../../../sdk/solverRelay/waitForIntentSettlement" import { emitEvent } from "../../../services/emitter" import type { BaseTokenInfo, UnifiedTokenInfo } from "../../../types/base" import type { @@ -130,7 +129,10 @@ export const giftMakerRootMachine = setup({ }: { input: { intentHashes: string[] }; signal: AbortSignal }) => { const intentHash = input.intentHashes[0] assert(intentHash, "intentHash is not defined") - return waitForIntentSettlement(signal, intentHash) + return solverRelay.waitForIntentSettlement({ + signal, + intentHash, + }) } ), savingGift: fromPromise( diff --git a/src/features/gift/actors/shared/giftClaimActor.ts b/src/features/gift/actors/shared/giftClaimActor.ts index 91712a24..328f6374 100644 --- a/src/features/gift/actors/shared/giftClaimActor.ts +++ b/src/features/gift/actors/shared/giftClaimActor.ts @@ -7,7 +7,6 @@ import { type PublishIntentsErr, convertPublishIntentsToLegacyFormat, } from "../../../../sdk/solverRelay/publishIntents" -import { waitForIntentSettlement } from "../../../../sdk/solverRelay/waitForIntentSettlement" import { assert } from "../../../../utils/assert" import { signGiftTakerMessage } from "../../utils/signGiftTakerMessage" import type { GiftInfo } from "./getGiftInfo" @@ -149,14 +148,22 @@ export const giftClaimActor = setup({ > => { const intentHash = input.intentHashes[0] assert(intentHash, "intentHash is not defined") - const result = await waitForIntentSettlement(signal, intentHash) - if (result.status === "NOT_FOUND_OR_NOT_VALID") { - return { - tag: "err" as const, - value: { reason: result.status }, + try { + await solverRelay.waitForIntentSettlement({ + signal, + intentHash, + }) + return { tag: "ok" as const } + } catch (err) { + if (err instanceof solverRelay.IntentSettlementError) { + return { + tag: "err" as const, + value: { reason: "NOT_FOUND_OR_NOT_VALID" }, + } } + // Optionally handle/log other error types here + throw err } - return { tag: "ok" as const } } ), }, diff --git a/src/features/gift/components/GiftTakerSuccessScreen.tsx b/src/features/gift/components/GiftTakerSuccessScreen.tsx index aad96248..4e1285a3 100644 --- a/src/features/gift/components/GiftTakerSuccessScreen.tsx +++ b/src/features/gift/components/GiftTakerSuccessScreen.tsx @@ -1,3 +1,4 @@ +import { solverRelay } from "@defuse-protocol/internal-utils" import { Button } from "@radix-ui/themes" import { useQuery } from "@tanstack/react-query" import { @@ -5,7 +6,6 @@ import { getUnderlyingBaseTokenInfos, } from "src/utils/tokenUtils" import { CopyButton } from "../../../components/IntentCard/CopyButton" -import { waitForIntentSettlement } from "../../../sdk/solverRelay/waitForIntentSettlement" import type { RenderHostAppLink } from "../../../types/hostAppLink" import { assert } from "../../../utils/assert" import type { GiftInfo } from "../actors/shared/getGiftInfo" @@ -38,7 +38,7 @@ export function GiftTakerSuccessScreen({ queryFn: async ({ signal }) => { const intentHash = intentHashes[0] assert(intentHash != null) - return waitForIntentSettlement(signal, intentHash) + return solverRelay.waitForIntentSettlement({ signal, intentHash }) }, }) diff --git a/src/features/machines/intentStatusMachine.ts b/src/features/machines/intentStatusMachine.ts index 1781b725..7f2677f0 100644 --- a/src/features/machines/intentStatusMachine.ts +++ b/src/features/machines/intentStatusMachine.ts @@ -1,4 +1,5 @@ import type { BridgeSDK } from "@defuse-protocol/bridge-sdk" +import { solverRelay } from "@defuse-protocol/internal-utils" import { type ActorRef, type Snapshot, @@ -11,10 +12,6 @@ import { import { auroraEngineContractId } from "../../constants/aurora" import { bridgeSDK } from "../../constants/bridgeSdk" import { logger } from "../../logger" -import { - type IntentSettlementResult, - waitForIntentSettlement, -} from "../../sdk/solverRelay/waitForIntentSettlement" import type { BaseTokenInfo, SupportedBridge, @@ -61,8 +58,10 @@ export const intentStatusMachine = setup({ logger.error(params.error) }, setSettlementResult: assign({ - txHash: (_, settlementResult: IntentSettlementResult) => - settlementResult.txHash, + txHash: ( + _, + settlementResult: solverRelay.WaitForIntentSettlementReturnType + ) => settlementResult.txHash, }), setBridgeTransactionResult: assign({ bridgeTransactionResult: ( @@ -79,8 +78,11 @@ export const intentStatusMachine = setup({ }: { input: { intentHash: string } signal: AbortSignal - }): Promise => - waitForIntentSettlement(signal, input.intentHash) + }): Promise => + solverRelay.waitForIntentSettlement({ + signal, + intentHash: input.intentHash, + }) ), waitForBridgeActor: fromPromise( async ({ @@ -116,8 +118,10 @@ export const intentStatusMachine = setup({ ), }, guards: { - isSettled: (_, settlementResult: IntentSettlementResult) => - settlementResult.status === "SETTLED", + isSettled: ( + _, + settlementResult: solverRelay.WaitForIntentSettlementReturnType + ) => !!settlementResult.txHash, isWithdraw: ({ context }) => { return context.intentDescription.type === "withdraw" }, diff --git a/src/features/otcDesk/components/OtcTakerSuccessScreen.tsx b/src/features/otcDesk/components/OtcTakerSuccessScreen.tsx index b0b731c0..04d652f7 100644 --- a/src/features/otcDesk/components/OtcTakerSuccessScreen.tsx +++ b/src/features/otcDesk/components/OtcTakerSuccessScreen.tsx @@ -1,8 +1,8 @@ +import { solverRelay } from "@defuse-protocol/internal-utils" import { Check as CheckIcon } from "@phosphor-icons/react" import { Button } from "@radix-ui/themes" import { useQuery } from "@tanstack/react-query" import { CopyButton } from "src/components/IntentCard/CopyButton" -import { waitForIntentSettlement } from "../../../sdk/solverRelay/waitForIntentSettlement" import type { BaseTokenInfo, UnifiedTokenInfo } from "../../../types/base" import type { RenderHostAppLink } from "../../../types/hostAppLink" import { assert } from "../../../utils/assert" @@ -53,7 +53,7 @@ export function OtcTakerSuccessScreen({ queryFn: async ({ signal }) => { const intentHash = intentHashes[0] assert(intentHash != null) - return waitForIntentSettlement(signal, intentHash) + return solverRelay.waitForIntentSettlement({ signal, intentHash }) }, }) diff --git a/src/features/otcDesk/utils/quoteUtils.ts b/src/features/otcDesk/utils/quoteUtils.ts index 5b30e396..8c5a40be 100644 --- a/src/features/otcDesk/utils/quoteUtils.ts +++ b/src/features/otcDesk/utils/quoteUtils.ts @@ -1,6 +1,6 @@ +import type { solverRelay } from "@defuse-protocol/internal-utils" import { Err, Ok, type Result } from "@thames/monads" import { settings } from "../../../constants/settings" -import type { FailedQuote } from "../../../sdk/solverRelay/solverRelayHttpClient/types" import { quoteWithLog } from "../../../sdk/solverRelay/utils/quoteWithLog" import { type AggregatedQuote, @@ -52,8 +52,8 @@ function handleQuote( return Err({ reason: "NO_QUOTES" }) } - const failedQuotes: FailedQuote[] = [] - const validQuotes = [] + const failedQuotes: solverRelay.FailedQuote[] = [] + const validQuotes: solverRelay.Quote[] = [] for (const q of quotes) { if (isFailedQuote(q)) { failedQuotes.push(q) diff --git a/src/features/tokenMigration/machines/tokenMigrationMachine.ts b/src/features/tokenMigration/machines/tokenMigrationMachine.ts index cfefa7f5..7c0cd9d7 100644 --- a/src/features/tokenMigration/machines/tokenMigrationMachine.ts +++ b/src/features/tokenMigration/machines/tokenMigrationMachine.ts @@ -5,10 +5,6 @@ import { nearClient } from "../../../constants/nearClient" import type { SignerCredentials } from "../../../core/formatters" import { logger } from "../../../logger" import { convertPublishIntentToLegacyFormat } from "../../../sdk/solverRelay/utils/parseFailedPublishError" -import { - type IntentSettlementResult, - waitForIntentSettlement, -} from "../../../sdk/solverRelay/waitForIntentSettlement" import { getDepositedBalances } from "../../../services/defuseBalanceService" import type { IntentsUserId } from "../../../types/intentsUserId" import type { WalletSignatureResult } from "../../../types/walletMessage" @@ -35,7 +31,7 @@ export const tokenMigrationMachine = setup({ signature: null | WalletSignatureResult intentHash: null | string error: null | string - intentStatus: null | IntentSettlementResult + intentStatus: null | solverRelay.WaitForIntentSettlementReturnType }, }, @@ -68,7 +64,13 @@ export const tokenMigrationMachine = setup({ input, signal, }: { input: { intentHash: string }; signal: AbortSignal }) => - waitForIntentSettlement(signal, input.intentHash) + solverRelay + .waitForIntentSettlement({ signal, intentHash: input.intentHash }) + .then((result) => ({ + ...result, + status: + result.txHash != null ? "SETTLED" : "NOT_FOUND_OR_NOT_VALID", + })) ), }, diff --git a/src/sdk/aggregatedQuote/aggregateQuotes.test.ts b/src/sdk/aggregatedQuote/aggregateQuotes.test.ts index cd69dab9..54059c5a 100644 --- a/src/sdk/aggregatedQuote/aggregateQuotes.test.ts +++ b/src/sdk/aggregatedQuote/aggregateQuotes.test.ts @@ -1,6 +1,6 @@ +import type { solverRelay } from "@defuse-protocol/internal-utils" import { describe, expect, it } from "vitest" import { QuoteError } from "../solverRelay/errors/quote" -import type { Quote } from "../solverRelay/solverRelayHttpClient/types" import { aggregateQuotes } from "./aggregateQuotes" import { AggregatedQuoteError } from "./errors/aggregatedQuoteError" @@ -12,7 +12,7 @@ describe("aggregateQuotes()", () => { it("aggregates quotes correctly", async () => { const quotes = await Promise.allSettled([ - Promise.resolve({ + Promise.resolve({ quote_hash: "q1", defuse_asset_identifier_in: "token1", defuse_asset_identifier_out: "tokenOut", @@ -20,7 +20,7 @@ describe("aggregateQuotes()", () => { amount_out: "2000000", // 2.0 with 6 decimals expiration_time: "2024-01-15T12:05:00.000Z", }), - Promise.resolve({ + Promise.resolve({ quote_hash: "q2", defuse_asset_identifier_in: "token2", defuse_asset_identifier_out: "tokenOut", @@ -52,7 +52,7 @@ describe("aggregateQuotes()", () => { it("continues with valid quotes even when some quotes have failed", async () => { const quotes = await Promise.allSettled([ - Promise.reject( + Promise.reject( new QuoteError({ quote: { type: "INSUFFICIENT_AMOUNT", @@ -61,7 +61,7 @@ describe("aggregateQuotes()", () => { quoteParams: defaultQuoteParams, }) ), - Promise.resolve({ + Promise.resolve({ quote_hash: "q1", defuse_asset_identifier_in: "token1", defuse_asset_identifier_out: "token2", @@ -100,7 +100,7 @@ describe("aggregateQuotes()", () => { it("throws error when all quotes have failed", async () => { const quotes = await Promise.allSettled([ - Promise.reject( + Promise.reject( new QuoteError({ quote: { type: "INSUFFICIENT_AMOUNT" as const, @@ -109,7 +109,7 @@ describe("aggregateQuotes()", () => { quoteParams: defaultQuoteParams, }) ), - Promise.reject( + Promise.reject( new QuoteError({ quote: null, quoteParams: defaultQuoteParams, diff --git a/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.test.ts b/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.test.ts index 9fc53263..f18a70d8 100644 --- a/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.test.ts +++ b/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.test.ts @@ -1,12 +1,12 @@ +import { solverRelay } from "@defuse-protocol/internal-utils" import { afterEach, describe, expect, it, vi } from "vitest" import type { BaseTokenInfo } from "../../types/base" import { adjustDecimals } from "../../utils/tokenUtils" import { QuoteError } from "../solverRelay/errors/quote" -import * as relayClient from "../solverRelay/solverRelayHttpClient" import { AggregatedQuoteError } from "./errors/aggregatedQuoteError" import { getAggregatedQuoteExactIn } from "./getAggregatedQuoteExactIn" -vi.spyOn(relayClient, "quote") +vi.spyOn(solverRelay, "quote") const tokenInfo: BaseTokenInfo = { defuseAssetId: "", @@ -53,7 +53,7 @@ describe("getAggregatedQuoteExactIn()", () => { waitMs: 0, } - vi.mocked(relayClient.quote).mockImplementationOnce(async () => [ + vi.mocked(solverRelay.quote).mockImplementationOnce(async () => [ { quote_hash: "q1", defuse_asset_identifier_in: "token1", @@ -76,8 +76,8 @@ describe("getAggregatedQuoteExactIn()", () => { wait_ms: 0, } - expect(relayClient.quote).toHaveBeenCalledTimes(1) - expect(relayClient.quote).toHaveBeenCalledWith( + expect(solverRelay.quote).toHaveBeenCalledTimes(1) + expect(solverRelay.quote).toHaveBeenCalledWith( quoteParams, expect.any(Object) ) @@ -107,7 +107,7 @@ describe("getAggregatedQuoteExactIn()", () => { waitMs: 0, } - vi.mocked(relayClient.quote) + vi.mocked(solverRelay.quote) .mockImplementationOnce(async () => [ { quote_hash: "q1", @@ -150,12 +150,12 @@ describe("getAggregatedQuoteExactIn()", () => { }, ] - expect(relayClient.quote).toHaveBeenCalledTimes(2) - expect(relayClient.quote).toHaveBeenCalledWith( + expect(solverRelay.quote).toHaveBeenCalledTimes(2) + expect(solverRelay.quote).toHaveBeenCalledWith( quoteParams[0], expect.any(Object) ) - expect(relayClient.quote).toHaveBeenCalledWith( + expect(solverRelay.quote).toHaveBeenCalledWith( quoteParams[1], expect.any(Object) ) @@ -183,7 +183,7 @@ describe("getAggregatedQuoteExactIn()", () => { waitMs: 0, } - vi.mocked(relayClient.quote).mockImplementationOnce(async () => [ + vi.mocked(solverRelay.quote).mockImplementationOnce(async () => [ { quote_hash: "q1", defuse_asset_identifier_in: "token1", @@ -244,7 +244,7 @@ describe("getAggregatedQuoteExactIn()", () => { waitMs: 0, } - vi.mocked(relayClient.quote) + vi.mocked(solverRelay.quote) .mockImplementationOnce(async () => null) .mockImplementationOnce(async () => []) @@ -285,7 +285,7 @@ describe("getAggregatedQuoteExactIn()", () => { }, ] - vi.mocked(relayClient.quote) + vi.mocked(solverRelay.quote) .mockImplementationOnce(async () => [ { quote_hash: "q1", @@ -331,7 +331,7 @@ describe("getAggregatedQuoteExactIn()", () => { waitMs: 0, } - vi.mocked(relayClient.quote).mockImplementationOnce(async () => [ + vi.mocked(solverRelay.quote).mockImplementationOnce(async () => [ { quote_hash: "q1", defuse_asset_identifier_in: "token1", @@ -346,7 +346,7 @@ describe("getAggregatedQuoteExactIn()", () => { aggregatedQuoteParams: input, }) - expect(relayClient.quote).toHaveBeenCalledTimes(1) + expect(solverRelay.quote).toHaveBeenCalledTimes(1) expect(result).toEqual({ expirationTime: expect.any(String), quoteHashes: ["q1"], diff --git a/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.ts b/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.ts index c21e3b64..ebd00659 100644 --- a/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.ts +++ b/src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.ts @@ -1,3 +1,4 @@ +import type { poaBridge } from "@defuse-protocol/internal-utils" import { settings } from "../../constants/settings" import type { AssertionError } from "../../errors/assert" import type { BaseTokenInfo, TokenValue } from "../../types/base" @@ -12,7 +13,6 @@ import { type GetQuoteReturnType, getQuote, } from "../solverRelay/getQuote" -import type { JSONRPCErrorType } from "../solverRelay/solverRelayHttpClient/types" import type { AggregatedQuote } from "../solverRelay/types/quote" import { aggregateQuotes } from "./aggregateQuotes" import { calculateSplitAmounts } from "./calculateSplitAmounts" @@ -31,7 +31,7 @@ export interface GetAggregatedExactInQuoteParams { export type GetAggregatedQuoteExactInReturnType = AggregatedQuote export type GetAggregatedQuoteExactInErrorType = - | JSONRPCErrorType + | poaBridge.httpClient.JSONRPCErrorType | AggregatedQuoteError | AmountMismatchError | AssertionError diff --git a/src/sdk/solverRelay/errors/quote.ts b/src/sdk/solverRelay/errors/quote.ts index 63b958af..bd146c8d 100644 --- a/src/sdk/solverRelay/errors/quote.ts +++ b/src/sdk/solverRelay/errors/quote.ts @@ -1,18 +1,17 @@ +import type { solverRelay } from "@defuse-protocol/internal-utils" import { BaseError } from "../../../errors/base" import { serialize } from "../../../utils/serialize" -import type { quote as quote_ } from "../solverRelayHttpClient" -import type { FailedQuote } from "../solverRelayHttpClient/types" export class QuoteError extends BaseError { - quote: FailedQuote | null - quoteParams: Parameters[0] + quote: solverRelay.FailedQuote | null + quoteParams: Parameters[0] constructor({ quote, quoteParams, }: { - quote: FailedQuote | null - quoteParams: Parameters[0] + quote: solverRelay.FailedQuote | null + quoteParams: Parameters[0] }) { super("Quote error", { details: quote == null ? "NO_QUOTE" : quote.type, diff --git a/src/sdk/solverRelay/getQuote.ts b/src/sdk/solverRelay/getQuote.ts index 107444c2..ab976a19 100644 --- a/src/sdk/solverRelay/getQuote.ts +++ b/src/sdk/solverRelay/getQuote.ts @@ -1,10 +1,5 @@ +import type { poaBridge, solverRelay } from "@defuse-protocol/internal-utils" import { QuoteError } from "./errors/quote" -import type { quote } from "./solverRelayHttpClient" -import type { - FailedQuote, - JSONRPCErrorType, - Quote, -} from "./solverRelayHttpClient/types" import { quoteWithLog } from "./utils/quoteWithLog" export type GetQuoteParams = { @@ -12,9 +7,11 @@ export type GetQuoteParams = { config: Parameters[1] } -export type GetQuoteReturnType = Quote +export type GetQuoteReturnType = solverRelay.Quote -export type GetQuoteErrorType = QuoteError | JSONRPCErrorType +export type GetQuoteErrorType = + | QuoteError + | poaBridge.httpClient.JSONRPCErrorType export async function getQuote( params: GetQuoteParams @@ -24,7 +21,7 @@ export async function getQuote( } function handleQuoteResult( - result: Awaited>, + result: Awaited>, quoteParams: GetQuoteParams["quoteParams"] ) { if (result == null) { @@ -34,7 +31,7 @@ function handleQuoteResult( }) } - const failedQuotes: FailedQuote[] = [] + const failedQuotes: solverRelay.FailedQuote[] = [] const validQuotes = [] for (const q of result) { if (isValidQuote(q)) { @@ -66,9 +63,9 @@ function handleQuoteResult( } function sortQuotes( - quotes: Quote[], + quotes: solverRelay.Quote[], quoteKind: "exact_in" | "exact_out" -): Quote[] { +): solverRelay.Quote[] { return quotes.slice().sort((a, b) => { if (quoteKind === "exact_in") { // For exact_in, sort by `amount_out` in descending order @@ -84,6 +81,8 @@ function sortQuotes( }) } -function isValidQuote(quote: Quote | FailedQuote): quote is Quote { +function isValidQuote( + quote: solverRelay.Quote | solverRelay.FailedQuote +): quote is solverRelay.Quote { return !("type" in quote) } diff --git a/src/sdk/solverRelay/solverRelayHttpClient/apis.ts b/src/sdk/solverRelay/solverRelayHttpClient/apis.ts deleted file mode 100644 index 34f574ea..00000000 --- a/src/sdk/solverRelay/solverRelayHttpClient/apis.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { jsonRPCRequest } from "./runtime" -import type * as types from "./types" - -export async function quote( - params: types.QuoteRequest["params"][0], - config: types.RequestConfig = {} -): Promise { - const result = await jsonRPCRequest( - "quote", - params, - config - ) - // biome-ignore lint/suspicious/noExplicitAny: - return result as any -} - -export async function getStatus( - params: types.GetStatusRequest["params"][0], - config: types.RequestConfig = {} -): Promise { - const result = await jsonRPCRequest( - "get_status", - params, - config - ) - // biome-ignore lint/suspicious/noExplicitAny: - return result as any -} diff --git a/src/sdk/solverRelay/solverRelayHttpClient/index.ts b/src/sdk/solverRelay/solverRelayHttpClient/index.ts deleted file mode 100644 index acd21856..00000000 --- a/src/sdk/solverRelay/solverRelayHttpClient/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type * as types from "./types" -export * from "./apis" diff --git a/src/sdk/solverRelay/solverRelayHttpClient/runtime.ts b/src/sdk/solverRelay/solverRelayHttpClient/runtime.ts deleted file mode 100644 index fed86c6e..00000000 --- a/src/sdk/solverRelay/solverRelayHttpClient/runtime.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { retry } from "@lifeomic/attempt" -import * as v from "valibot" -import { config as globalConfig } from "../../../config" -import { handleRPCResponse } from "../../../utils/handleRPCResponse" -import { request } from "../../../utils/request" -import { requestShouldRetry } from "../../../utils/requestShouldRetry" -import type * as types from "./types" - -const rpcResponseSchema = v.union([ - // success - v.object({ - jsonrpc: v.literal("2.0"), - id: v.string(), - result: v.unknown(), - }), - // error - v.object({ - jsonrpc: v.literal("2.0"), - id: v.string(), - error: v.pipe( - v.object({ - code: v.number(), - message: v.string(), - }), - v.transform((v) => { - return { - code: v.code, - data: null, - message: v.message, - } - }) - ), - }), -]) - -export async function jsonRPCRequest< - T extends types.JSONRPCRequest, ->( - method: T["method"], - params: T["params"][0], - config?: types.RequestConfig | undefined -) { - const url = `${globalConfig.env.solverRelayBaseURL}/rpc` - - const body = { - id: config?.requestId ?? "dontcare", - jsonrpc: "2.0", - method, - params: params !== undefined ? [params] : undefined, - } - - const response = await retry( - () => { - return request({ - url, - body, - ...config, - fetchOptions: { - ...config?.fetchOptions, - method: "POST", - }, - }) - }, - { - delay: 200, - maxAttempts: 3, - handleError: (err, context) => { - if (!requestShouldRetry(err)) { - context.abort - } - }, - } - ) - - return handleRPCResponse(response, body, rpcResponseSchema) -} diff --git a/src/sdk/solverRelay/solverRelayHttpClient/types.ts b/src/sdk/solverRelay/solverRelayHttpClient/types.ts deleted file mode 100644 index 1a862b37..00000000 --- a/src/sdk/solverRelay/solverRelayHttpClient/types.ts +++ /dev/null @@ -1,124 +0,0 @@ -import type { RpcRequestError } from "../../../errors/request" -import type { MultiPayload } from "../../../types/defuse-contracts-types" -import type { RequestErrorType } from "../../../utils/request" - -export type RequestConfig = { - requestId?: string | undefined - timeout?: number | undefined - fetchOptions?: Omit | undefined -} - -export type JSONRPCRequest = { - id: string - jsonrpc: "2.0" - method: Method - params: Params[] -} - -export type JSONRPCResponse = { - id: string - jsonrpc: "2.0" - result: Result -} - -export type JSONRPCErrorType = RequestErrorType | RpcRequestError - -export type QuoteRequest = JSONRPCRequest< - "quote", - { - defuse_asset_identifier_in: string - defuse_asset_identifier_out: string - exact_amount_in?: string - exact_amount_out?: string - min_deadline_ms?: number - wait_ms?: number - } -> - -export type Params> = T["params"][0] - -export type FailedQuote = { - type: "INSUFFICIENT_AMOUNT" - min_amount: string -} - -export type Quote = { - quote_hash: string - defuse_asset_identifier_in: string - defuse_asset_identifier_out: string - amount_in: string - amount_out: string - // ISO-8601 date string - expiration_time: string -} -export type QuoteResponse = JSONRPCResponse> - -export type PublishIntentRequest = JSONRPCRequest< - "publish_intent", - { - quote_hashes: string[] - signed_data: MultiPayload - } -> - -export type PublishIntentResponse = JSONRPCResponse< - PublishIntentResponseSuccess | PublishIntentResponseFailure -> - -export type PublishIntentResponseSuccess = { - intent_hash: string - status: "OK" -} -export type PublishIntentResponseFailure = { - intent_hash: string - status: "FAILED" - reason: string | "expired" | "internal" -} - -export type PublishIntentsRequest = JSONRPCRequest< - "publish_intents", - { - quote_hashes: string[] - signed_datas: MultiPayload[] - } -> - -export type PublishIntentsResponse = JSONRPCResponse< - PublishIntentsResponseSuccess | PublishIntentsResponseFailure -> - -export type PublishIntentsResponseSuccess = { - intent_hashes: string[] - status: "OK" -} -export type PublishIntentsResponseFailure = { - intent_hashes: string[] - status: "FAILED" - reason: string | "expired" | "internal" -} - -export type GetStatusRequest = JSONRPCRequest< - "get_status", - { intent_hash: string } -> - -export type GetStatusResponse = JSONRPCResponse< - | { - status: "PENDING" - intent_hash: string - } - | { - status: "TX_BROADCASTED" - intent_hash: string - data: { hash: string } - } - | { - status: "SETTLED" - intent_hash: string - data: { hash: string } - } - | { - status: "NOT_FOUND_OR_NOT_VALID" - intent_hash: string - } -> diff --git a/src/sdk/solverRelay/utils/quoteWithLog.ts b/src/sdk/solverRelay/utils/quoteWithLog.ts index 4a89b4ff..cb133a1a 100644 --- a/src/sdk/solverRelay/utils/quoteWithLog.ts +++ b/src/sdk/solverRelay/utils/quoteWithLog.ts @@ -1,15 +1,15 @@ +import { solverRelay } from "@defuse-protocol/internal-utils" import { logger } from "../../../logger" -import { quote } from "../solverRelayHttpClient" export async function quoteWithLog( - params: Parameters[0], + params: Parameters[0], { logBalanceSufficient, ...config - }: { logBalanceSufficient: boolean } & Parameters[1] + }: { logBalanceSufficient: boolean } & Parameters[1] ) { const requestId = crypto.randomUUID() - const result = await quote(params, { ...config, requestId }) + const result = await solverRelay.quote(params, { ...config, requestId }) if (result == null) { logger.warn("quote: No liquidity available", { quoteParams: params }) diff --git a/src/sdk/solverRelay/waitForIntentSettlement.ts b/src/sdk/solverRelay/waitForIntentSettlement.ts deleted file mode 100644 index 7330a708..00000000 --- a/src/sdk/solverRelay/waitForIntentSettlement.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { retry } from "@lifeomic/attempt" -import { BaseError } from "../../errors/base" -import { HttpRequestError } from "../../errors/request" -import { wait } from "../../utils/wait" -import * as solverRelayClient from "./solverRelayHttpClient" -import type * as types from "./solverRelayHttpClient/types" - -export type IntentSettlementResult = Awaited< - ReturnType -> - -export async function waitForIntentSettlement( - signal: AbortSignal, - intentHash: string -) { - let attempts = 0 - const MAX_INVALID_ATTEMPTS = 3 // ~600 ms of waiting - - let lastSeenResult: types.GetStatusResponse["result"] | null = null - let txHash: string | null = null - - while (true) { - signal.throwIfAborted() - - const res = await retry( - () => - solverRelayClient.getStatus({ - intent_hash: intentHash, - }), - { - delay: 1000, - factor: 1.5, - maxAttempts: Number.MAX_SAFE_INTEGER, - jitter: true, - handleError: (err, context) => { - if ( - err instanceof BaseError && - err.walk((err) => err instanceof HttpRequestError) - ) { - return - } - - context.abort() - }, - } - ) - - const status = res.status - switch (status) { - case "PENDING": - // Do nothing, just wait - break - - case "TX_BROADCASTED": - txHash = res.data.hash - break - - case "SETTLED": - return { - status: "SETTLED" as const, - txHash: res.data.hash, - intentHash: res.intent_hash, - } - - case "NOT_FOUND_OR_NOT_VALID": { - if ( - // If previous status differs, we're sure new result is final - (lastSeenResult != null && lastSeenResult.status !== res.status) || - // If we've seen only NOT_VALID and keep getting it then we should abort - MAX_INVALID_ATTEMPTS <= ++attempts - ) { - return { - status: "NOT_FOUND_OR_NOT_VALID" as const, - txHash: txHash, - intentHash: res.intent_hash, - } - } - break - } - - default: - status satisfies never - } - - lastSeenResult = res - - // Wait a bit before polling again - await wait(200) - } -} diff --git a/src/services/quoteService.test.ts b/src/services/quoteService.test.ts index 9a744508..673527e1 100644 --- a/src/services/quoteService.test.ts +++ b/src/services/quoteService.test.ts @@ -1,10 +1,10 @@ +import { solverRelay } from "@defuse-protocol/internal-utils" import { afterEach, describe, expect, it, vi } from "vitest" -import * as relayClient from "../sdk/solverRelay/solverRelayHttpClient" import type { BaseTokenInfo } from "../types/base" import { adjustDecimals } from "../utils/tokenUtils" import { queryQuote } from "./quoteService" -vi.spyOn(relayClient, "quote") +vi.spyOn(solverRelay, "quote") const tokenInfo: BaseTokenInfo = { defuseAssetId: "", @@ -51,7 +51,7 @@ describe("queryQuote()", () => { waitMs: 0, } - vi.mocked(relayClient.quote).mockImplementationOnce(async () => [ + vi.mocked(solverRelay.quote).mockImplementationOnce(async () => [ { quote_hash: "q1", defuse_asset_identifier_in: "token1", @@ -64,8 +64,8 @@ describe("queryQuote()", () => { const result = await queryQuote(input) - expect(relayClient.quote).toHaveBeenCalledTimes(1) - expect(relayClient.quote).toHaveBeenCalledWith( + expect(solverRelay.quote).toHaveBeenCalledTimes(1) + expect(solverRelay.quote).toHaveBeenCalledWith( { defuse_asset_identifier_in: "token1", defuse_asset_identifier_out: "tokenOut", @@ -101,7 +101,7 @@ describe("queryQuote()", () => { waitMs: 0, } - vi.mocked(relayClient.quote) + vi.mocked(solverRelay.quote) .mockImplementationOnce(async () => [ { quote_hash: "q1", @@ -125,8 +125,8 @@ describe("queryQuote()", () => { const result = await queryQuote(input) - expect(relayClient.quote).toHaveBeenCalledTimes(2) - expect(relayClient.quote).toHaveBeenCalledWith( + expect(solverRelay.quote).toHaveBeenCalledTimes(2) + expect(solverRelay.quote).toHaveBeenCalledWith( { defuse_asset_identifier_in: "token1", defuse_asset_identifier_out: "tokenOut", @@ -136,7 +136,7 @@ describe("queryQuote()", () => { }, expect.any(Object) ) - expect(relayClient.quote).toHaveBeenCalledWith( + expect(solverRelay.quote).toHaveBeenCalledWith( { defuse_asset_identifier_in: "token2", defuse_asset_identifier_out: "tokenOut", @@ -170,7 +170,7 @@ describe("queryQuote()", () => { waitMs: 0, } - vi.mocked(relayClient.quote).mockImplementationOnce(async () => [ + vi.mocked(solverRelay.quote).mockImplementationOnce(async () => [ { quote_hash: "q1", defuse_asset_identifier_in: "token1", @@ -221,7 +221,7 @@ describe("queryQuote()", () => { waitMs: 0, } - vi.mocked(relayClient.quote) + vi.mocked(solverRelay.quote) .mockImplementationOnce(async () => null) .mockImplementationOnce(async () => []) @@ -252,7 +252,7 @@ describe("queryQuote()", () => { waitMs: 0, } - vi.mocked(relayClient.quote) + vi.mocked(solverRelay.quote) .mockImplementationOnce(async () => [ { quote_hash: "q1", @@ -287,7 +287,7 @@ describe("queryQuote()", () => { waitMs: 0, } - vi.mocked(relayClient.quote).mockImplementationOnce(async () => [ + vi.mocked(solverRelay.quote).mockImplementationOnce(async () => [ { quote_hash: "q1", defuse_asset_identifier_in: "token1", @@ -300,7 +300,7 @@ describe("queryQuote()", () => { const result = await queryQuote(input) - expect(relayClient.quote).toHaveBeenCalledTimes(1) + expect(solverRelay.quote).toHaveBeenCalledTimes(1) expect(result).toEqual({ tag: "ok", value: { diff --git a/src/services/quoteService.ts b/src/services/quoteService.ts index 724f7b49..5a5bfee8 100644 --- a/src/services/quoteService.ts +++ b/src/services/quoteService.ts @@ -1,17 +1,14 @@ +import type { solverRelay } from "@defuse-protocol/internal-utils" import { settings } from "../constants/settings" import { AggregatedQuoteError } from "../sdk/aggregatedQuote/errors/aggregatedQuoteError" import { AmountMismatchError } from "../sdk/aggregatedQuote/errors/amountMismatchError" import { getAggregatedQuoteExactIn } from "../sdk/aggregatedQuote/getAggregatedQuoteExactIn" -import type { - FailedQuote, - Quote, -} from "../sdk/solverRelay/solverRelayHttpClient/types" import { quoteWithLog } from "../sdk/solverRelay/utils/quoteWithLog" import type { BaseTokenInfo, TokenValue } from "../types/base" export function isFailedQuote( - quote: Quote | FailedQuote -): quote is FailedQuote { + quote: solverRelay.Quote | solverRelay.FailedQuote +): quote is solverRelay.FailedQuote { return "type" in quote } @@ -154,7 +151,7 @@ export async function queryQuoteExactOut( } } - const failedQuotes: FailedQuote[] = [] + const failedQuotes: solverRelay.FailedQuote[] = [] const validQuotes = [] for (const q of quotes) { if (isFailedQuote(q)) { diff --git a/src/utils/prepareBroadcastRequest.ts b/src/utils/prepareBroadcastRequest.ts index 3b590d77..6f483121 100644 --- a/src/utils/prepareBroadcastRequest.ts +++ b/src/utils/prepareBroadcastRequest.ts @@ -1,8 +1,5 @@ +import type { solverRelay } from "@defuse-protocol/internal-utils" import { base58, base64, hex } from "@scure/base" -import type { - Params, - PublishIntentRequest, -} from "../sdk/solverRelay/solverRelayHttpClient/types" import type { AuthMethod } from "../types/authHandle" import type { WalletSignatureResult } from "../types/walletMessage" import { assert } from "./assert" @@ -11,7 +8,7 @@ import { makeWebAuthnMultiPayload } from "./multiPayload/webauthn" export function prepareSwapSignedData( signature: WalletSignatureResult, userInfo: { userAddress: string; userChainType: AuthMethod } -): Params["signed_data"] { +): solverRelay.Params["signed_data"] { const signatureType = signature.type switch (signatureType) { case "NEP413": {