@funkit/fun-relay 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @funkit/fun-relay
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 6cb808b: feat(relay): add exact input quote handling
8
+
9
+ ## 0.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - bff34b2: chore: fix files config
14
+
3
15
  ## 0.1.0
4
16
 
5
17
  In development
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { getRelayClient, initializeRelayClient, type InitializeRelayClientParams, } from './src/client';
2
+ export { FUN_RELAY_REFERRER, FUN_RELAY_REVENUE_WALLET, } from './src/constants';
2
3
  export { type ExecuteRelayQuoteParams, executeRelayQuote, getRelayExecutionInfo, } from './src/execution';
3
- export { type GetRelayQuoteParams, getRelayQuote } from './src/quote';
4
+ export { computeFunRelayFeeBps, parseRelayFees, } from './src/fees';
5
+ export { type GetRelayQuoteParams, getRelayQuote, type RelayQuote, } from './src/quote';
4
6
  export { getRelayExecutionRefundState, getRelayExecutionState, isRelayExecutionTerminalStatus, } from './src/utils';
5
7
  export { LogLevel, type RelayExecutionInfo, type RelayExecutionStatus, } from './src/types';
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,KAAK,2BAA2B,GACjC,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,KAAK,uBAAuB,EAC5B,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,qBAAqB,EACrB,cAAc,GACf,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,KAAK,mBAAmB,EACxB,aAAa,EACb,KAAK,UAAU,GAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAA"}
package/dist/index.js CHANGED
@@ -20,7 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ FUN_RELAY_REFERRER: () => FUN_RELAY_REFERRER,
24
+ FUN_RELAY_REVENUE_WALLET: () => FUN_RELAY_REVENUE_WALLET,
23
25
  LogLevel: () => import_relay_sdk3.LogLevel,
26
+ computeFunRelayFeeBps: () => computeFunRelayFeeBps,
24
27
  executeRelayQuote: () => executeRelayQuote,
25
28
  getRelayClient: () => getRelayClient,
26
29
  getRelayExecutionInfo: () => getRelayExecutionInfo,
@@ -28,7 +31,8 @@ __export(index_exports, {
28
31
  getRelayExecutionState: () => getRelayExecutionState,
29
32
  getRelayQuote: () => getRelayQuote,
30
33
  initializeRelayClient: () => initializeRelayClient,
31
- isRelayExecutionTerminalStatus: () => isRelayExecutionTerminalStatus
34
+ isRelayExecutionTerminalStatus: () => isRelayExecutionTerminalStatus,
35
+ parseRelayFees: () => parseRelayFees
32
36
  });
33
37
  module.exports = __toCommonJS(index_exports);
34
38
 
@@ -44,7 +48,7 @@ function initializeRelayClient({
44
48
  baseApiUrl: import_relay_sdk.MAINNET_RELAY_API,
45
49
  chains: chains.map(import_relay_sdk.convertViemChainToRelayChain),
46
50
  logger: (message) => {
47
- logger.log("[RelayClient]:", message);
51
+ logger.info("[RelayClient]:", message);
48
52
  }
49
53
  });
50
54
  }
@@ -56,14 +60,26 @@ function getRelayClient() {
56
60
  return client;
57
61
  }
58
62
 
63
+ // src/constants.ts
64
+ var FUNKIT_NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
65
+ var RELAY_NATIVE_TOKEN = "0x0000000000000000000000000000000000000000";
66
+ var FUN_RELAY_REVENUE_WALLET = "0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E";
67
+ var FUN_RELAY_REFERRER = "funxyz";
68
+ var RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3e3;
69
+ var RELAY_TERMINAL_STATUSES = [
70
+ "refund",
71
+ "failure",
72
+ "success"
73
+ ];
74
+
59
75
  // src/execution.ts
60
76
  var import_relay_sdk2 = require("@reservoir0x/relay-sdk");
