diff --git a/packages/sdk/src/helpers/getBridgeHistory.ts b/packages/sdk/src/helpers/getBridgeHistory.ts index 7d00bbf..7ffaed4 100644 --- a/packages/sdk/src/helpers/getBridgeHistory.ts +++ b/packages/sdk/src/helpers/getBridgeHistory.ts @@ -1,13 +1,16 @@ import { Environment } from "../enums"; +import type { RelayRequest } from "../relay"; +import { getRequests } from "../relay"; +import { RELAY_STATUSES_MAPPING } from "../relay/constants"; import { getTransfers } from "../sygma/api"; import type { Status, SygmaTransfer } from "../sygma/types"; import type { Address } from "../types"; interface History { originTx: string; - originName: string; + originChainId: number; destinationTx?: string; - destinationName: string; + destinationChainId: number; amount: string; tokenSymbol: string; status: Status; @@ -16,15 +19,33 @@ interface History { function handleSygmaResponseEntry(entry: SygmaTransfer): History { return { originTx: entry.deposit?.txHash || "0x0", - originName: entry.fromDomain.name, + originChainId: Number(entry.fromDomain.id), destinationTx: entry.execution?.txHash, - destinationName: entry.toDomain.name, + destinationChainId: Number(entry.toDomain.name), amount: entry.amount, tokenSymbol: entry.fee.tokenSymbol, status: entry.status, }; } +function handleRelayResponseEntry(entry: RelayRequest): History { + // * mapping statuses from relay to "sprinter" statuses + // * inTxs and outTxs contain information about the + // * transfer. e.g chain ID and amount of tokens + const status = RELAY_STATUSES_MAPPING.get(entry.status); + // ! throw error if data is not available + if (!status || entry.data.inTxs.length <= 0 || entry.data.outTxs.length <= 0) + throw new Error("Missing transaction information"); + return { + originTx: entry.data.inTxs[0].hash, + originChainId: entry.data.inTxs[0].chainId, + destinationChainId: entry.data.outTxs[0].chainId, + amount: entry.data.metadata.currencyIn.amountFormatted, + tokenSymbol: entry.data.currencyObject.symbol, + status, + }; +} + /** * Returns bridging history * for an address @@ -42,5 +63,11 @@ export async function getBridgeHistory( sygmaTransfers.map((transfer) => handleSygmaResponseEntry(transfer)), ); + transactions.push( + ...(await getRequests(address, environment).then((response) => + response.requests.map((request) => handleRelayResponseEntry(request)), + )), + ); + return transactions; } diff --git a/packages/sdk/src/relay/api.ts b/packages/sdk/src/relay/api.ts new file mode 100644 index 0000000..25673e6 --- /dev/null +++ b/packages/sdk/src/relay/api.ts @@ -0,0 +1,26 @@ +import type { Environment } from "../enums"; + +import { RELAY_API_ENDPOINTS } from "./constants"; +import type { RelayRequestsResponse } from "./types"; + +/** + * Returns list of transfers from + * Relay protocol + * + * https://docs.relay.link/references/api/get-requests?playground=open + * @param {Environment} environment + */ +export async function getRequests( + address: string, + environment: Environment, +): Promise { + const requestsPath = `/requests/v2`; + const url = new URL(RELAY_API_ENDPOINTS[environment], requestsPath); + url.searchParams.set("user", address); + + const response: RelayRequestsResponse = await fetch(url.toString()).then( + (response): Promise => response.json(), + ); + + return response; +} diff --git a/packages/sdk/src/relay/constants.ts b/packages/sdk/src/relay/constants.ts new file mode 100644 index 0000000..f99714b --- /dev/null +++ b/packages/sdk/src/relay/constants.ts @@ -0,0 +1,18 @@ +import { Environment } from "../enums"; +import { Status } from "../sygma"; + +import { RelayRequestStatus } from "./types"; + +export const RELAY_API_ENDPOINTS: Record = { + [Environment.MAINNET]: "https://api.relay.link", + [Environment.TESTNET]: "https://api.testnets.relay.link", +}; + +export const RELAY_STATUSES_MAPPING = new Map([ + [RelayRequestStatus.Refund, Status.failed], + [RelayRequestStatus.Delayed, Status.pending], + [RelayRequestStatus.Waiting, Status.pending], + [RelayRequestStatus.Failure, Status.failed], + [RelayRequestStatus.Pending, Status.pending], + [RelayRequestStatus.Success, Status.executed], +]); diff --git a/packages/sdk/src/relay/index.ts b/packages/sdk/src/relay/index.ts new file mode 100644 index 0000000..1d58e1a --- /dev/null +++ b/packages/sdk/src/relay/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./types"; diff --git a/packages/sdk/src/relay/types.ts b/packages/sdk/src/relay/types.ts new file mode 100644 index 0000000..5ebd468 --- /dev/null +++ b/packages/sdk/src/relay/types.ts @@ -0,0 +1,116 @@ +/** + * * All types extracted from official relay + * * documentation which can be found here + * * https://docs.relay.link/references/api/get-requests#parameter-user + */ + +enum FailureReason { + UNKNOWN = "UNKNOWN", + AMOUNT_TOO_LOW_TO_REFUND = "AMOUNT_TOO_LOW_TO_REFUND", + DEPOSIT_ADDRESS_MISMATCH = "DEPOSIT_ADDRESS_MISMATCH", + DEPOSIT_CHAIN_MISMATCH = "DEPOSIT_CHAIN_MISMATCH", + NA = "N/A", +} + +export enum RelayRequestStatus { + Refund = "refund", + Delayed = "delayed", + Waiting = "waiting", + Failure = "failure", + Pending = "pending", + Success = "success", +} + +interface Currency { + name: string; + symbol: string; + address: string; + chainId: number; + decimals: number; + metadata: { + isNative: boolean; + logoURI: string; + verified: boolean; + }; +} + +interface Fees { + fixed: string; + gas: string; + price: string; +} + +interface TransactionData { + fee: string; + // * relay documentation marks these as any + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: any; + // * relay documentation marks these as any + // eslint-disable-next-line @typescript-eslint/no-explicit-any + stateChanges: any; + hash: string; + block: number; + type: string; + chainId: number; + timestamp: number; +} + +export interface RelayRequest { + id: string; + status: RelayRequestStatus; + user: string; + recipient: string; + createdAt: string; + updatedAt: string; + + data: { + failReason: FailureReason; + fees: Fees; + feesUsd: Fees; + inTxs: Array; + currency: string; + currencyObject: Currency; + feeCurrency: string; + feeCurrencyObject: Currency; + appFees: Array<{ + amount: string; + recipient: string; + }>; + metadata: { + sender: string; + recipient: string; + currencyIn: { + currency: Currency; + amount: string; + amountFormatted: string; + amountUsd: string; + minimumAmount: string; + }; + currencyOut: { + currency: Currency; + amount: string; + amountFormatted: string; + amountUsd: string; + minimumAmount: string; + }; + rate: string; + }; + price: string; + usesExternalLiquidity: boolean; + timeEstimate: number; + outTxs: Array; + + refundCurrencyData: { + amount: string; + amountFormatted: string; + amountUsd: string; + currency: Currency; + minimumAmount: string; + }; + }; +} + +export interface RelayRequestsResponse { + continuation: string; + requests: Array; +}