@funkit/fun-relay 0.1.0 → 0.1.1

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,11 @@
1
1
  # @funkit/fun-relay
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - bff34b2: chore: fix files config
8
+
3
9
  ## 0.1.0
4
10
 
5
11
  In development
@@ -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,KAAK,uBAAuB,EAC5B,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,KAAK,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACrE,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.mjs ADDED
@@ -0,0 +1,309 @@
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.log("[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/execution.ts
31
+ import { MAINNET_RELAY_API as MAINNET_RELAY_API2 } from "@reservoir0x/relay-sdk";
32
+ async function executeRelayQuote({
33
+ logger,
34
+ onConfirmed,
35
+ onError,
36
+ relayQuote,
37
+ stepMessageSetter,
38
+ walletClient
39
+ }) {
40
+ await getRelayClient().actions.execute({
41
+ quote: relayQuote,
42
+ wallet: walletClient,
43
+ onProgress: async ({
44
+ steps,
45
+ fees,
46
+ breakdown,
47
+ currentStep,
48
+ currentStepItem,
49
+ txHashes,
50
+ details,
51
+ error
52
+ }) => {
53
+ const logPrefix = "onRelayProgress";
54
+ logger.log(`${logPrefix}:params`, {
55
+ steps,
56
+ currentStep,
57
+ fees,
58
+ breakdown,
59
+ currentStepItem,
60
+ txHashes,
61
+ details,
62
+ error
63
+ });
64
+ stepMessageSetter(currentStep?.action ?? "");
65
+ if (error) {
66
+ logger.log(`${logPrefix}:errorDetected`, error);
67
+ await onError(error).catch((e) => {
68
+ logger.error(`${logPrefix}:onErrorFailed`, e);
69
+ });
70
+ } else if (
71
+ // We can redirect as soon as all the required user steps are done
72
+ // https://fun-xyz.slack.com/archives/C08MQ85QB2N/p1748381169792379
73
+ txHashes && txHashes.length > 0 && txHashes.length === steps.length
74
+ ) {
75
+ logger.log(`${logPrefix}:completed`, txHashes);
76
+ await onConfirmed(txHashes[0].txHash).catch((e) => {
77
+ logger.error(`${logPrefix}:onConfirmedFailed`, e);
78
+ });
79
+ }
80
+ }
81
+ });
82
+ }
83
+ async function getRelayExecutionInfo(requestId) {
84
+ const url = `${MAINNET_RELAY_API2}/intents/status/v2?requestId=${requestId}`;
85
+ const response = await fetch(url);
86
+ if (!response.ok) {
87
+ throw Error(response.statusText);
88
+ }
89
+ const data = await response.json();
90
+ return data;
91
+ }
92
+
93
+ // src/quote.ts
94
+ import { encodeFunctionData } from "viem";
95
+
96
+ // src/constants.ts
97
+ var FUNKIT_NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
98
+ var RELAY_NATIVE_TOKEN = "0x0000000000000000000000000000000000000000";
99
+ var FUN_RELAY_REVENUE_WALLET = "0xb61562d83aEC43a050A06BED12Ac2bD8f9BFfd5E";
100
+ var FUN_RELAY_REFERRER = "funxyz";
101
+ var RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS = 3e3;
102
+ var RELAY_TERMINAL_STATUSES = [
103
+ "refund",
104
+ "failure",
105
+ "success"
106
+ ];
107
+
108
+ // src/fees.ts
109
+ function computeFunRelayFeeBps({
110
+ isSameToken
111
+ }) {
112
+ return isSameToken ? 0 : 2;
113
+ }
114
+ function parseRelayFees({
115
+ fees,
116
+ logger
117
+ }) {
118
+ const relayGasFeesUsd = Number.parseFloat(fees?.gas?.amountUsd || "0");
119
+ const funLpFeesUsd = Number.parseFloat(fees?.app?.amountUsd || "0");
120
+ const funLpFeesFromAmount = Number.parseFloat(
121
+ fees?.app?.amountFormatted || "0"
122
+ );
123
+ const funLpFeesFromAmountBaseUnit = BigInt(fees?.app?.amount || "0");
124
+ const relayLpFeesUsd = Number.parseFloat(fees?.relayer?.amountUsd || "0") + Number.parseFloat(fees?.relayerGas?.amountUsd || "0") + Number.parseFloat(fees?.relayerService?.amountUsd || "0");
125
+ const relayLpFeesFromAmount = Number.parseFloat(fees?.relayer?.amountFormatted || "0") + Number.parseFloat(fees?.relayerGas?.amountFormatted || "0") + Number.parseFloat(fees?.relayerService?.amountFormatted || "0");
126
+ const relayLpFeesFromAmountBaseUnit = BigInt(fees?.relayer?.amount || "0") + BigInt(fees?.relayerGas?.amount || "0") + BigInt(fees?.relayerService?.amount || "0");
127
+ const totalLpFeesUsd = funLpFeesUsd + relayLpFeesUsd;
128
+ const totalLpFeesFromAmount = funLpFeesFromAmount + relayLpFeesFromAmount;
129
+ const totalLpFeesFromAmountBaseUnit = funLpFeesFromAmountBaseUnit + relayLpFeesFromAmountBaseUnit;
130
+ logger.log("parseRelayFees", {
131
+ relayGasFeesUsd,
132
+ funLpFeesUsd,
133
+ funLpFeesFromAmount,
134
+ funLpFeesFromAmountBaseUnit,
135
+ relayLpFeesUsd,
136
+ relayLpFeesFromAmount,
137
+ relayLpFeesFromAmountBaseUnit,
138
+ totalLpFeesUsd,
139
+ totalLpFeesFromAmount,
140
+ totalLpFeesFromAmountBaseUnit
141
+ });
142
+ return {
143
+ relayGasFeesUsd,
144
+ totalLpFeesUsd,
145
+ totalFeesUsd: relayGasFeesUsd + totalLpFeesUsd,
146
+ totalFeesFromAmount: totalLpFeesFromAmount,
147
+ totalFeesFromAmountBaseUnit: totalLpFeesFromAmountBaseUnit
148
+ };
149
+ }
150
+
151
+ // src/types.ts
152
+ import { LogLevel } from "@reservoir0x/relay-sdk";
153
+
154
+ // src/utils.ts
155
+ function convertFunToRelayTokenAddress(address) {
156
+ if (address.toLowerCase() === FUNKIT_NATIVE_TOKEN.toLowerCase()) {
157
+ return RELAY_NATIVE_TOKEN;
158
+ }
159
+ return address;
160
+ }
161
+ function getRelayExecutionRefundState(info) {
162
+ switch (info.status) {
163
+ case "refund":
164
+ return "REFUNDED" /* REFUNDED */;
165
+ default:
166
+ return void 0;
167
+ }
168
+ }
169
+ function getRelayExecutionState(info) {
170
+ switch (info.status) {
171
+ case "success":
172
+ return "COMPLETED" /* COMPLETED */;
173
+ case "failure":
174
+ case "refund":
175
+ return "CHECKOUT_ERROR" /* CHECKOUT_ERROR */;
176
+ default:
177
+ return "PENDING_RECEIVAL" /* PENDING_RECEIVAL */;
178
+ }
179
+ }
180
+ function isRelayExecutionTerminalStatus(info) {
181
+ return RELAY_TERMINAL_STATUSES.includes(info.status);
182
+ }
183
+
184
+ // src/quote.ts
185
+ async function getRelayQuote({
186
+ actionParams,
187
+ logger,
188
+ toChainId,
189
+ toTokenAddress,
190
+ toTokenAmount,
191
+ toTokenDecimals,
192
+ fromChainId,
193
+ fromTokenAddress,
194
+ recipientAddress,
195
+ userAddress
196
+ }) {
197
+ try {
198
+ const relayClient = getRelayClient();
199
+ const toMultipler = 10 ** toTokenDecimals;
200
+ const toAmountBaseUnitBI = BigInt(Math.floor(toTokenAmount * toMultipler));
201
+ const toAmountBaseUnitBIString = toAmountBaseUnitBI.toString();
202
+ const txs = actionParams?.map((action) => {
203
+ const data = encodeFunctionData({
204
+ abi: action.contractAbi,
205
+ args: action.functionArgs,
206
+ functionName: action.functionName
207
+ });
208
+ return {
209
+ data,
210
+ to: action.contractAddress,
211
+ value: String(action.value ?? 0n)
212
+ };
213
+ });
214
+ logger.log("getRelayQuoteParams", {
215
+ actionParams,
216
+ toChainId,
217
+ toTokenAddress,
218
+ toTokenAmount,
219
+ toTokenDecimals,
220
+ fromChainId,
221
+ fromTokenAddress,
222
+ recipientAddress,
223
+ userAddress,
224
+ relayClient,
225
+ toAmountBaseUnitBI: toAmountBaseUnitBIString,
226
+ txs
227
+ });
228
+ const relayQuote = await relayClient.actions.getQuote({
229
+ chainId: Number(fromChainId),
230
+ toChainId: Number(toChainId),
231
+ currency: convertFunToRelayTokenAddress(fromTokenAddress),
232
+ toCurrency: convertFunToRelayTokenAddress(toTokenAddress),
233
+ amount: toAmountBaseUnitBIString,
234
+ recipient: recipientAddress,
235
+ tradeType: "EXACT_OUTPUT",
236
+ user: userAddress,
237
+ ...txs && { txs },
238
+ options: {
239
+ referrer: FUN_RELAY_REFERRER,
240
+ appFees: [
241
+ {
242
+ fee: computeFunRelayFeeBps({
243
+ isSameToken: fromChainId === toChainId && fromTokenAddress.toLowerCase() === toTokenAddress.toLowerCase()
244
+ }).toString(),
245
+ recipient: FUN_RELAY_REVENUE_WALLET
246
+ }
247
+ ]
248
+ }
249
+ });
250
+ logger.log("relayQuote", relayQuote);
251
+ const estSubtotalUsd = Number(
252
+ relayQuote.details?.currencyOut?.amountUsd || 0
253
+ );
254
+ const estTotalUsd = Number(relayQuote.details?.currencyIn?.amountUsd || 0);
255
+ const fromAmountString = relayQuote.details?.currencyIn?.amountFormatted || "0";
256
+ const fromAmountBaseUnitString = relayQuote.details?.currencyIn?.amount || "0";
257
+ const relayRequestId = relayQuote.steps[0]?.requestId;
258
+ if (!relayRequestId) {
259
+ throw new Error("Relay quote does not contain a requestId");
260
+ }
261
+ const {
262
+ relayGasFeesUsd,
263
+ totalLpFeesUsd,
264
+ totalFeesUsd,
265
+ totalFeesFromAmount,
266
+ totalFeesFromAmountBaseUnit
267
+ } = parseRelayFees({ fees: relayQuote.fees, logger });
268
+ const estSubtotalFromAmount = (Number.parseFloat(fromAmountString) - totalFeesFromAmount).toString();
269
+ const estSubtotalFromAmountBaseUnit = (BigInt(fromAmountBaseUnitString) - totalFeesFromAmountBaseUnit).toString();
270
+ return {
271
+ quoteId: relayRequestId,
272
+ estTotalFromAmount: fromAmountString,
273
+ estSubtotalFromAmount,
274
+ estTotalFromAmountBaseUnit: fromAmountBaseUnitString,
275
+ estSubtotalFromAmountBaseUnit,
276
+ estFeesFromAmount: totalFeesFromAmount.toString(),
277
+ estFeesFromAmountBaseUnit: totalFeesFromAmountBaseUnit.toString(),
278
+ fromTokenAddress,
279
+ estFeesUsd: totalFeesUsd,
280
+ estSubtotalUsd,
281
+ estTotalUsd,
282
+ estCheckoutTimeMs: (relayQuote.details?.timeEstimate || 0) * 1e3 + RELAY_QUOTE_CHECKOUT_TIME_BUFFER_MS,
283
+ estMarketMakerGasUsd: relayGasFeesUsd,
284
+ lpFeePercentage: 0,
285
+ // TODO: ?
286
+ lpFeeUsd: totalLpFeesUsd,
287
+ metadata: {
288
+ relayQuote,
289
+ toAmountBaseUnit: toAmountBaseUnitBIString
290
+ }
291
+ };
292
+ } catch (err) {
293
+ throw new Error(
294
+ `An error occured trying to generate a relay quote: ${err instanceof Error ? err.message : JSON.stringify(err)}`
295
+ );
296
+ }
297
+ }
298
+ export {
299
+ LogLevel,
300
+ executeRelayQuote,
301
+ getRelayClient,
302
+ getRelayExecutionInfo,
303
+ getRelayExecutionRefundState,
304
+ getRelayExecutionState,
305
+ getRelayQuote,
306
+ initializeRelayClient,
307
+ isRelayExecutionTerminalStatus
308
+ };
309
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/client.ts", "../src/execution.ts", "../src/quote.ts", "../src/constants.ts", "../src/fees.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.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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",
6
+ "names": ["MAINNET_RELAY_API", "MAINNET_RELAY_API"]
7
+ }
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@funkit/fun-relay",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",