61
77
  async function executeRelayQuote({
62
78
  logger,
63
79
  onConfirmed,
64
80
  onError,
81
+ onProgress,
65
82
  relayQuote,
66
- stepMessageSetter,
67
83
  walletClient
68
84
  }) {
69
85
  await getRelayClient().actions.execute({
@@ -80,7 +96,7 @@ async function executeRelayQuote({
80
96
  error
81
97
  }) => {
82
98
  const logPrefix = "onRelayProgress";
83
- logger.log(`${logPrefix}:params`, {
99
+ logger.info(`${logPrefix}:params`, {
84
100
  steps,
85
101
  currentStep,
86
102
  fees,
@@ -90,9 +106,9 @@ async function executeRelayQuote({
90
106
  details,
91
107
  error
92
108
  });
93
- stepMessageSetter(currentStep?.action ?? "");
109
+ onProgress?.(currentStep ?? null);
94
110
  if (error) {
95
- logger.log(`${logPrefix}:errorDetected`, error);
111
+ logger.info(`${logPrefix}:errorDetected`, error);
96
112
  await onError(error).catch((e) => {
97
113
  logger.error(`${logPrefix}:onErrorFailed`, e);
98
114
  });
@@ -101,7 +117,7 @@ async function executeRelayQuote({
101
117
  // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1748381169792379
102
118
  txHashes && txHashes.length > 0 && txHashes.length === steps.length
103
119
  ) {
104
- logger.log(`${logPrefix}:completed`, txHashes);
120
+ logger.info(`${logPrefix}:completed`, txHashes);
105
121
  await onConfirmed(txHashes[0].txHash).catch((e) => {
106
122
  logger.error(`${logPrefix}:onConfirmedFailed`, e);
107
123
  });
@@ -119,21 +135,6 @@ async function getRelayExecutionInfo(requestId) {
119
135
  return data;
120
136
  }
121
137
 
122
- // src/quote.ts
123
- var import_viem = require("viem");
124
-
125
- // src/constants.ts
126
- var FUNKIT_NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
127
- var RELAY_NATIVE_TOKEN = "0x0000000000000000000000000000000000000000";
128
- var FUN_RELAY_REVENUE_WALLET = "0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E";
129
- var FUN_RELAY_REFERRER = "funxyz";
130
- var RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3e3;
131
- var RELAY_TERMINAL_STATUSES = [
132
- "refund",
133
- "failure",
134
- "success"
135
- ];
136
-
137
138
  // src/fees.ts
138
139
  function computeFunRelayFeeBps({
139
140
  isSameToken
@@ -156,7 +157,7 @@ function parseRelayFees({
156
157
  const totalLpFeesUsd = funLpFeesUsd + relayLpFeesUsd;
157
158
  const totalLpFeesFromAmount = funLpFeesFromAmount + relayLpFeesFromAmount;
158
159
  const totalLpFeesFromAmountBaseUnit = funLpFeesFromAmountBaseUnit + relayLpFeesFromAmountBaseUnit;
159
- logger.log("parseRelayFees", {
160
+ logger.info("parseRelayFees", {
160
161
  relayGasFeesUsd,
161
162
  funLpFeesUsd,
162
163
  funLpFeesFromAmount,
@@ -177,6 +178,9 @@ function parseRelayFees({
177
178
  };
178
179
  }
179
180
 
181
+ // src/quote.ts
182
+ var import_viem = require("viem");
183
+
180
184
  // src/types.ts
181
185
  var import_relay_sdk3 = require("@reservoir0x/relay-sdk");
182
186
 
@@ -212,22 +216,22 @@ function isRelayExecutionTerminalStatus(info) {
212
216
 
213
217
  // src/quote.ts
214
218
  async function getRelayQuote({
215
- actionParams,
216
219
  logger,
217
- toChainId,
218
- toTokenAddress,
219
- toTokenAmount,
220
- toTokenDecimals,
221
- fromChainId,
222
- fromTokenAddress,
223
- recipientAddress,
224
- userAddress
220
+ ...params
225
221
  }) {
222
+ const {
223
+ actionParams,
224
+ fromChainId,
225
+ fromTokenAddress,
226
+ options,
227
+ recipientAddress,
228
+ toChainId,
229
+ toTokenAddress,
230
+ userAddress
231
+ } = params;
226
232
  try {
227
233
  const relayClient = getRelayClient();
228
- const toMultipler = 10 ** toTokenDecimals;
229
- const toAmountBaseUnitBI = BigInt(Math.floor(toTokenAmount * toMultipler));
230
- const toAmountBaseUnitBIString = toAmountBaseUnitBI.toString();
234
+ const tokenAmountBaseUnit = params.tradeType === "EXACT_INPUT" ? params.fromTokenAmountBaseUnit : params.toTokenAmountBaseUnit;
231
235
  const txs = actionParams?.map((action) => {
232
236
  const data = (0, import_viem.encodeFunctionData)({
233
237
  abi: action.contractAbi,
@@ -240,18 +244,9 @@ async function getRelayQuote({
240
244
  value: String(action.value ?? 0n)
241
245
  };
242
246
  });
243
- logger.log("getRelayQuoteParams", {
244
- actionParams,
245
- toChainId,
246
- toTokenAddress,
247
- toTokenAmount,
248
- toTokenDecimals,
249
- fromChainId,
250
- fromTokenAddress,
251
- recipientAddress,
252
- userAddress,
253
- relayClient,
254
- toAmountBaseUnitBI: toAmountBaseUnitBIString,
247
+ logger.info("getRelayQuoteParams", {
248
+ ...params,
249
+ tokenAmountBaseUnit,
255
250
  txs
256
251
  });
257
252
  const relayQuote = await relayClient.actions.getQuote({
@@ -259,9 +254,9 @@ async function getRelayQuote({
259
254
  toChainId: Number(toChainId),
260
255
  currency: convertFunToRelayTokenAddress(fromTokenAddress),
261
256
  toCurrency: convertFunToRelayTokenAddress(toTokenAddress),
262
- amount: toAmountBaseUnitBIString,
257
+ amount: tokenAmountBaseUnit.toString(),
263
258
  recipient: recipientAddress,
264
- tradeType: "EXACT_OUTPUT",
259
+ tradeType: params.tradeType,
265
260
  user: userAddress,
266
261
  ...txs && { txs },
267
262
  options: {
@@ -273,10 +268,11 @@ async function getRelayQuote({
273
268
  }).toString(),
274
269
  recipient: FUN_RELAY_REVENUE_WALLET
275
270
  }
276
- ]
271
+ ],
272
+ ...options
277
273
  }
278
274
  });
279
- logger.log("relayQuote", relayQuote);
275
+ logger.info("relayQuote", relayQuote);
280
276
  const estSubtotalUsd = Number(
281
277
  relayQuote.details?.currencyOut?.amountUsd || 0
282
278
  );
@@ -287,6 +283,9 @@ async function getRelayQuote({
287
283
  if (!relayRequestId) {
288
284
  throw new Error("Relay quote does not contain a requestId");
289
285
  }
286
+ if (!relayQuote.details?.currencyIn || !relayQuote.details?.currencyOut) {
287
+ throw new Error("Relay quote does not contain trade details");
288
+ }
290
289
  const {
291
290
  relayGasFeesUsd,
292
291
  totalLpFeesUsd,
@@ -298,29 +297,32 @@ async function getRelayQuote({
298
297
  const estSubtotalFromAmountBaseUnit = (BigInt(fromAmountBaseUnitString) - totalFeesFromAmountBaseUnit).toString();
299
298
  return {
300
299
  quoteId: relayRequestId,
301
- estTotalFromAmount: fromAmountString,
302
- estSubtotalFromAmount,
303
- estTotalFromAmountBaseUnit: fromAmountBaseUnitString,
304
- estSubtotalFromAmountBaseUnit,
300
+ estCheckoutTimeMs: (relayQuote.details.timeEstimate || 0) * 1e3 + RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,
305
301
  estFeesFromAmount: totalFeesFromAmount.toString(),
306
302
  estFeesFromAmountBaseUnit: totalFeesFromAmountBaseUnit.toString(),
307
- fromTokenAddress,
308
303
  estFeesUsd: totalFeesUsd,
304
+ estMarketMakerGasUsd: relayGasFeesUsd,
305
+ estSubtotalFromAmount,
306
+ estSubtotalFromAmountBaseUnit,
309
307
  estSubtotalUsd,
308
+ estTotalFromAmount: fromAmountString,
309
+ estTotalFromAmountBaseUnit: fromAmountBaseUnitString,
310
310
  estTotalUsd,
311
- estCheckoutTimeMs: (relayQuote.details?.timeEstimate || 0) * 1e3 + RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,
312
- estMarketMakerGasUsd: relayGasFeesUsd,
311
+ finalToAmountBaseUnit: relayQuote.details.currencyOut.amount ?? "0",
312
+ // TODO: Or do we want 'minimumAmount'?
313
+ fromTokenAddress,
313
314
  lpFeePercentage: 0,
314
315
  // TODO: ?
315
316
  lpFeeUsd: totalLpFeesUsd,
316
317
  metadata: {
318
+ fromAmountBaseUnit: params.tradeType === "EXACT_INPUT" ? tokenAmountBaseUnit.toString() : relayQuote.details.currencyIn.amount ?? "0",
317
319
  relayQuote,
318
- toAmountBaseUnit: toAmountBaseUnitBIString
320
+ toAmountBaseUnit: params.tradeType === "EXACT_INPUT" ? relayQuote.details.currencyOut.amount ?? "0" : tokenAmountBaseUnit.toString()
319
321
  }
320
322
  };
321
323
  } catch (err) {
322
324
  throw new Error(
323
- `An error occured trying to generate a relay quote: ${err instanceof Error ? err.message : JSON.stringify(err)}`
325
+ `An error occurred trying to generate a relay quote: ${err instanceof Error ? err.message : JSON.stringify(err)}`
324
326
  );
325
327
  }
326
328
  }
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../index.ts", "../src/client.ts", "../src/execution.ts", "../src/quote.ts", "../src/constants.ts", "../src/fees.ts", "../src/types.ts", "../src/utils.ts"],
4
- "sourcesContent": ["export {\n getRelayClient,\n initializeRelayClient,\n type InitializeRelayClientParams,\n} from './src/client'\nexport {\n type ExecuteRelayQuoteParams,\n executeRelayQuote,\n getRelayExecutionInfo,\n} from './src/execution'\nexport { type GetRelayQuoteParams, getRelayQuote } from './src/quote'\nexport {\n getRelayExecutionRefundState,\n getRelayExecutionState,\n isRelayExecutionTerminalStatus,\n} from './src/utils'\nexport {\n LogLevel,\n type RelayExecutionInfo,\n type RelayExecutionStatus,\n} from './src/types'\n", "import {\n MAINNET_RELAY_API,\n type RelayClient,\n type RelayClientOptions,\n convertViemChainToRelayChain,\n createClient,\n getClient,\n} from '@reservoir0x/relay-sdk'\nimport type { Chain } from 'viem'\nimport type { Logger } from './types'\n\nexport type InitializeRelayClientParams = Omit<\n RelayClientOptions,\n 'baseApiUrl' | 'chains' | 'logger'\n> & {\n chains: Chain[]\n logger: Logger\n}\n\n/**\n * Initializes a global instance of the RelayClient\n * https://docs.relay.link/references/sdk/createClient\n */\nexport function initializeRelayClient({\n chains,\n logger,\n ...options\n}: InitializeRelayClientParams): RelayClient {\n return createClient({\n ...options,\n baseApiUrl: MAINNET_RELAY_API,\n chains: chains.map(convertViemChainToRelayChain),\n logger: (message) => {\n logger.log('[RelayClient]:', message)\n },\n })\n}\n\n/**\n * Gets the global instance of the RelayClient\n */\nexport function getRelayClient(): RelayClient {\n const client = getClient()\n\n if (!client) {\n throw new Error('Relay client is not defined')\n }\n\n return client\n}\n", "import { type Execute, MAINNET_RELAY_API } from '@reservoir0x/relay-sdk'\nimport type { Hex, WalletClient } from 'viem'\nimport { getRelayClient } from './client'\nimport type { Logger, RelayExecutionInfo } from './types'\n\nexport interface ExecuteRelayQuoteParams {\n logger: Logger\n onConfirmed: (txHash: Hex) => Promise<void>\n onError: (error: Error) => Promise<void>\n relayQuote: Execute\n stepMessageSetter: (message: string) => void\n walletClient: WalletClient\n}\n\n// TODO: Add unit tests for this once impl is settled\nexport async function executeRelayQuote({\n logger,\n onConfirmed,\n onError,\n relayQuote,\n stepMessageSetter,\n walletClient,\n}: ExecuteRelayQuoteParams) {\n await getRelayClient().actions.execute({\n quote: relayQuote,\n wallet: walletClient,\n onProgress: async ({\n steps,\n fees,\n breakdown,\n currentStep,\n currentStepItem,\n txHashes,\n details,\n error,\n }) => {\n const logPrefix = 'onRelayProgress'\n logger.log(`${logPrefix}:params`, {\n steps,\n currentStep,\n fees,\n breakdown,\n currentStepItem,\n txHashes,\n details,\n error,\n })\n\n stepMessageSetter(currentStep?.action ?? '')\n\n if (error) {\n logger.log(`${logPrefix}:errorDetected`, error)\n await onError(error).catch((e) => {\n logger.error(`${logPrefix}:onErrorFailed`, e)\n })\n } else if (\n // We can redirect as soon as all the required user steps are done\n // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1748381169792379\n txHashes &&\n txHashes.length > 0 &&\n txHashes.length === steps.length\n ) {\n logger.log(`${logPrefix}:completed`, txHashes)\n // Can we assume its completed here?\n // Use first txHash as the main txHash in fun DE table\n await onConfirmed(txHashes[0].txHash as Hex).catch((e) => {\n logger.error(`${logPrefix}:onConfirmedFailed`, e)\n })\n }\n },\n })\n}\n\nexport async function getRelayExecutionInfo(\n requestId: string,\n): Promise<RelayExecutionInfo> {\n const url = `${MAINNET_RELAY_API}/intents/status/v2?requestId=${requestId}`\n const response = await fetch(url)\n if (!response.ok) {\n throw Error(response.statusText)\n }\n\n const data = await response.json()\n return data as RelayExecutionInfo\n}\n", "import { type Address, encodeFunctionData } from 'viem'\nimport { getRelayClient } from './client'\nimport {\n FUN_RELAY_REFERRER,\n FUN_RELAY_REVENUE_WALLET,\n RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,\n} from './constants'\nimport { computeFunRelayFeeBps, parseRelayFees } from './fees'\nimport type {\n ApiFunkitCheckoutActionParams,\n CheckoutQuoteResponse,\n Logger,\n} from './types'\nimport { convertFunToRelayTokenAddress } from './utils'\n\nexport interface GetRelayQuoteParams {\n actionParams?: ApiFunkitCheckoutActionParams[]\n fromChainId: string\n fromTokenAddress: Address\n logger: Logger\n recipientAddress: Address | undefined\n toChainId: string\n toTokenAddress: Address\n toTokenAmount: number\n toTokenDecimals: number\n userAddress: Address | undefined\n}\n\nexport async function getRelayQuote({\n actionParams,\n logger,\n toChainId,\n toTokenAddress,\n toTokenAmount,\n toTokenDecimals,\n fromChainId,\n fromTokenAddress,\n recipientAddress,\n userAddress,\n}: GetRelayQuoteParams): Promise<CheckoutQuoteResponse> {\n try {\n const relayClient = getRelayClient()\n\n // Mirror logic in api-base (this is wrong)\n const toMultipler = 10 ** toTokenDecimals\n const toAmountBaseUnitBI = BigInt(Math.floor(toTokenAmount * toMultipler))\n const toAmountBaseUnitBIString = toAmountBaseUnitBI.toString()\n\n const txs = actionParams?.map((action) => {\n const data = encodeFunctionData({\n abi: action.contractAbi,\n args: action.functionArgs,\n functionName: action.functionName,\n })\n\n return {\n data,\n to: action.contractAddress,\n value: String(action.value ?? 0n),\n }\n })\n\n logger.log('getRelayQuoteParams', {\n actionParams,\n toChainId,\n toTokenAddress,\n toTokenAmount,\n toTokenDecimals,\n fromChainId,\n fromTokenAddress,\n recipientAddress,\n userAddress,\n relayClient,\n toAmountBaseUnitBI: toAmountBaseUnitBIString,\n txs,\n })\n\n // Get the relay quote\n const relayQuote = await relayClient.actions.getQuote({\n chainId: Number(fromChainId),\n toChainId: Number(toChainId),\n currency: convertFunToRelayTokenAddress(fromTokenAddress),\n toCurrency: convertFunToRelayTokenAddress(toTokenAddress),\n amount: toAmountBaseUnitBIString,\n recipient: recipientAddress,\n tradeType: 'EXACT_OUTPUT',\n user: userAddress,\n ...(txs && { txs }),\n options: {\n referrer: FUN_RELAY_REFERRER,\n appFees: [\n {\n fee: computeFunRelayFeeBps({\n isSameToken:\n fromChainId === toChainId &&\n fromTokenAddress.toLowerCase() === toTokenAddress.toLowerCase(),\n }).toString(),\n recipient: FUN_RELAY_REVENUE_WALLET,\n },\n ],\n },\n })\n\n // TODO: Handling for no route response\n\n logger.log('relayQuote', relayQuote)\n\n const estSubtotalUsd = Number(\n relayQuote.details?.currencyOut?.amountUsd || 0,\n )\n const estTotalUsd = Number(relayQuote.details?.currencyIn?.amountUsd || 0)\n // Get how much fromAmount is needed for the quote\n const fromAmountString =\n relayQuote.details?.currencyIn?.amountFormatted || '0'\n const fromAmountBaseUnitString =\n relayQuote.details?.currencyIn?.amount || '0'\n\n // RequestID will be consistent across steps in the quote\n // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1747774944603209\n const relayRequestId = relayQuote.steps[0]?.requestId\n\n // TODO: Verify with relay team if this is possible?\n if (!relayRequestId) {\n throw new Error('Relay quote does not contain a requestId')\n }\n\n const {\n relayGasFeesUsd,\n totalLpFeesUsd,\n totalFeesUsd,\n totalFeesFromAmount,\n totalFeesFromAmountBaseUnit,\n } = parseRelayFees({ fees: relayQuote.fees, logger })\n\n const estSubtotalFromAmount = (\n Number.parseFloat(fromAmountString) - totalFeesFromAmount\n ).toString()\n\n const estSubtotalFromAmountBaseUnit = (\n BigInt(fromAmountBaseUnitString) - totalFeesFromAmountBaseUnit\n ).toString()\n\n return {\n quoteId: relayRequestId,\n estTotalFromAmount: fromAmountString,\n estSubtotalFromAmount,\n estTotalFromAmountBaseUnit: fromAmountBaseUnitString,\n estSubtotalFromAmountBaseUnit: estSubtotalFromAmountBaseUnit,\n estFeesFromAmount: totalFeesFromAmount.toString(),\n estFeesFromAmountBaseUnit: totalFeesFromAmountBaseUnit.toString(),\n fromTokenAddress,\n estFeesUsd: totalFeesUsd,\n estSubtotalUsd,\n estTotalUsd,\n estCheckoutTimeMs:\n (relayQuote.details?.timeEstimate || 0) * 1000 +\n RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,\n estMarketMakerGasUsd: relayGasFeesUsd,\n lpFeePercentage: 0, // TODO: ?\n lpFeeUsd: totalLpFeesUsd,\n metadata: {\n relayQuote,\n toAmountBaseUnit: toAmountBaseUnitBIString,\n },\n }\n } catch (err) {\n throw new Error(\n `An error occured trying to generate a relay quote: ${\n err instanceof Error ? err.message : JSON.stringify(err)\n }`,\n )\n }\n}\n", "import type { Address } from 'viem'\nimport type { RelayExecutionStatus } from './types'\n\n/**\n * Fake address for a chain's native currency used by Funkit\n */\nexport const FUNKIT_NATIVE_TOKEN =\n '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' satisfies Address\n\n/**\n * Fake address for a chain's native currency used by Relay\n */\nexport const RELAY_NATIVE_TOKEN =\n '0x0000000000000000000000000000000000000000' satisfies Address\n\n/**\n * Wallet that receives the app fees collected by Relay\n */\nexport const FUN_RELAY_REVENUE_WALLET =\n '0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E' satisfies Address\n\n/**\n * Referred field in Relay quote\n */\nexport const FUN_RELAY_REFERRER = 'funxyz'\n\n/**\n * Buffer added to Relay's time estimate (which sometimes is 0)\n */\nexport const RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3_000 // 3 seconds\n\nexport const RELAY_TERMINAL_STATUSES: RelayExecutionStatus[] = [\n 'refund',\n 'failure',\n 'success',\n]\n", "import type { CallFees } from '@reservoir0x/relay-sdk'\nimport type { Logger } from './types'\n\nexport function computeFunRelayFeeBps({\n isSameToken,\n}: {\n isSameToken: boolean\n}): number {\n // For now, we have a flat 2bps app fee for all relay transactions\n // TODO: Dynamic fee based on the transaction size, from token, to token, etc\n return isSameToken ? 0 : 2\n}\n\nexport function parseRelayFees({\n fees,\n logger,\n}: {\n fees: CallFees | undefined\n logger: Logger\n}) {\n // Gas fees, denominated in source chain native token\n const relayGasFeesUsd = Number.parseFloat(fees?.gas?.amountUsd || '0')\n\n // App fees, denominated in source chain token\n const funLpFeesUsd = Number.parseFloat(fees?.app?.amountUsd || '0')\n const funLpFeesFromAmount = Number.parseFloat(\n fees?.app?.amountFormatted || '0',\n )\n const funLpFeesFromAmountBaseUnit = BigInt(fees?.app?.amount || '0')\n\n // Relay fees, denominated in source chain token\n const relayLpFeesUsd =\n Number.parseFloat(fees?.relayer?.amountUsd || '0') +\n Number.parseFloat(fees?.relayerGas?.amountUsd || '0') +\n Number.parseFloat(fees?.relayerService?.amountUsd || '0')\n const relayLpFeesFromAmount =\n Number.parseFloat(fees?.relayer?.amountFormatted || '0') +\n Number.parseFloat(fees?.relayerGas?.amountFormatted || '0') +\n Number.parseFloat(fees?.relayerService?.amountFormatted || '0')\n const relayLpFeesFromAmountBaseUnit =\n BigInt(fees?.relayer?.amount || '0') +\n BigInt(fees?.relayerGas?.amount || '0') +\n BigInt(fees?.relayerService?.amount || '0')\n\n const totalLpFeesUsd = funLpFeesUsd + relayLpFeesUsd\n const totalLpFeesFromAmount = funLpFeesFromAmount + relayLpFeesFromAmount\n const totalLpFeesFromAmountBaseUnit =\n funLpFeesFromAmountBaseUnit + relayLpFeesFromAmountBaseUnit\n\n logger.log('parseRelayFees', {\n relayGasFeesUsd,\n funLpFeesUsd,\n funLpFeesFromAmount,\n funLpFeesFromAmountBaseUnit,\n relayLpFeesUsd,\n relayLpFeesFromAmount,\n relayLpFeesFromAmountBaseUnit,\n totalLpFeesUsd,\n totalLpFeesFromAmount,\n totalLpFeesFromAmountBaseUnit,\n })\n\n return {\n relayGasFeesUsd,\n totalLpFeesUsd,\n totalFeesUsd: relayGasFeesUsd + totalLpFeesUsd,\n totalFeesFromAmount: totalLpFeesFromAmount,\n totalFeesFromAmountBaseUnit: totalLpFeesFromAmountBaseUnit,\n }\n}\n", "import { LogLevel } from '@reservoir0x/relay-sdk'\nimport type { Abi, Address } from 'viem'\n\nexport { LogLevel }\n\nexport type RelayExecutionStatus =\n | 'refund'\n | 'delayed'\n | 'waiting'\n | 'failure'\n | 'pending'\n | 'success'\n\n// https://docs.relay.link/references/api/get-intents-status-v2\nexport interface RelayExecutionInfo {\n status: RelayExecutionStatus\n details: string\n /** Incoming transaction hashes */\n inTxHashes: string[]\n /** Outgoing transaction hashes */\n txHashes: string[]\n /** The last timestamp the data was updated in milliseconds */\n time: number\n originChainId: number\n destinationChainId: number\n}\n\n//// The types below are duplicated from @funkit/api-base atm, but this package should be used in BE as well\n//// TODO: Are we fine with BE importing @funkit/api-base and (by extension) @funkit/utils?\n//// See https://linear.app/funxyz/issue/PE-1342/sdk-extract-domainsrelayts-to-a-new-package#comment-d487d533\n\nexport interface Logger {\n error(message: string, data?: object): void\n log(message: string, data?: object): void\n}\n\nexport interface ApiFunkitCheckoutActionParams {\n contractAbi: Abi\n contractAddress: Address\n functionName: string\n functionArgs: unknown[]\n value?: bigint\n}\n\nexport enum CheckoutRefundState {\n INITIATED = 'INITIATED',\n ERROR = 'ERROR',\n REFUNDED = 'REFUNDED',\n PROCEEDED = 'PROCEEDED',\n WAITING_FOR_FULFILLMENT = 'WAITING_FOR_FULFILLMENT',\n FULFILLED = 'FULFILLED',\n}\n\n// Reference from api server: https://github.com/fun-xyz/fun-api-server/blob/main/src/tables/FunWalletCheckout.ts#L11C1-L21C2\nexport enum CheckoutState {\n // In-progress States\n FROM_UNFUNDED = 'FROM_UNFUNDED',\n FROM_FUNDED = 'FROM_FUNDED',\n FROM_POOLED = 'FROM_POOLED',\n TO_UNFUNDED = 'TO_UNFUNDED',\n TO_FUNDED = 'TO_FUNDED',\n TO_POOLED = 'TO_POOLED',\n TO_READY = 'TO_READY',\n PENDING_RECEIVAL = 'PENDING_RECEIVAL',\n // Terminal States\n COMPLETED = 'COMPLETED',\n CHECKOUT_ERROR = 'CHECKOUT_ERROR',\n EXPIRED = 'EXPIRED',\n CANCELLED = 'CANCELLED',\n}\n\n// The response of the actual /checkout/quote api\nexport type CheckoutApiQuoteResponse = {\n quoteId: string\n estTotalFromAmountBaseUnit: string\n estSubtotalFromAmountBaseUnit: string\n estFeesFromAmountBaseUnit: string\n fromTokenAddress: Address\n estFeesUsd: number\n estSubtotalUsd: number\n estTotalUsd: number\n estCheckoutTimeMs: number\n estMarketMakerGasUsd: number\n lpFeePercentage: number\n lpFeeUsd: number\n}\n\n// The formatted response quote interface from the core sdk\nexport type CheckoutQuoteResponse = CheckoutApiQuoteResponse & {\n estTotalFromAmount: string\n estSubtotalFromAmount: string\n estFeesFromAmount: string\n\n // Any additional fields purely for frontend use\n metadata?: { [key: string]: unknown }\n}\n", "import type { Address } from 'viem'\nimport {\n FUNKIT_NATIVE_TOKEN,\n RELAY_NATIVE_TOKEN,\n RELAY_TERMINAL_STATUSES,\n} from './constants'\nimport {\n CheckoutRefundState,\n CheckoutState,\n type RelayExecutionInfo,\n} from './types'\n\n/**\n * Converts a token address within Funkit the corresponding Relay token address.\n */\nexport function convertFunToRelayTokenAddress(address: Address): Address {\n if (address.toLowerCase() === FUNKIT_NATIVE_TOKEN.toLowerCase()) {\n return RELAY_NATIVE_TOKEN\n }\n\n return address\n}\n\nexport function getRelayExecutionRefundState(\n info: RelayExecutionInfo,\n): CheckoutRefundState | undefined {\n switch (info.status) {\n case 'refund':\n return CheckoutRefundState.REFUNDED\n default:\n return undefined\n }\n}\n\nexport function getRelayExecutionState(\n info: RelayExecutionInfo,\n): CheckoutState {\n switch (info.status) {\n case 'success':\n return CheckoutState.COMPLETED\n case 'failure':\n case 'refund':\n return CheckoutState.CHECKOUT_ERROR\n default:\n return CheckoutState.PENDING_RECEIVAL\n }\n}\n\n/**\n * Checks whether the Relay execution has reached a terminal status.\n */\nexport function isRelayExecutionTerminalStatus(\n info: RelayExecutionInfo,\n): boolean {\n return RELAY_TERMINAL_STATUSES.includes(info.status)\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../index.ts", "../src/client.ts", "../src/constants.ts", "../src/execution.ts", "../src/fees.ts", "../src/quote.ts", "../src/types.ts", "../src/utils.ts"],
4
+ "sourcesContent": ["export {\n getRelayClient,\n initializeRelayClient,\n type InitializeRelayClientParams,\n} from './src/client'\nexport {\n FUN_RELAY_REFERRER,\n FUN_RELAY_REVENUE_WALLET,\n} from './src/constants'\nexport {\n type ExecuteRelayQuoteParams,\n executeRelayQuote,\n getRelayExecutionInfo,\n} from './src/execution'\nexport {\n computeFunRelayFeeBps,\n parseRelayFees,\n} from './src/fees'\nexport {\n type GetRelayQuoteParams,\n getRelayQuote,\n type RelayQuote,\n} from './src/quote'\nexport {\n getRelayExecutionRefundState,\n getRelayExecutionState,\n isRelayExecutionTerminalStatus,\n} from './src/utils'\nexport {\n LogLevel,\n type RelayExecutionInfo,\n type RelayExecutionStatus,\n} from './src/types'\n", "import {\n MAINNET_RELAY_API,\n type RelayClient,\n type RelayClientOptions,\n convertViemChainToRelayChain,\n createClient,\n getClient,\n} from '@reservoir0x/relay-sdk'\nimport type { Chain } from 'viem'\nimport type { Logger } from './types'\n\nexport type InitializeRelayClientParams = Omit<\n RelayClientOptions,\n 'baseApiUrl' | 'chains' | 'logger'\n> & {\n chains: Chain[]\n logger: Logger\n}\n\n/**\n * Initializes a global instance of the RelayClient\n * https://docs.relay.link/references/sdk/createClient\n */\nexport function initializeRelayClient({\n chains,\n logger,\n ...options\n}: InitializeRelayClientParams): RelayClient {\n return createClient({\n ...options,\n baseApiUrl: MAINNET_RELAY_API,\n chains: chains.map(convertViemChainToRelayChain),\n logger: (message) => {\n logger.info('[RelayClient]:', message)\n },\n })\n}\n\n/**\n * Gets the global instance of the RelayClient\n */\nexport function getRelayClient(): RelayClient {\n const client = getClient()\n\n if (!client) {\n throw new Error('Relay client is not defined')\n }\n\n return client\n}\n", "import type { Address } from 'viem'\nimport type { RelayExecutionStatus } from './types'\n\n/**\n * Fake address for a chain's native currency used by Funkit\n */\nexport const FUNKIT_NATIVE_TOKEN =\n '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' satisfies Address\n\n/**\n * Fake address for a chain's native currency used by Relay\n */\nexport const RELAY_NATIVE_TOKEN =\n '0x0000000000000000000000000000000000000000' satisfies Address\n\n/**\n * Wallet that receives the app fees collected by Relay\n */\nexport const FUN_RELAY_REVENUE_WALLET =\n '0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E' satisfies Address\n\n/**\n * Referred field in Relay quote\n */\nexport const FUN_RELAY_REFERRER = 'funxyz'\n\n/**\n * Buffer added to Relay's time estimate (which sometimes is 0)\n */\nexport const RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3_000 // 3 seconds\n\nexport const RELAY_TERMINAL_STATUSES: RelayExecutionStatus[] = [\n 'refund',\n 'failure',\n 'success',\n]\n", "import {\n type Execute,\n MAINNET_RELAY_API,\n type ProgressData,\n} from '@reservoir0x/relay-sdk'\nimport type { Hex, WalletClient } from 'viem'\nimport { getRelayClient } from './client'\nimport type { Logger, RelayExecutionInfo } from './types'\n\nexport type RelayExecutionStep = ProgressData['currentStep'] & {}\n\nexport interface ExecuteRelayQuoteParams {\n logger: Logger\n onConfirmed: (txHash: Hex) => Promise<void>\n onError: (error: Error) => Promise<void>\n onProgress?: (step: RelayExecutionStep | null) => void\n relayQuote: Execute\n walletClient: WalletClient\n}\n\nexport async function executeRelayQuote({\n logger,\n onConfirmed,\n onError,\n onProgress,\n relayQuote,\n walletClient,\n}: ExecuteRelayQuoteParams) {\n await getRelayClient().actions.execute({\n quote: relayQuote,\n wallet: walletClient,\n onProgress: async ({\n steps,\n fees,\n breakdown,\n currentStep,\n currentStepItem,\n txHashes,\n details,\n error,\n }) => {\n const logPrefix = 'onRelayProgress'\n logger.info(`${logPrefix}:params`, {\n steps,\n currentStep,\n fees,\n breakdown,\n currentStepItem,\n txHashes,\n details,\n error,\n })\n\n onProgress?.(currentStep ?? null)\n\n if (error) {\n logger.info(`${logPrefix}:errorDetected`, error)\n await onError(error).catch((e) => {\n logger.error(`${logPrefix}:onErrorFailed`, e)\n })\n } else if (\n // We can redirect as soon as all the required user steps are done\n // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1748381169792379\n txHashes &&\n txHashes.length > 0 &&\n txHashes.length === steps.length\n ) {\n logger.info(`${logPrefix}:completed`, txHashes)\n // Can we assume its completed here?\n // Use first txHash as the main txHash in fun DE table\n await onConfirmed(txHashes[0].txHash as Hex).catch((e) => {\n logger.error(`${logPrefix}:onConfirmedFailed`, e)\n })\n }\n },\n })\n}\n\nexport async function getRelayExecutionInfo(\n requestId: string,\n): Promise<RelayExecutionInfo> {\n const url = `${MAINNET_RELAY_API}/intents/status/v2?requestId=${requestId}`\n const response = await fetch(url)\n if (!response.ok) {\n throw Error(response.statusText)\n }\n\n const data = await response.json()\n return data as RelayExecutionInfo\n}\n", "import type { CallFees } from '@reservoir0x/relay-sdk'\nimport type { Logger } from './types'\n\nexport function computeFunRelayFeeBps({\n isSameToken,\n}: {\n isSameToken: boolean\n}): number {\n // For now, we have a flat 2bps app fee for all relay transactions\n // TODO: Dynamic fee based on the transaction size, from token, to token, etc\n return isSameToken ? 0 : 2\n}\n\nexport function parseRelayFees({\n fees,\n logger,\n}: {\n fees: CallFees | undefined\n logger: Logger\n}) {\n // Gas fees, denominated in source chain native token\n const relayGasFeesUsd = Number.parseFloat(fees?.gas?.amountUsd || '0')\n\n // App fees, denominated in source chain token\n const funLpFeesUsd = Number.parseFloat(fees?.app?.amountUsd || '0')\n const funLpFeesFromAmount = Number.parseFloat(\n fees?.app?.amountFormatted || '0',\n )\n const funLpFeesFromAmountBaseUnit = BigInt(fees?.app?.amount || '0')\n\n // Relay fees, denominated in source chain token\n const relayLpFeesUsd =\n Number.parseFloat(fees?.relayer?.amountUsd || '0') +\n Number.parseFloat(fees?.relayerGas?.amountUsd || '0') +\n Number.parseFloat(fees?.relayerService?.amountUsd || '0')\n const relayLpFeesFromAmount =\n Number.parseFloat(fees?.relayer?.amountFormatted || '0') +\n Number.parseFloat(fees?.relayerGas?.amountFormatted || '0') +\n Number.parseFloat(fees?.relayerService?.amountFormatted || '0')\n const relayLpFeesFromAmountBaseUnit =\n BigInt(fees?.relayer?.amount || '0') +\n BigInt(fees?.relayerGas?.amount || '0') +\n BigInt(fees?.relayerService?.amount || '0')\n\n const totalLpFeesUsd = funLpFeesUsd + relayLpFeesUsd\n const totalLpFeesFromAmount = funLpFeesFromAmount + relayLpFeesFromAmount\n const totalLpFeesFromAmountBaseUnit =\n funLpFeesFromAmountBaseUnit + relayLpFeesFromAmountBaseUnit\n\n logger.info('parseRelayFees', {\n relayGasFeesUsd,\n funLpFeesUsd,\n funLpFeesFromAmount,\n funLpFeesFromAmountBaseUnit,\n relayLpFeesUsd,\n relayLpFeesFromAmount,\n relayLpFeesFromAmountBaseUnit,\n totalLpFeesUsd,\n totalLpFeesFromAmount,\n totalLpFeesFromAmountBaseUnit,\n })\n\n return {\n relayGasFeesUsd,\n totalLpFeesUsd,\n totalFeesUsd: relayGasFeesUsd + totalLpFeesUsd,\n totalFeesFromAmount: totalLpFeesFromAmount,\n totalFeesFromAmountBaseUnit: totalLpFeesFromAmountBaseUnit,\n }\n}\n", "import type { Execute, GetQuoteParameters } from '@reservoir0x/relay-sdk'\nimport { type Address, encodeFunctionData } from 'viem'\nimport { getRelayClient } from './client'\nimport {\n FUN_RELAY_REFERRER,\n FUN_RELAY_REVENUE_WALLET,\n RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,\n} from './constants'\nimport { computeFunRelayFeeBps, parseRelayFees } from './fees'\nimport type {\n ApiFunkitCheckoutActionParams,\n CheckoutQuoteResponse,\n Logger,\n} from './types'\nimport { convertFunToRelayTokenAddress } from './utils'\n\ntype RelayQuoteOptions = GetQuoteParameters['options'] & {}\n\nexport type GetRelayQuoteParams = {\n actionParams?: ApiFunkitCheckoutActionParams[]\n fromChainId: string\n fromTokenAddress: Address\n logger: Logger\n /**\n * {@link getRelayQuote} already sets {@link RelayQuoteOptions.appFees|appFees} and {@link RelayQuoteOptions.referrer|referrer}.\n * Only include them if you wish to override.\n */\n options?: RelayQuoteOptions\n recipientAddress: Address | undefined\n toChainId: string\n toTokenAddress: Address\n tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT'\n userAddress: Address | undefined\n} & (\n | {\n fromTokenAmountBaseUnit: bigint | string\n tradeType: 'EXACT_INPUT'\n }\n | {\n toTokenAmountBaseUnit: bigint | string\n tradeType: 'EXACT_OUTPUT'\n }\n)\n\nexport type RelayQuote = CheckoutQuoteResponse & {\n /** Required for EXACT_INPUT checkouts */\n finalToAmountBaseUnit: string\n metadata: {\n fromAmountBaseUnit: string\n relayQuote: Execute\n toAmountBaseUnit: string\n }\n}\n\nexport async function getRelayQuote({\n logger,\n ...params\n}: GetRelayQuoteParams): Promise<RelayQuote> {\n const {\n actionParams,\n fromChainId,\n fromTokenAddress,\n options,\n recipientAddress,\n toChainId,\n toTokenAddress,\n userAddress,\n } = params\n\n try {\n const relayClient = getRelayClient()\n\n const tokenAmountBaseUnit =\n params.tradeType === 'EXACT_INPUT'\n ? params.fromTokenAmountBaseUnit\n : params.toTokenAmountBaseUnit\n\n const txs = actionParams?.map((action) => {\n const data = encodeFunctionData({\n abi: action.contractAbi,\n args: action.functionArgs,\n functionName: action.functionName,\n })\n\n return {\n data,\n to: action.contractAddress,\n value: String(action.value ?? 0n),\n }\n })\n\n logger.info('getRelayQuoteParams', {\n ...params,\n tokenAmountBaseUnit,\n txs,\n })\n\n // Get the relay quote\n const relayQuote = await relayClient.actions.getQuote({\n chainId: Number(fromChainId),\n toChainId: Number(toChainId),\n currency: convertFunToRelayTokenAddress(fromTokenAddress),\n toCurrency: convertFunToRelayTokenAddress(toTokenAddress),\n amount: tokenAmountBaseUnit.toString(),\n recipient: recipientAddress,\n tradeType: params.tradeType,\n user: userAddress,\n ...(txs && { txs }),\n options: {\n referrer: FUN_RELAY_REFERRER,\n appFees: [\n {\n fee: computeFunRelayFeeBps({\n isSameToken:\n fromChainId === toChainId &&\n fromTokenAddress.toLowerCase() === toTokenAddress.toLowerCase(),\n }).toString(),\n recipient: FUN_RELAY_REVENUE_WALLET,\n },\n ],\n ...options,\n },\n })\n\n // TODO: Handling for no route response\n\n logger.info('relayQuote', relayQuote)\n\n const estSubtotalUsd = Number(\n relayQuote.details?.currencyOut?.amountUsd || 0,\n )\n const estTotalUsd = Number(relayQuote.details?.currencyIn?.amountUsd || 0)\n // Get how much fromAmount is needed for the quote\n const fromAmountString =\n relayQuote.details?.currencyIn?.amountFormatted || '0'\n const fromAmountBaseUnitString =\n relayQuote.details?.currencyIn?.amount || '0'\n\n // RequestID will be consistent across steps in the quote\n // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1747774944603209\n const relayRequestId = relayQuote.steps[0]?.requestId\n\n // TODO: Verify with relay team if this is possible?\n if (!relayRequestId) {\n throw new Error('Relay quote does not contain a requestId')\n }\n\n // TODO: Verify with relay team if this is possible?\n if (!relayQuote.details?.currencyIn || !relayQuote.details?.currencyOut) {\n throw new Error('Relay quote does not contain trade details')\n }\n\n const {\n relayGasFeesUsd,\n totalLpFeesUsd,\n totalFeesUsd,\n totalFeesFromAmount,\n totalFeesFromAmountBaseUnit,\n } = parseRelayFees({ fees: relayQuote.fees, logger })\n\n const estSubtotalFromAmount = (\n Number.parseFloat(fromAmountString) - totalFeesFromAmount\n ).toString()\n\n const estSubtotalFromAmountBaseUnit = (\n BigInt(fromAmountBaseUnitString) - totalFeesFromAmountBaseUnit\n ).toString()\n\n return {\n quoteId: relayRequestId,\n estCheckoutTimeMs:\n (relayQuote.details.timeEstimate || 0) * 1000 +\n RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,\n estFeesFromAmount: totalFeesFromAmount.toString(),\n estFeesFromAmountBaseUnit: totalFeesFromAmountBaseUnit.toString(),\n estFeesUsd: totalFeesUsd,\n estMarketMakerGasUsd: relayGasFeesUsd,\n estSubtotalFromAmount,\n estSubtotalFromAmountBaseUnit,\n estSubtotalUsd,\n estTotalFromAmount: fromAmountString,\n estTotalFromAmountBaseUnit: fromAmountBaseUnitString,\n estTotalUsd,\n finalToAmountBaseUnit: relayQuote.details.currencyOut.amount ?? '0', // TODO: Or do we want 'minimumAmount'?\n fromTokenAddress,\n lpFeePercentage: 0, // TODO: ?\n lpFeeUsd: totalLpFeesUsd,\n metadata: {\n fromAmountBaseUnit:\n params.tradeType === 'EXACT_INPUT'\n ? tokenAmountBaseUnit.toString()\n : (relayQuote.details.currencyIn.amount ?? '0'),\n relayQuote,\n toAmountBaseUnit:\n params.tradeType === 'EXACT_INPUT'\n ? (relayQuote.details.currencyOut.amount ?? '0')\n : tokenAmountBaseUnit.toString(),\n },\n }\n } catch (err) {\n throw new Error(\n `An error occurred trying to generate a relay quote: ${\n err instanceof Error ? err.message : JSON.stringify(err)\n }`,\n )\n }\n}\n", "import { LogLevel } from '@reservoir0x/relay-sdk'\nimport type { Abi, Address } from 'viem'\n\nexport { LogLevel }\n\nexport type RelayExecutionStatus =\n | 'refund'\n | 'delayed'\n | 'waiting'\n | 'failure'\n | 'pending'\n | 'success'\n\n// https://docs.relay.link/references/api/get-intents-status-v2\nexport interface RelayExecutionInfo {\n status: RelayExecutionStatus\n details: string\n /** Incoming transaction hashes */\n inTxHashes: string[]\n /** Outgoing transaction hashes */\n txHashes: string[]\n /** The last timestamp the data was updated in milliseconds */\n time: number\n originChainId: number\n destinationChainId: number\n}\n\n//// The types below are duplicated from @funkit/api-base atm, but this package should be used in BE as well\n//// TODO: Are we fine with BE importing @funkit/api-base and (by extension) @funkit/utils?\n//// See https://linear.app/funxyz/issue/PE-1342/sdk-extract-domainsrelayts-to-a-new-package#comment-d487d533\n\nexport interface Logger {\n error(message: string, data?: object): void\n info(message: string, data?: object): void\n}\n\nexport interface ApiFunkitCheckoutActionParams {\n contractAbi: Abi\n contractAddress: Address\n functionName: string\n functionArgs: unknown[]\n value?: bigint\n}\n\nexport enum CheckoutRefundState {\n INITIATED = 'INITIATED',\n ERROR = 'ERROR',\n REFUNDED = 'REFUNDED',\n PROCEEDED = 'PROCEEDED',\n WAITING_FOR_FULFILLMENT = 'WAITING_FOR_FULFILLMENT',\n FULFILLED = 'FULFILLED',\n}\n\n// Reference from api server: https://github.com/fun-xyz/fun-api-server/blob/main/src/tables/FunWalletCheckout.ts#L11C1-L21C2\nexport enum CheckoutState {\n // In-progress States\n FROM_UNFUNDED = 'FROM_UNFUNDED',\n FROM_FUNDED = 'FROM_FUNDED',\n FROM_POOLED = 'FROM_POOLED',\n TO_UNFUNDED = 'TO_UNFUNDED',\n TO_FUNDED = 'TO_FUNDED',\n TO_POOLED = 'TO_POOLED',\n TO_READY = 'TO_READY',\n PENDING_RECEIVAL = 'PENDING_RECEIVAL',\n // Terminal States\n COMPLETED = 'COMPLETED',\n CHECKOUT_ERROR = 'CHECKOUT_ERROR',\n EXPIRED = 'EXPIRED',\n CANCELLED = 'CANCELLED',\n}\n\n// The response of the actual /checkout/quote api\nexport type CheckoutApiQuoteResponse = {\n quoteId: string\n estTotalFromAmountBaseUnit: string\n estSubtotalFromAmountBaseUnit: string\n estFeesFromAmountBaseUnit: string\n fromTokenAddress: Address\n estFeesUsd: number\n estSubtotalUsd: number\n estTotalUsd: number\n estCheckoutTimeMs: number\n estMarketMakerGasUsd: number\n lpFeePercentage: number\n lpFeeUsd: number\n}\n\n// The formatted response quote interface from the core sdk\nexport type CheckoutQuoteResponse = CheckoutApiQuoteResponse & {\n estTotalFromAmount: string\n estSubtotalFromAmount: string\n estFeesFromAmount: string\n\n // Any additional fields purely for frontend use\n metadata?: { [key: string]: unknown }\n}\n", "import type { Address } from 'viem'\nimport {\n FUNKIT_NATIVE_TOKEN,\n RELAY_NATIVE_TOKEN,\n RELAY_TERMINAL_STATUSES,\n} from './constants'\nimport {\n CheckoutRefundState,\n CheckoutState,\n type RelayExecutionInfo,\n} from './types'\n\n/**\n * Converts a token address within Funkit the corresponding Relay token address.\n */\nexport function convertFunToRelayTokenAddress(address: Address): Address {\n if (address.toLowerCase() === FUNKIT_NATIVE_TOKEN.toLowerCase()) {\n return RELAY_NATIVE_TOKEN\n }\n\n return address\n}\n\nexport function getRelayExecutionRefundState(\n info: RelayExecutionInfo,\n): CheckoutRefundState | undefined {\n switch (info.status) {\n case 'refund':\n return CheckoutRefundState.REFUNDED\n default:\n return undefined\n }\n}\n\nexport function getRelayExecutionState(\n info: RelayExecutionInfo,\n): CheckoutState {\n switch (info.status) {\n case 'success':\n return CheckoutState.COMPLETED\n case 'failure':\n case 'refund':\n return CheckoutState.CHECKOUT_ERROR\n default:\n return CheckoutState.PENDING_RECEIVAL\n }\n}\n\n/**\n * Checks whether the Relay execution has reached a terminal status.\n */\nexport function isRelayExecutionTerminalStatus(\n info: RelayExecutionInfo,\n): boolean {\n return RELAY_TERMINAL_STATUSES.includes(info.status)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_relay_sdk", "import_relay_sdk"]
7
7
  }
package/dist/index.mjs ADDED
@@ -0,0 +1,313 @@
1
+ // src/client.ts
2
+ import {
3
+ MAINNET_RELAY_API,
4
+ convertViemChainToRelayChain,
5
+ createClient,
6
+ getClient
7
+ } from "@reservoir0x/relay-sdk";
8
+ function initializeRelayClient({
9
+ chains,
10
+ logger,
11
+ ...options
12
+ }) {
13
+ return createClient({
14
+ ...options,
15
+ baseApiUrl: MAINNET_RELAY_API,
16
+ chains: chains.map(convertViemChainToRelayChain),
17
+ logger: (message) => {
18
+ logger.info("[RelayClient]:", message);
19
+ }
20
+ });
21
+ }
22
+ function getRelayClient() {
23
+ const client = getClient();
24
+ if (!client) {
25
+ throw new Error("Relay client is not defined");
26
+ }
27
+ return client;
28
+ }
29
+
30
+ // src/constants.ts
31
+ var FUNKIT_NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
32
+ var RELAY_NATIVE_TOKEN = "0x0000000000000000000000000000000000000000";
33
+ var FUN_RELAY_REVENUE_WALLET = "0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E";
34
+ var FUN_RELAY_REFERRER = "funxyz";
35
+ var RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3e3;
36
+ var RELAY_TERMINAL_STATUSES = [
37
+ "refund",
38
+ "failure",
39
+ "success"
40
+ ];
41
+
42
+ // src/execution.ts
43
+ import {
44
+ MAINNET_RELAY_API as MAINNET_RELAY_API2
45
+ } from "@reservoir0x/relay-sdk";
46
+ async function executeRelayQuote({
47
+ logger,
48
+ onConfirmed,
49
+ onError,
50
+ onProgress,
51
+ relayQuote,
52
+ walletClient
53
+ }) {
54
+ await getRelayClient().actions.execute({
55
+ quote: relayQuote,
56
+ wallet: walletClient,
57
+ onProgress: async ({
58
+ steps,
59
+ fees,
60
+ breakdown,
61
+ currentStep,
62
+ currentStepItem,
63
+ txHashes,
64
+ details,
65
+ error
66
+ }) => {
67
+ const logPrefix = "onRelayProgress";
68
+ logger.info(`${logPrefix}:params`, {
69
+ steps,
70
+ currentStep,
71
+ fees,
72
+ breakdown,
73
+ currentStepItem,
74
+ txHashes,
75
+ details,
76
+ error
77
+ });
78
+ onProgress?.(currentStep ?? null);
79
+ if (error) {
80
+ logger.info(`${logPrefix}:errorDetected`, error);
81
+ await onError(error).catch((e) => {
82
+ logger.error(`${logPrefix}:onErrorFailed`, e);
83
+ });
84
+ } else if (
85
+ // We can redirect as soon as all the required user steps are done
86
+ // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1748381169792379
87
+ txHashes && txHashes.length > 0 && txHashes.length === steps.length
88
+ ) {
89
+ logger.info(`${logPrefix}:completed`, txHashes);
90
+ await onConfirmed(txHashes[0].txHash).catch((e) => {
91
+ logger.error(`${logPrefix}:onConfirmedFailed`, e);
92
+ });
93
+ }
94
+ }
95
+ });
96
+ }
97
+ async function getRelayExecutionInfo(requestId) {
98
+ const url = `${MAINNET_RELAY_API2}/intents/status/v2?requestId=${requestId}`;
99
+ const response = await fetch(url);
100
+ if (!response.ok) {
101
+ throw Error(response.statusText);
102
+ }
103
+ const data = await response.json();
104
+ return data;
105
+ }
106
+
107
+ // src/fees.ts
108
+ function computeFunRelayFeeBps({
109
+ isSameToken
110
+ }) {
111
+ return isSameToken ? 0 : 2;
112
+ }
113
+ function parseRelayFees({
114
+ fees,
115
+ logger
116
+ }) {
117
+ const relayGasFeesUsd = Number.parseFloat(fees?.gas?.amountUsd || "0");
118
+ const funLpFeesUsd = Number.parseFloat(fees?.app?.amountUsd || "0");
119
+ const funLpFeesFromAmount = Number.parseFloat(
120
+ fees?.app?.amountFormatted || "0"
121
+ );
122
+ const funLpFeesFromAmountBaseUnit = BigInt(fees?.app?.amount || "0");
123
+ const relayLpFeesUsd = Number.parseFloat(fees?.relayer?.amountUsd || "0") + Number.parseFloat(fees?.relayerGas?.amountUsd || "0") + Number.parseFloat(fees?.relayerService?.amountUsd || "0");
124
+ const relayLpFeesFromAmount = Number.parseFloat(fees?.relayer?.amountFormatted || "0") + Number.parseFloat(fees?.relayerGas?.amountFormatted || "0") + Number.parseFloat(fees?.relayerService?.amountFormatted || "0");
125
+ const relayLpFeesFromAmountBaseUnit = BigInt(fees?.relayer?.amount || "0") + BigInt(fees?.relayerGas?.amount || "0") + BigInt(fees?.relayerService?.amount || "0");
126
+ const totalLpFeesUsd = funLpFeesUsd + relayLpFeesUsd;
127
+ const totalLpFeesFromAmount = funLpFeesFromAmount + relayLpFeesFromAmount;
128
+ const totalLpFeesFromAmountBaseUnit = funLpFeesFromAmountBaseUnit + relayLpFeesFromAmountBaseUnit;
129
+ logger.info("parseRelayFees", {
130
+ relayGasFeesUsd,
131
+ funLpFeesUsd,
132
+ funLpFeesFromAmount,
133
+ funLpFeesFromAmountBaseUnit,
134
+ relayLpFeesUsd,
135
+ relayLpFeesFromAmount,
136
+ relayLpFeesFromAmountBaseUnit,
137
+ totalLpFeesUsd,
138
+ totalLpFeesFromAmount,
139
+ totalLpFeesFromAmountBaseUnit
140
+ });
141
+ return {
142
+ relayGasFeesUsd,
143
+ totalLpFeesUsd,
144
+ totalFeesUsd: relayGasFeesUsd + totalLpFeesUsd,
145
+ totalFeesFromAmount: totalLpFeesFromAmount,
146
+ totalFeesFromAmountBaseUnit: totalLpFeesFromAmountBaseUnit
147
+ };
148
+ }
149
+
150
+ // src/quote.ts
151
+ import { encodeFunctionData } from "viem";
152
+
153
+ // src/types.ts
154
+ import { LogLevel } from "@reservoir0x/relay-sdk";
155
+
156
+ // src/utils.ts
157
+ function convertFunToRelayTokenAddress(address) {
158
+ if (address.toLowerCase() === FUNKIT_NATIVE_TOKEN.toLowerCase()) {
159
+ return RELAY_NATIVE_TOKEN;
160
+ }
161
+ return address;
162
+ }
163
+ function getRelayExecutionRefundState(info) {
164
+ switch (info.status) {
165
+ case "refund":
166
+ return "REFUNDED" /* REFUNDED */;
167
+ default:
168
+ return void 0;
169
+ }
170
+ }
171
+ function getRelayExecutionState(info) {
172
+ switch (info.status) {
173
+ case "success":
174
+ return "COMPLETED" /* COMPLETED */;
175
+ case "failure":
176
+ case "refund":
177
+ return "CHECKOUT_ERROR" /* CHECKOUT_ERROR */;
178
+ default:
179
+ return "PENDING_RECEIVAL" /* PENDING_RECEIVAL */;
180
+ }
181
+ }
182
+ function isRelayExecutionTerminalStatus(info) {
183
+ return RELAY_TERMINAL_STATUSES.includes(info.status);
184
+ }
185
+
186
+ // src/quote.ts
187
+ async function getRelayQuote({
188
+ logger,
189
+ ...params
190
+ }) {
191
+ const {
192
+ actionParams,
193
+ fromChainId,
194
+ fromTokenAddress,
195
+ options,
196
+ recipientAddress,
197
+ toChainId,
198
+ toTokenAddress,
199
+ userAddress
200
+ } = params;
201
+ try {
202
+ const relayClient = getRelayClient();
203
+ const tokenAmountBaseUnit = params.tradeType === "EXACT_INPUT" ? params.fromTokenAmountBaseUnit : params.toTokenAmountBaseUnit;
204
+ const txs = actionParams?.map((action) => {
205
+ const data = encodeFunctionData({
206
+ abi: action.contractAbi,
207
+ args: action.functionArgs,
208
+ functionName: action.functionName
209
+ });
210
+ return {
211
+ data,
212
+ to: action.contractAddress,
213
+ value: String(action.value ?? 0n)
214
+ };
215
+ });
216
+ logger.info("getRelayQuoteParams", {
217
+ ...params,
218
+ tokenAmountBaseUnit,
219
+ txs
220
+ });
221
+ const relayQuote = await relayClient.actions.getQuote({
222
+ chainId: Number(fromChainId),
223
+ toChainId: Number(toChainId),
224
+ currency: convertFunToRelayTokenAddress(fromTokenAddress),
225
+ toCurrency: convertFunToRelayTokenAddress(toTokenAddress),
226
+ amount: tokenAmountBaseUnit.toString(),
227
+ recipient: recipientAddress,
228
+ tradeType: params.tradeType,
229
+ user: userAddress,
230
+ ...txs && { txs },
231
+ options: {
232
+ referrer: FUN_RELAY_REFERRER,
233
+ appFees: [
234
+ {
235
+ fee: computeFunRelayFeeBps({
236
+ isSameToken: fromChainId === toChainId && fromTokenAddress.toLowerCase() === toTokenAddress.toLowerCase()
237
+ }).toString(),
238
+ recipient: FUN_RELAY_REVENUE_WALLET
239
+ }
240
+ ],
241
+ ...options
242
+ }
243
+ });
244
+ logger.info("relayQuote", relayQuote);
245
+ const estSubtotalUsd = Number(
246
+ relayQuote.details?.currencyOut?.amountUsd || 0
247
+ );
248
+ const estTotalUsd = Number(relayQuote.details?.currencyIn?.amountUsd || 0);
249
+ const fromAmountString = relayQuote.details?.currencyIn?.amountFormatted || "0";
250
+ const fromAmountBaseUnitString = relayQuote.details?.currencyIn?.amount || "0";
251
+ const relayRequestId = relayQuote.steps[0]?.requestId;
252
+ if (!relayRequestId) {
253
+ throw new Error("Relay quote does not contain a requestId");
254
+ }
255
+ if (!relayQuote.details?.currencyIn || !relayQuote.details?.currencyOut) {
256
+ throw new Error("Relay quote does not contain trade details");
257
+ }
258
+ const {
259
+ relayGasFeesUsd,
260
+ totalLpFeesUsd,
261
+ totalFeesUsd,
262
+ totalFeesFromAmount,
263
+ totalFeesFromAmountBaseUnit
264
+ } = parseRelayFees({ fees: relayQuote.fees, logger });
265
+ const estSubtotalFromAmount = (Number.parseFloat(fromAmountString) - totalFeesFromAmount).toString();
266
+ const estSubtotalFromAmountBaseUnit = (BigInt(fromAmountBaseUnitString) - totalFeesFromAmountBaseUnit).toString();
267
+ return {
268
+ quoteId: relayRequestId,
269
+ estCheckoutTimeMs: (relayQuote.details.timeEstimate || 0) * 1e3 + RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,
270
+ estFeesFromAmount: totalFeesFromAmount.toString(),
271
+ estFeesFromAmountBaseUnit: totalFeesFromAmountBaseUnit.toString(),
272
+ estFeesUsd: totalFeesUsd,
273
+ estMarketMakerGasUsd: relayGasFeesUsd,
274
+ estSubtotalFromAmount,
275
+ estSubtotalFromAmountBaseUnit,
276
+ estSubtotalUsd,
277
+ estTotalFromAmount: fromAmountString,
278
+ estTotalFromAmountBaseUnit: fromAmountBaseUnitString,
279
+ estTotalUsd,
280
+ finalToAmountBaseUnit: relayQuote.details.currencyOut.amount ?? "0",
281
+ // TODO: Or do we want 'minimumAmount'?
282
+ fromTokenAddress,
283
+ lpFeePercentage: 0,
284
+ // TODO: ?
285
+ lpFeeUsd: totalLpFeesUsd,
286
+ metadata: {
287
+ fromAmountBaseUnit: params.tradeType === "EXACT_INPUT" ? tokenAmountBaseUnit.toString() : relayQuote.details.currencyIn.amount ?? "0",
288
+ relayQuote,
289
+ toAmountBaseUnit: params.tradeType === "EXACT_INPUT" ? relayQuote.details.currencyOut.amount ?? "0" : tokenAmountBaseUnit.toString()
290
+ }
291
+ };
292
+ } catch (err) {
293
+ throw new Error(
294
+ `An error occurred trying to generate a relay quote: ${err instanceof Error ? err.message : JSON.stringify(err)}`
295
+ );
296
+ }
297
+ }
298
+ export {
299
+ FUN_RELAY_REFERRER,
300
+ FUN_RELAY_REVENUE_WALLET,
301
+ LogLevel,
302
+ computeFunRelayFeeBps,
303
+ executeRelayQuote,
304
+ getRelayClient,
305
+ getRelayExecutionInfo,
306
+ getRelayExecutionRefundState,
307
+ getRelayExecutionState,
308
+ getRelayQuote,
309
+ initializeRelayClient,
310
+ isRelayExecutionTerminalStatus,
311
+ parseRelayFees
312
+ };
313
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/client.ts", "../src/constants.ts", "../src/execution.ts", "../src/fees.ts", "../src/quote.ts", "../src/types.ts", "../src/utils.ts"],
4
+ "sourcesContent": ["import {\n MAINNET_RELAY_API,\n type RelayClient,\n type RelayClientOptions,\n convertViemChainToRelayChain,\n createClient,\n getClient,\n} from '@reservoir0x/relay-sdk'\nimport type { Chain } from 'viem'\nimport type { Logger } from './types'\n\nexport type InitializeRelayClientParams = Omit<\n RelayClientOptions,\n 'baseApiUrl' | 'chains' | 'logger'\n> & {\n chains: Chain[]\n logger: Logger\n}\n\n/**\n * Initializes a global instance of the RelayClient\n * https://docs.relay.link/references/sdk/createClient\n */\nexport function initializeRelayClient({\n chains,\n logger,\n ...options\n}: InitializeRelayClientParams): RelayClient {\n return createClient({\n ...options,\n baseApiUrl: MAINNET_RELAY_API,\n chains: chains.map(convertViemChainToRelayChain),\n logger: (message) => {\n logger.info('[RelayClient]:', message)\n },\n })\n}\n\n/**\n * Gets the global instance of the RelayClient\n */\nexport function getRelayClient(): RelayClient {\n const client = getClient()\n\n if (!client) {\n throw new Error('Relay client is not defined')\n }\n\n return client\n}\n", "import type { Address } from 'viem'\nimport type { RelayExecutionStatus } from './types'\n\n/**\n * Fake address for a chain's native currency used by Funkit\n */\nexport const FUNKIT_NATIVE_TOKEN =\n '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' satisfies Address\n\n/**\n * Fake address for a chain's native currency used by Relay\n */\nexport const RELAY_NATIVE_TOKEN =\n '0x0000000000000000000000000000000000000000' satisfies Address\n\n/**\n * Wallet that receives the app fees collected by Relay\n */\nexport const FUN_RELAY_REVENUE_WALLET =\n '0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E' satisfies Address\n\n/**\n * Referred field in Relay quote\n */\nexport const FUN_RELAY_REFERRER = 'funxyz'\n\n/**\n * Buffer added to Relay's time estimate (which sometimes is 0)\n */\nexport const RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3_000 // 3 seconds\n\nexport const RELAY_TERMINAL_STATUSES: RelayExecutionStatus[] = [\n 'refund',\n 'failure',\n 'success',\n]\n", "import {\n type Execute,\n MAINNET_RELAY_API,\n type ProgressData,\n} from '@reservoir0x/relay-sdk'\nimport type { Hex, WalletClient } from 'viem'\nimport { getRelayClient } from './client'\nimport type { Logger, RelayExecutionInfo } from './types'\n\nexport type RelayExecutionStep = ProgressData['currentStep'] & {}\n\nexport interface ExecuteRelayQuoteParams {\n logger: Logger\n onConfirmed: (txHash: Hex) => Promise<void>\n onError: (error: Error) => Promise<void>\n onProgress?: (step: RelayExecutionStep | null) => void\n relayQuote: Execute\n walletClient: WalletClient\n}\n\nexport async function executeRelayQuote({\n logger,\n onConfirmed,\n onError,\n onProgress,\n relayQuote,\n walletClient,\n}: ExecuteRelayQuoteParams) {\n await getRelayClient().actions.execute({\n quote: relayQuote,\n wallet: walletClient,\n onProgress: async ({\n steps,\n fees,\n breakdown,\n currentStep,\n currentStepItem,\n txHashes,\n details,\n error,\n }) => {\n const logPrefix = 'onRelayProgress'\n logger.info(`${logPrefix}:params`, {\n steps,\n currentStep,\n fees,\n breakdown,\n currentStepItem,\n txHashes,\n details,\n error,\n })\n\n onProgress?.(currentStep ?? null)\n\n if (error) {\n logger.info(`${logPrefix}:errorDetected`, error)\n await onError(error).catch((e) => {\n logger.error(`${logPrefix}:onErrorFailed`, e)\n })\n } else if (\n // We can redirect as soon as all the required user steps are done\n // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1748381169792379\n txHashes &&\n txHashes.length > 0 &&\n txHashes.length === steps.length\n ) {\n logger.info(`${logPrefix}:completed`, txHashes)\n // Can we assume its completed here?\n // Use first txHash as the main txHash in fun DE table\n await onConfirmed(txHashes[0].txHash as Hex).catch((e) => {\n logger.error(`${logPrefix}:onConfirmedFailed`, e)\n })\n }\n },\n })\n}\n\nexport async function getRelayExecutionInfo(\n requestId: string,\n): Promise<RelayExecutionInfo> {\n const url = `${MAINNET_RELAY_API}/intents/status/v2?requestId=${requestId}`\n const response = await fetch(url)\n if (!response.ok) {\n throw Error(response.statusText)\n }\n\n const data = await response.json()\n return data as RelayExecutionInfo\n}\n", "import type { CallFees } from '@reservoir0x/relay-sdk'\nimport type { Logger } from './types'\n\nexport function computeFunRelayFeeBps({\n isSameToken,\n}: {\n isSameToken: boolean\n}): number {\n // For now, we have a flat 2bps app fee for all relay transactions\n // TODO: Dynamic fee based on the transaction size, from token, to token, etc\n return isSameToken ? 0 : 2\n}\n\nexport function parseRelayFees({\n fees,\n logger,\n}: {\n fees: CallFees | undefined\n logger: Logger\n}) {\n // Gas fees, denominated in source chain native token\n const relayGasFeesUsd = Number.parseFloat(fees?.gas?.amountUsd || '0')\n\n // App fees, denominated in source chain token\n const funLpFeesUsd = Number.parseFloat(fees?.app?.amountUsd || '0')\n const funLpFeesFromAmount = Number.parseFloat(\n fees?.app?.amountFormatted || '0',\n )\n const funLpFeesFromAmountBaseUnit = BigInt(fees?.app?.amount || '0')\n\n // Relay fees, denominated in source chain token\n const relayLpFeesUsd =\n Number.parseFloat(fees?.relayer?.amountUsd || '0') +\n Number.parseFloat(fees?.relayerGas?.amountUsd || '0') +\n Number.parseFloat(fees?.relayerService?.amountUsd || '0')\n const relayLpFeesFromAmount =\n Number.parseFloat(fees?.relayer?.amountFormatted || '0') +\n Number.parseFloat(fees?.relayerGas?.amountFormatted || '0') +\n Number.parseFloat(fees?.relayerService?.amountFormatted || '0')\n const relayLpFeesFromAmountBaseUnit =\n BigInt(fees?.relayer?.amount || '0') +\n BigInt(fees?.relayerGas?.amount || '0') +\n BigInt(fees?.relayerService?.amount || '0')\n\n const totalLpFeesUsd = funLpFeesUsd + relayLpFeesUsd\n const totalLpFeesFromAmount = funLpFeesFromAmount + relayLpFeesFromAmount\n const totalLpFeesFromAmountBaseUnit =\n funLpFeesFromAmountBaseUnit + relayLpFeesFromAmountBaseUnit\n\n logger.info('parseRelayFees', {\n relayGasFeesUsd,\n funLpFeesUsd,\n funLpFeesFromAmount,\n funLpFeesFromAmountBaseUnit,\n relayLpFeesUsd,\n relayLpFeesFromAmount,\n relayLpFeesFromAmountBaseUnit,\n totalLpFeesUsd,\n totalLpFeesFromAmount,\n totalLpFeesFromAmountBaseUnit,\n })\n\n return {\n relayGasFeesUsd,\n totalLpFeesUsd,\n totalFeesUsd: relayGasFeesUsd + totalLpFeesUsd,\n totalFeesFromAmount: totalLpFeesFromAmount,\n totalFeesFromAmountBaseUnit: totalLpFeesFromAmountBaseUnit,\n }\n}\n", "import type { Execute, GetQuoteParameters } from '@reservoir0x/relay-sdk'\nimport { type Address, encodeFunctionData } from 'viem'\nimport { getRelayClient } from './client'\nimport {\n FUN_RELAY_REFERRER,\n FUN_RELAY_REVENUE_WALLET,\n RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,\n} from './constants'\nimport { computeFunRelayFeeBps, parseRelayFees } from './fees'\nimport type {\n ApiFunkitCheckoutActionParams,\n CheckoutQuoteResponse,\n Logger,\n} from './types'\nimport { convertFunToRelayTokenAddress } from './utils'\n\ntype RelayQuoteOptions = GetQuoteParameters['options'] & {}\n\nexport type GetRelayQuoteParams = {\n actionParams?: ApiFunkitCheckoutActionParams[]\n fromChainId: string\n fromTokenAddress: Address\n logger: Logger\n /**\n * {@link getRelayQuote} already sets {@link RelayQuoteOptions.appFees|appFees} and {@link RelayQuoteOptions.referrer|referrer}.\n * Only include them if you wish to override.\n */\n options?: RelayQuoteOptions\n recipientAddress: Address | undefined\n toChainId: string\n toTokenAddress: Address\n tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT'\n userAddress: Address | undefined\n} & (\n | {\n fromTokenAmountBaseUnit: bigint | string\n tradeType: 'EXACT_INPUT'\n }\n | {\n toTokenAmountBaseUnit: bigint | string\n tradeType: 'EXACT_OUTPUT'\n }\n)\n\nexport type RelayQuote = CheckoutQuoteResponse & {\n /** Required for EXACT_INPUT checkouts */\n finalToAmountBaseUnit: string\n metadata: {\n fromAmountBaseUnit: string\n relayQuote: Execute\n toAmountBaseUnit: string\n }\n}\n\nexport async function getRelayQuote({\n logger,\n ...params\n}: GetRelayQuoteParams): Promise<RelayQuote> {\n const {\n actionParams,\n fromChainId,\n fromTokenAddress,\n options,\n recipientAddress,\n toChainId,\n toTokenAddress,\n userAddress,\n } = params\n\n try {\n const relayClient = getRelayClient()\n\n const tokenAmountBaseUnit =\n params.tradeType === 'EXACT_INPUT'\n ? params.fromTokenAmountBaseUnit\n : params.toTokenAmountBaseUnit\n\n const txs = actionParams?.map((action) => {\n const data = encodeFunctionData({\n abi: action.contractAbi,\n args: action.functionArgs,\n functionName: action.functionName,\n })\n\n return {\n data,\n to: action.contractAddress,\n value: String(action.value ?? 0n),\n }\n })\n\n logger.info('getRelayQuoteParams', {\n ...params,\n tokenAmountBaseUnit,\n txs,\n })\n\n // Get the relay quote\n const relayQuote = await relayClient.actions.getQuote({\n chainId: Number(fromChainId),\n toChainId: Number(toChainId),\n currency: convertFunToRelayTokenAddress(fromTokenAddress),\n toCurrency: convertFunToRelayTokenAddress(toTokenAddress),\n amount: tokenAmountBaseUnit.toString(),\n recipient: recipientAddress,\n tradeType: params.tradeType,\n user: userAddress,\n ...(txs && { txs }),\n options: {\n referrer: FUN_RELAY_REFERRER,\n appFees: [\n {\n fee: computeFunRelayFeeBps({\n isSameToken:\n fromChainId === toChainId &&\n fromTokenAddress.toLowerCase() === toTokenAddress.toLowerCase(),\n }).toString(),\n recipient: FUN_RELAY_REVENUE_WALLET,\n },\n ],\n ...options,\n },\n })\n\n // TODO: Handling for no route response\n\n logger.info('relayQuote', relayQuote)\n\n const estSubtotalUsd = Number(\n relayQuote.details?.currencyOut?.amountUsd || 0,\n )\n const estTotalUsd = Number(relayQuote.details?.currencyIn?.amountUsd || 0)\n // Get how much fromAmount is needed for the quote\n const fromAmountString =\n relayQuote.details?.currencyIn?.amountFormatted || '0'\n const fromAmountBaseUnitString =\n relayQuote.details?.currencyIn?.amount || '0'\n\n // RequestID will be consistent across steps in the quote\n // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1747774944603209\n const relayRequestId = relayQuote.steps[0]?.requestId\n\n // TODO: Verify with relay team if this is possible?\n if (!relayRequestId) {\n throw new Error('Relay quote does not contain a requestId')\n }\n\n // TODO: Verify with relay team if this is possible?\n if (!relayQuote.details?.currencyIn || !relayQuote.details?.currencyOut) {\n throw new Error('Relay quote does not contain trade details')\n }\n\n const {\n relayGasFeesUsd,\n totalLpFeesUsd,\n totalFeesUsd,\n totalFeesFromAmount,\n totalFeesFromAmountBaseUnit,\n } = parseRelayFees({ fees: relayQuote.fees, logger })\n\n const estSubtotalFromAmount = (\n Number.parseFloat(fromAmountString) - totalFeesFromAmount\n ).toString()\n\n const estSubtotalFromAmountBaseUnit = (\n BigInt(fromAmountBaseUnitString) - totalFeesFromAmountBaseUnit\n ).toString()\n\n return {\n quoteId: relayRequestId,\n estCheckoutTimeMs:\n (relayQuote.details.timeEstimate || 0) * 1000 +\n RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,\n estFeesFromAmount: totalFeesFromAmount.toString(),\n estFeesFromAmountBaseUnit: totalFeesFromAmountBaseUnit.toString(),\n estFeesUsd: totalFeesUsd,\n estMarketMakerGasUsd: relayGasFeesUsd,\n estSubtotalFromAmount,\n estSubtotalFromAmountBaseUnit,\n estSubtotalUsd,\n estTotalFromAmount: fromAmountString,\n estTotalFromAmountBaseUnit: fromAmountBaseUnitString,\n estTotalUsd,\n finalToAmountBaseUnit: relayQuote.details.currencyOut.amount ?? '0', // TODO: Or do we want 'minimumAmount'?\n fromTokenAddress,\n lpFeePercentage: 0, // TODO: ?\n lpFeeUsd: totalLpFeesUsd,\n metadata: {\n fromAmountBaseUnit:\n params.tradeType === 'EXACT_INPUT'\n ? tokenAmountBaseUnit.toString()\n : (relayQuote.details.currencyIn.amount ?? '0'),\n relayQuote,\n toAmountBaseUnit:\n params.tradeType === 'EXACT_INPUT'\n ? (relayQuote.details.currencyOut.amount ?? '0')\n : tokenAmountBaseUnit.toString(),\n },\n }\n } catch (err) {\n throw new Error(\n `An error occurred trying to generate a relay quote: ${\n err instanceof Error ? err.message : JSON.stringify(err)\n }`,\n )\n }\n}\n", "import { LogLevel } from '@reservoir0x/relay-sdk'\nimport type { Abi, Address } from 'viem'\n\nexport { LogLevel }\n\nexport type RelayExecutionStatus =\n | 'refund'\n | 'delayed'\n | 'waiting'\n | 'failure'\n | 'pending'\n | 'success'\n\n// https://docs.relay.link/references/api/get-intents-status-v2\nexport interface RelayExecutionInfo {\n status: RelayExecutionStatus\n details: string\n /** Incoming transaction hashes */\n inTxHashes: string[]\n /** Outgoing transaction hashes */\n txHashes: string[]\n /** The last timestamp the data was updated in milliseconds */\n time: number\n originChainId: number\n destinationChainId: number\n}\n\n//// The types below are duplicated from @funkit/api-base atm, but this package should be used in BE as well\n//// TODO: Are we fine with BE importing @funkit/api-base and (by extension) @funkit/utils?\n//// See https://linear.app/funxyz/issue/PE-1342/sdk-extract-domainsrelayts-to-a-new-package#comment-d487d533\n\nexport interface Logger {\n error(message: string, data?: object): void\n info(message: string, data?: object): void\n}\n\nexport interface ApiFunkitCheckoutActionParams {\n contractAbi: Abi\n contractAddress: Address\n functionName: string\n functionArgs: unknown[]\n value?: bigint\n}\n\nexport enum CheckoutRefundState {\n INITIATED = 'INITIATED',\n ERROR = 'ERROR',\n REFUNDED = 'REFUNDED',\n PROCEEDED = 'PROCEEDED',\n WAITING_FOR_FULFILLMENT = 'WAITING_FOR_FULFILLMENT',\n FULFILLED = 'FULFILLED',\n}\n\n// Reference from api server: https://github.com/fun-xyz/fun-api-server/blob/main/src/tables/FunWalletCheckout.ts#L11C1-L21C2\nexport enum CheckoutState {\n // In-progress States\n FROM_UNFUNDED = 'FROM_UNFUNDED',\n FROM_FUNDED = 'FROM_FUNDED',\n FROM_POOLED = 'FROM_POOLED',\n TO_UNFUNDED = 'TO_UNFUNDED',\n TO_FUNDED = 'TO_FUNDED',\n TO_POOLED = 'TO_POOLED',\n TO_READY = 'TO_READY',\n PENDING_RECEIVAL = 'PENDING_RECEIVAL',\n // Terminal States\n COMPLETED = 'COMPLETED',\n CHECKOUT_ERROR = 'CHECKOUT_ERROR',\n EXPIRED = 'EXPIRED',\n CANCELLED = 'CANCELLED',\n}\n\n// The response of the actual /checkout/quote api\nexport type CheckoutApiQuoteResponse = {\n quoteId: string\n estTotalFromAmountBaseUnit: string\n estSubtotalFromAmountBaseUnit: string\n estFeesFromAmountBaseUnit: string\n fromTokenAddress: Address\n estFeesUsd: number\n estSubtotalUsd: number\n estTotalUsd: number\n estCheckoutTimeMs: number\n estMarketMakerGasUsd: number\n lpFeePercentage: number\n lpFeeUsd: number\n}\n\n// The formatted response quote interface from the core sdk\nexport type CheckoutQuoteResponse = CheckoutApiQuoteResponse & {\n estTotalFromAmount: string\n estSubtotalFromAmount: string\n estFeesFromAmount: string\n\n // Any additional fields purely for frontend use\n metadata?: { [key: string]: unknown }\n}\n", "import type { Address } from 'viem'\nimport {\n FUNKIT_NATIVE_TOKEN,\n RELAY_NATIVE_TOKEN,\n RELAY_TERMINAL_STATUSES,\n} from './constants'\nimport {\n CheckoutRefundState,\n CheckoutState,\n type RelayExecutionInfo,\n} from './types'\n\n/**\n * Converts a token address within Funkit the corresponding Relay token address.\n */\nexport function convertFunToRelayTokenAddress(address: Address): Address {\n if (address.toLowerCase() === FUNKIT_NATIVE_TOKEN.toLowerCase()) {\n return RELAY_NATIVE_TOKEN\n }\n\n return address\n}\n\nexport function getRelayExecutionRefundState(\n info: RelayExecutionInfo,\n): CheckoutRefundState | undefined {\n switch (info.status) {\n case 'refund':\n return CheckoutRefundState.REFUNDED\n default:\n return undefined\n }\n}\n\nexport function getRelayExecutionState(\n info: RelayExecutionInfo,\n): CheckoutState {\n switch (info.status) {\n case 'success':\n return CheckoutState.COMPLETED\n case 'failure':\n case 'refund':\n return CheckoutState.CHECKOUT_ERROR\n default:\n return CheckoutState.PENDING_RECEIVAL\n }\n}\n\n/**\n * Checks whether the Relay execution has reached a terminal status.\n */\nexport function isRelayExecutionTerminalStatus(\n info: RelayExecutionInfo,\n): boolean {\n return RELAY_TERMINAL_STATUSES.includes(info.status)\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["MAINNET_RELAY_API", "MAINNET_RELAY_API"]
7
+ }
@@ -1,14 +1,15 @@
1
- import { type Execute } from '@reservoir0x/relay-sdk';
1
+ import { type Execute, type ProgressData } from '@reservoir0x/relay-sdk';
2
2
  import type { Hex, WalletClient } from 'viem';
3
3
  import type { Logger, RelayExecutionInfo } from './types';
4
+ export type RelayExecutionStep = ProgressData['currentStep'] & {};
4
5
  export interface ExecuteRelayQuoteParams {
5
6
  logger: Logger;
6
7
  onConfirmed: (txHash: Hex) => Promise<void>;
7
8
  onError: (error: Error) => Promise<void>;
9
+ onProgress?: (step: RelayExecutionStep | null) => void;
8
10
  relayQuote: Execute;
9
- stepMessageSetter: (message: string) => void;
10
11
  walletClient: WalletClient;
11
12
  }
12
- export declare function executeRelayQuote({ logger, onConfirmed, onError, relayQuote, stepMessageSetter, walletClient, }: ExecuteRelayQuoteParams): Promise<void>;
13
+ export declare function executeRelayQuote({ logger, onConfirmed, onError, onProgress, relayQuote, walletClient, }: ExecuteRelayQuoteParams): Promise<void>;
13
14
  export declare function getRelayExecutionInfo(requestId: string): Promise<RelayExecutionInfo>;
14
15
  //# sourceMappingURL=execution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAqB,MAAM,wBAAwB,CAAA;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEzD,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,UAAU,EAAE,OAAO,CAAA;IACnB,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5C,YAAY,EAAE,YAAY,CAAA;CAC3B;AAGD,wBAAsB,iBAAiB,CAAC,EACtC,MAAM,EACN,WAAW,EACX,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,YAAY,GACb,EAAE,uBAAuB,iBAiDzB;AAED,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAS7B"}
1
+ {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/execution.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAEZ,KAAK,YAAY,EAClB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEzD,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,aAAa,CAAC,GAAG,EAAE,CAAA;AAEjE,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAA;IACtD,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,wBAAsB,iBAAiB,CAAC,EACtC,MAAM,EACN,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,YAAY,GACb,EAAE,uBAAuB,iBAiDzB;AAED,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAS7B"}
@@ -1,16 +1,38 @@
1
+ import type { Execute, GetQuoteParameters } from '@reservoir0x/relay-sdk';
1
2
  import { type Address } from 'viem';
2
3
  import type { ApiFunkitCheckoutActionParams, CheckoutQuoteResponse, Logger } from './types';
3
- export interface GetRelayQuoteParams {
4
+ type RelayQuoteOptions = GetQuoteParameters['options'] & {};
5
+ export type GetRelayQuoteParams = {
4
6
  actionParams?: ApiFunkitCheckoutActionParams[];
5
7
  fromChainId: string;
6
8
  fromTokenAddress: Address;
7
9
  logger: Logger;
10
+ /**
11
+ * {@link getRelayQuote} already sets {@link RelayQuoteOptions.appFees|appFees} and {@link RelayQuoteOptions.referrer|referrer}.
12
+ * Only include them if you wish to override.
13
+ */
14
+ options?: RelayQuoteOptions;
8
15
  recipientAddress: Address | undefined;
9
16
  toChainId: string;
10
17
  toTokenAddress: Address;
11
- toTokenAmount: number;
12
- toTokenDecimals: number;
18
+ tradeType: 'EXACT_INPUT' | 'EXACT_OUTPUT';
13
19
  userAddress: Address | undefined;
14
- }
15
- export declare function getRelayQuote({ actionParams, logger, toChainId, toTokenAddress, toTokenAmount, toTokenDecimals, fromChainId, fromTokenAddress, recipientAddress, userAddress, }: GetRelayQuoteParams): Promise<CheckoutQuoteResponse>;
20
+ } & ({
21
+ fromTokenAmountBaseUnit: bigint | string;
22
+ tradeType: 'EXACT_INPUT';
23
+ } | {
24
+ toTokenAmountBaseUnit: bigint | string;
25
+ tradeType: 'EXACT_OUTPUT';
26
+ });
27
+ export type RelayQuote = CheckoutQuoteResponse & {
28
+ /** Required for EXACT_INPUT checkouts */
29
+ finalToAmountBaseUnit: string;
30
+ metadata: {
31
+ fromAmountBaseUnit: string;
32
+ relayQuote: Execute;
33
+ toAmountBaseUnit: string;
34
+ };
35
+ };
36
+ export declare function getRelayQuote({ logger, ...params }: GetRelayQuoteParams): Promise<RelayQuote>;
37
+ export {};
16
38
  //# sourceMappingURL=quote.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../../src/quote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,MAAM,CAAA;AAQvD,OAAO,KAAK,EACV,6BAA6B,EAC7B,qBAAqB,EACrB,MAAM,EACP,MAAM,SAAS,CAAA;AAGhB,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAA;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,OAAO,CAAA;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,OAAO,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,OAAO,GAAG,SAAS,CAAA;CACjC;AAED,wBAAsB,aAAa,CAAC,EAClC,YAAY,EACZ,MAAM,EACN,SAAS,EACT,cAAc,EACd,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,GACZ,EAAE,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAqItD"}
1
+ {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../../src/quote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,MAAM,CAAA;AAQvD,OAAO,KAAK,EACV,6BAA6B,EAC7B,qBAAqB,EACrB,MAAM,EACP,MAAM,SAAS,CAAA;AAGhB,KAAK,iBAAiB,GAAG,kBAAkB,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA;AAE3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAA;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,OAAO,CAAA;IACzB,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,OAAO,CAAA;IACvB,SAAS,EAAE,aAAa,GAAG,cAAc,CAAA;IACzC,WAAW,EAAE,OAAO,GAAG,SAAS,CAAA;CACjC,GAAG,CACA;IACE,uBAAuB,EAAE,MAAM,GAAG,MAAM,CAAA;IACxC,SAAS,EAAE,aAAa,CAAA;CACzB,GACD;IACE,qBAAqB,EAAE,MAAM,GAAG,MAAM,CAAA;IACtC,SAAS,EAAE,cAAc,CAAA;CAC1B,CACJ,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,qBAAqB,GAAG;IAC/C,yCAAyC;IACzC,qBAAqB,EAAE,MAAM,CAAA;IAC7B,QAAQ,EAAE;QACR,kBAAkB,EAAE,MAAM,CAAA;QAC1B,UAAU,EAAE,OAAO,CAAA;QACnB,gBAAgB,EAAE,MAAM,CAAA;KACzB,CAAA;CACF,CAAA;AAED,wBAAsB,aAAa,CAAC,EAClC,MAAM,EACN,GAAG,MAAM,EACV,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqJ3C"}
@@ -16,7 +16,7 @@ export interface RelayExecutionInfo {
16
16
  }
17
17
  export interface Logger {
18
18
  error(message: string, data?: object): void;
19
- log(message: string, data?: object): void;
19
+ info(message: string, data?: object): void;
20
20
  }
21
21
  export interface ApiFunkitCheckoutActionParams {
22
22
  contractAbi: Abi;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAExC,OAAO,EAAE,QAAQ,EAAE,CAAA;AAEnB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,CAAA;AAGb,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,kCAAkC;IAClC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IACrB,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAMD,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1C;AAED,MAAM,WAAW,6BAA6B;IAC5C,WAAW,EAAE,GAAG,CAAA;IAChB,eAAe,EAAE,OAAO,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,OAAO,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,oBAAY,mBAAmB;IAC7B,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,SAAS,cAAc;IACvB,uBAAuB,4BAA4B;IACnD,SAAS,cAAc;CACxB;AAGD,oBAAY,aAAa;IAEvB,aAAa,kBAAkB;IAC/B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,QAAQ,aAAa;IACrB,gBAAgB,qBAAqB;IAErC,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,OAAO,YAAY;IACnB,SAAS,cAAc;CACxB;AAGD,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,MAAM,CAAA;IACf,0BAA0B,EAAE,MAAM,CAAA;IAClC,6BAA6B,EAAE,MAAM,CAAA;IACrC,yBAAyB,EAAE,MAAM,CAAA;IACjC,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAGD,MAAM,MAAM,qBAAqB,GAAG,wBAAwB,GAAG;IAC7D,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,iBAAiB,EAAE,MAAM,CAAA;IAGzB,QAAQ,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CACtC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAExC,OAAO,EAAE,QAAQ,EAAE,CAAA;AAEnB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,CAAA;AAGb,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,kCAAkC;IAClC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IACrB,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAMD,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3C;AAED,MAAM,WAAW,6BAA6B;IAC5C,WAAW,EAAE,GAAG,CAAA;IAChB,eAAe,EAAE,OAAO,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,OAAO,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,oBAAY,mBAAmB;IAC7B,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,SAAS,cAAc;IACvB,uBAAuB,4BAA4B;IACnD,SAAS,cAAc;CACxB;AAGD,oBAAY,aAAa;IAEvB,aAAa,kBAAkB;IAC/B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,QAAQ,aAAa;IACrB,gBAAgB,qBAAqB;IAErC,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,OAAO,YAAY;IACnB,SAAS,cAAc;CACxB;AAGD,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,MAAM,CAAA;IACf,0BAA0B,EAAE,MAAM,CAAA;IAClC,6BAA6B,EAAE,MAAM,CAAA;IACrC,yBAAyB,EAAE,MAAM,CAAA;IACjC,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAGD,MAAM,MAAM,qBAAqB,GAAG,wBAAwB,GAAG;IAC7D,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,iBAAiB,EAAE,MAAM,CAAA;IAGzB,QAAQ,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;CACtC,CAAA"}
package/package.json CHANGED
@@ -1,16 +1,24 @@
1
1
  {
2
2
  "name": "@funkit/fun-relay",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "files": [
5
5
  "dist/src",
6
6
  "dist/index.d.ts",
7
+ "dist/index.d.ts.map",
7
8
  "dist/index.js",
8
9
  "dist/index.js.map",
10
+ "dist/index.mjs",
11
+ "dist/index.mjs.map",
9
12
  "CHANGELOG.md"
10
13
  ],
11
14
  "main": "./dist/index.js",
12
15
  "module": "./dist/index.mjs",
13
16
  "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.js"
21
+ },
14
22
  "sideEffects": false,
15
23
  "engines": {
16
24
  "node": ">=18"