@metamask/transaction-pay-controller 4.0.0 → 5.0.0

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/TransactionPayController.cjs +6 -3
  3. package/dist/TransactionPayController.cjs.map +1 -1
  4. package/dist/TransactionPayController.d.cts +1 -1
  5. package/dist/TransactionPayController.d.cts.map +1 -1
  6. package/dist/TransactionPayController.d.mts +1 -1
  7. package/dist/TransactionPayController.d.mts.map +1 -1
  8. package/dist/TransactionPayController.mjs +6 -3
  9. package/dist/TransactionPayController.mjs.map +1 -1
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +1 -1
  12. package/dist/index.d.cts.map +1 -1
  13. package/dist/index.d.mts +1 -1
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/strategy/bridge/bridge-quotes.cjs.map +1 -1
  17. package/dist/strategy/bridge/bridge-quotes.mjs.map +1 -1
  18. package/dist/strategy/relay/constants.cjs +3 -1
  19. package/dist/strategy/relay/constants.cjs.map +1 -1
  20. package/dist/strategy/relay/constants.d.cts +2 -0
  21. package/dist/strategy/relay/constants.d.cts.map +1 -1
  22. package/dist/strategy/relay/constants.d.mts +2 -0
  23. package/dist/strategy/relay/constants.d.mts.map +1 -1
  24. package/dist/strategy/relay/constants.mjs +2 -0
  25. package/dist/strategy/relay/constants.mjs.map +1 -1
  26. package/dist/strategy/relay/relay-quotes.cjs +65 -25
  27. package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
  28. package/dist/strategy/relay/relay-quotes.d.cts.map +1 -1
  29. package/dist/strategy/relay/relay-quotes.d.mts.map +1 -1
  30. package/dist/strategy/relay/relay-quotes.mjs +68 -28
  31. package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
  32. package/dist/strategy/relay/relay-submit.cjs +29 -32
  33. package/dist/strategy/relay/relay-submit.cjs.map +1 -1
  34. package/dist/strategy/relay/relay-submit.d.cts.map +1 -1
  35. package/dist/strategy/relay/relay-submit.d.mts.map +1 -1
  36. package/dist/strategy/relay/relay-submit.mjs +30 -33
  37. package/dist/strategy/relay/relay-submit.mjs.map +1 -1
  38. package/dist/strategy/relay/types.cjs.map +1 -1
  39. package/dist/strategy/relay/types.d.cts +7 -2
  40. package/dist/strategy/relay/types.d.cts.map +1 -1
  41. package/dist/strategy/relay/types.d.mts +7 -2
  42. package/dist/strategy/relay/types.d.mts.map +1 -1
  43. package/dist/strategy/relay/types.mjs.map +1 -1
  44. package/dist/tests/messenger-mock.cjs +3 -0
  45. package/dist/tests/messenger-mock.cjs.map +1 -1
  46. package/dist/tests/messenger-mock.d.cts +20 -22
  47. package/dist/tests/messenger-mock.d.cts.map +1 -1
  48. package/dist/tests/messenger-mock.d.mts +20 -22
  49. package/dist/tests/messenger-mock.d.mts.map +1 -1
  50. package/dist/tests/messenger-mock.mjs +3 -0
  51. package/dist/tests/messenger-mock.mjs.map +1 -1
  52. package/dist/types.cjs.map +1 -1
  53. package/dist/types.d.cts +17 -2
  54. package/dist/types.d.cts.map +1 -1
  55. package/dist/types.d.mts +17 -2
  56. package/dist/types.d.mts.map +1 -1
  57. package/dist/types.mjs.map +1 -1
  58. package/dist/utils/totals.cjs +1 -1
  59. package/dist/utils/totals.cjs.map +1 -1
  60. package/dist/utils/totals.d.cts.map +1 -1
  61. package/dist/utils/totals.d.mts.map +1 -1
  62. package/dist/utils/totals.mjs +1 -1
  63. package/dist/utils/totals.mjs.map +1 -1
  64. package/package.json +2 -2
@@ -1,7 +1,9 @@
1
1
  export declare const ARBITRUM_USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
2
2
  export declare const CHAIN_ID_ARBITRUM = "0xa4b1";
3
3
  export declare const CHAIN_ID_POLYGON = "0x89";
4
+ export declare const CHAIN_ID_HYPERCORE = "0x539";
4
5
  export declare const RELAY_URL_BASE = "https://api.relay.link";
5
6
  export declare const RELAY_URL_QUOTE = "https://api.relay.link/quote";
6
7
  export declare const RELAY_FALLBACK_GAS_LIMIT = 900000;
8
+ export declare const RELAY_POLLING_INTERVAL = 1000;
7
9
  //# sourceMappingURL=constants.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+CACY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,eAAe,iCAA4B,CAAC;AACzD,eAAO,MAAM,wBAAwB,SAAS,CAAC"}
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+CACY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,eAAe,iCAA4B,CAAC;AACzD,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAC/C,eAAO,MAAM,sBAAsB,OAAO,CAAC"}
@@ -1,7 +1,9 @@
1
1
  export declare const ARBITRUM_USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
2
2
  export declare const CHAIN_ID_ARBITRUM = "0xa4b1";
3
3
  export declare const CHAIN_ID_POLYGON = "0x89";
4
+ export declare const CHAIN_ID_HYPERCORE = "0x539";
4
5
  export declare const RELAY_URL_BASE = "https://api.relay.link";
5
6
  export declare const RELAY_URL_QUOTE = "https://api.relay.link/quote";
6
7
  export declare const RELAY_FALLBACK_GAS_LIMIT = 900000;
8
+ export declare const RELAY_POLLING_INTERVAL = 1000;
7
9
  //# sourceMappingURL=constants.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+CACY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,eAAe,iCAA4B,CAAC;AACzD,eAAO,MAAM,wBAAwB,SAAS,CAAC"}
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+CACY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,eAAe,iCAA4B,CAAC;AACzD,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAC/C,eAAO,MAAM,sBAAsB,OAAO,CAAC"}
@@ -1,7 +1,9 @@
1
1
  export const ARBITRUM_USDC_ADDRESS = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
2
2
  export const CHAIN_ID_ARBITRUM = '0xa4b1';
3
3
  export const CHAIN_ID_POLYGON = '0x89';
4
+ export const CHAIN_ID_HYPERCORE = '0x539';
4
5
  export const RELAY_URL_BASE = 'https://api.relay.link';
5
6
  export const RELAY_URL_QUOTE = `${RELAY_URL_BASE}/quote`;
6
7
  export const RELAY_FALLBACK_GAS_LIMIT = 900000;
8
+ export const RELAY_POLLING_INTERVAL = 1000; // 1 Second
7
9
  //# sourceMappingURL=constants.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAChC,4CAA4C,CAAC;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,cAAc,QAAQ,CAAC;AACzD,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC","sourcesContent":["export const ARBITRUM_USDC_ADDRESS =\n '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';\nexport const CHAIN_ID_ARBITRUM = '0xa4b1';\nexport const CHAIN_ID_POLYGON = '0x89';\nexport const RELAY_URL_BASE = 'https://api.relay.link';\nexport const RELAY_URL_QUOTE = `${RELAY_URL_BASE}/quote`;\nexport const RELAY_FALLBACK_GAS_LIMIT = 900000;\n"]}
1
+ {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAChC,4CAA4C,CAAC;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAC1C,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,cAAc,QAAQ,CAAC;AACzD,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC,CAAC,WAAW","sourcesContent":["export const ARBITRUM_USDC_ADDRESS =\n '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';\nexport const CHAIN_ID_ARBITRUM = '0xa4b1';\nexport const CHAIN_ID_POLYGON = '0x89';\nexport const CHAIN_ID_HYPERCORE = '0x539';\nexport const RELAY_URL_BASE = 'https://api.relay.link';\nexport const RELAY_URL_QUOTE = `${RELAY_URL_BASE}/quote`;\nexport const RELAY_FALLBACK_GAS_LIMIT = 900000;\nexport const RELAY_POLLING_INTERVAL = 1000; // 1 Second\n"]}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getRelayQuotes = void 0;
4
+ const abi_1 = require("@ethersproject/abi");
4
5
  const controller_utils_1 = require("@metamask/controller-utils");
5
6
  const utils_1 = require("@metamask/utils");
6
7
  const bignumber_js_1 = require("bignumber.js");
@@ -21,14 +22,12 @@ async function getRelayQuotes(request) {
21
22
  const { requests } = request;
22
23
  log('Fetching quotes', requests);
23
24
  try {
24
- const result = requests
25
+ const normalizedRequests = requests
25
26
  // Ignore gas fee token requests
26
27
  .filter((r) => r.targetAmountMinimum !== '0')
27
28
  .map((r) => normalizeRequest(r));
28
- const normalizedRequests = result.map((r) => r.request);
29
- const isSkipTransaction = result.some((r) => r.isSkipTransaction);
30
- log('Normalized requests', { normalizedRequests, isSkipTransaction });
31
- return await Promise.all(normalizedRequests.map((r) => getSingleQuote(r, isSkipTransaction, request)));
29
+ log('Normalized requests', normalizedRequests);
30
+ return await Promise.all(normalizedRequests.map((r) => getSingleQuote(r, request)));
32
31
  }
33
32
  catch (error) {
34
33
  log('Error fetching quotes', { error });
@@ -40,12 +39,11 @@ exports.getRelayQuotes = getRelayQuotes;
40
39
  * Fetches a single Relay quote.
41
40
  *
42
41
  * @param request - Quote request.
43
- * @param isSkipTransaction - Whether to skip the transaction.
44
42
  * @param fullRequest - Full quotes request.
45
43
  * @returns Single quote.
46
44
  */
47
- async function getSingleQuote(request, isSkipTransaction, fullRequest) {
48
- const { messenger } = fullRequest;
45
+ async function getSingleQuote(request, fullRequest) {
46
+ const { messenger, transaction } = fullRequest;
49
47
  try {
50
48
  const body = {
51
49
  amount: request.targetAmountMinimum,
@@ -57,15 +55,16 @@ async function getSingleQuote(request, isSkipTransaction, fullRequest) {
57
55
  tradeType: 'EXPECTED_OUTPUT',
58
56
  user: request.from,
59
57
  };
58
+ await processTransactions(transaction, request, body, messenger);
60
59
  const url = getFeatureFlags(messenger).relayQuoteUrl;
60
+ log('Request body', { body, url });
61
61
  const response = await (0, controller_utils_1.successfulFetch)(url, {
62
62
  method: 'POST',
63
63
  headers: { 'Content-Type': 'application/json' },
64
64
  body: JSON.stringify(body),
65
65
  });
66
66
  const quote = (await response.json());
67
- quote.skipTransaction = isSkipTransaction;
68
- log('Fetched relay quote', { quote, url });
67
+ log('Fetched relay quote', quote);
69
68
  return normalizeQuote(quote, request, fullRequest);
70
69
  }
71
70
  catch (e) {
@@ -73,6 +72,51 @@ async function getSingleQuote(request, isSkipTransaction, fullRequest) {
73
72
  throw e;
74
73
  }
75
74
  }
75
+ /**
76
+ * Add tranasction data to request body if needed.
77
+ *
78
+ * @param transaction - Transaction metadata.
79
+ * @param request - Quote request.
80
+ * @param requestBody - Request body to populate.
81
+ * @param messenger - Controller messenger.
82
+ */
83
+ async function processTransactions(transaction, request, requestBody, messenger) {
84
+ const { data, value } = transaction.txParams;
85
+ /* istanbul ignore next */
86
+ const hasNoParams = (!data || data === '0x') && (!value || value === '0x0');
87
+ const skipDelegation = hasNoParams || request.targetChainId === constants_1.CHAIN_ID_HYPERCORE;
88
+ if (skipDelegation) {
89
+ log('Skipping delegation as no transaction data');
90
+ return;
91
+ }
92
+ const delegation = await messenger.call('TransactionPayController:getDelegationTransaction', { transaction });
93
+ const normalizedAuthorizationList = delegation.authorizationList?.map((a) => ({
94
+ ...a,
95
+ chainId: Number(a.chainId),
96
+ nonce: Number(a.nonce),
97
+ yParity: Number(a.yParity),
98
+ }));
99
+ const tokenTransferData = new abi_1.Interface([
100
+ 'function transfer(address to, uint256 amount)',
101
+ ]).encodeFunctionData('transfer', [
102
+ request.from,
103
+ request.targetAmountMinimum,
104
+ ]);
105
+ requestBody.authorizationList = normalizedAuthorizationList;
106
+ requestBody.tradeType = 'EXACT_OUTPUT';
107
+ requestBody.txs = [
108
+ {
109
+ to: request.targetTokenAddress,
110
+ data: tokenTransferData,
111
+ value: '0x0',
112
+ },
113
+ {
114
+ to: delegation.to,
115
+ data: delegation.data,
116
+ value: delegation.value,
117
+ },
118
+ ];
119
+ }
76
120
  /**
77
121
  * Normalizes requests for Relay.
78
122
  *
@@ -90,7 +134,9 @@ function normalizeRequest(request) {
90
134
  sourceTokenAddress: isPolygonNativeSource
91
135
  ? constants_2.NATIVE_TOKEN_ADDRESS
92
136
  : request.sourceTokenAddress,
93
- targetChainId: isHyperliquidDeposit ? (0, controller_utils_1.toHex)(1337) : request.targetChainId,
137
+ targetChainId: isHyperliquidDeposit
138
+ ? constants_1.CHAIN_ID_HYPERCORE
139
+ : request.targetChainId,
94
140
  targetTokenAddress: isHyperliquidDeposit
95
141
  ? '0x00000000000000000000000000000000'
96
142
  : request.targetTokenAddress,
@@ -104,10 +150,7 @@ function normalizeRequest(request) {
104
150
  normalizedRequest: requestOutput,
105
151
  });
106
152
  }
107
- return {
108
- request: requestOutput,
109
- isSkipTransaction: isHyperliquidDeposit,
110
- };
153
+ return requestOutput;
111
154
  }
112
155
  /**
113
156
  * Normalizes a Relay quote into a TransactionPayQuote.
@@ -118,19 +161,16 @@ function normalizeRequest(request) {
118
161
  * @returns Normalized quote.
119
162
  */
120
163
  function normalizeQuote(quote, request, fullRequest) {
121
- const { messenger, transaction } = fullRequest;
122
- const { details } = quote;
123
- const { currencyIn, currencyOut } = details;
164
+ const { messenger } = fullRequest;
165
+ const { details, fees } = quote;
124
166
  const { usdToFiatRate } = getFiatRates(messenger, request);
125
167
  const dust = getFiatValueFromUsd(calculateDustUsd(quote, request), usdToFiatRate);
126
- const provider = getFiatValueFromUsd(new bignumber_js_1.BigNumber(currencyIn.amountUsd).minus(currencyOut.amountUsd), usdToFiatRate);
168
+ const provider = getFiatValueFromUsd(new bignumber_js_1.BigNumber(fees.relayer.amountUsd), usdToFiatRate);
127
169
  const sourceNetwork = calculateSourceNetworkCost(quote, messenger);
128
- const targetNetwork = quote.skipTransaction
129
- ? {
130
- usd: '0',
131
- fiat: '0',
132
- }
133
- : (0, gas_1.calculateTransactionGasCost)(transaction, messenger);
170
+ const targetNetwork = {
171
+ usd: '0',
172
+ fiat: '0',
173
+ };
134
174
  return {
135
175
  dust,
136
176
  estimatedDuration: details.timeEstimate,
@@ -1 +1 @@
1
- {"version":3,"file":"relay-quotes.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { successfulFetch, toHex } from '@metamask/controller-utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_POLYGON,\n RELAY_FALLBACK_GAS_LIMIT,\n RELAY_URL_QUOTE,\n} from './constants';\nimport type { RelayQuote } from './types';\nimport { TransactionPayStrategy } from '../..';\nimport { NATIVE_TOKEN_ADDRESS } from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n FiatValue,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { calculateGasCost, calculateTransactionGasCost } from '../../utils/gas';\nimport { getNativeToken, getTokenFiatRate } from '../../utils/token';\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Fetches Relay quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getRelayQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const result = requests\n // Ignore gas fee token requests\n .filter((r) => r.targetAmountMinimum !== '0')\n .map((r) => normalizeRequest(r));\n\n const normalizedRequests = result.map((r) => r.request);\n const isSkipTransaction = result.some((r) => r.isSkipTransaction);\n\n log('Normalized requests', { normalizedRequests, isSkipTransaction });\n\n return await Promise.all(\n normalizedRequests.map((r) =>\n getSingleQuote(r, isSkipTransaction, request),\n ),\n );\n } catch (error) {\n log('Error fetching quotes', { error });\n throw new Error(`Failed to fetch Relay quotes: ${String(error)}`);\n }\n}\n\n/**\n * Fetches a single Relay quote.\n *\n * @param request - Quote request.\n * @param isSkipTransaction - Whether to skip the transaction.\n * @param fullRequest - Full quotes request.\n * @returns Single quote.\n */\nasync function getSingleQuote(\n request: QuoteRequest,\n isSkipTransaction: boolean,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n\n try {\n const body = {\n amount: request.targetAmountMinimum,\n destinationChainId: Number(request.targetChainId),\n destinationCurrency: request.targetTokenAddress,\n originChainId: Number(request.sourceChainId),\n originCurrency: request.sourceTokenAddress,\n recipient: request.from,\n tradeType: 'EXPECTED_OUTPUT',\n user: request.from,\n };\n\n const url = getFeatureFlags(messenger).relayQuoteUrl;\n\n const response = await successfulFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const quote = (await response.json()) as RelayQuote;\n quote.skipTransaction = isSkipTransaction;\n\n log('Fetched relay quote', { quote, url });\n\n return normalizeQuote(quote, request, fullRequest);\n } catch (e) {\n log('Error fetching relay quote', e);\n throw e;\n }\n}\n\n/**\n * Normalizes requests for Relay.\n *\n * @param request - Quote request to normalize.\n * @returns Normalized request.\n */\nfunction normalizeRequest(request: QuoteRequest) {\n const isHyperliquidDeposit =\n request.targetChainId === CHAIN_ID_ARBITRUM &&\n request.targetTokenAddress.toLowerCase() ===\n ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n const isPolygonNativeSource =\n request.sourceChainId === CHAIN_ID_POLYGON &&\n request.sourceTokenAddress === getNativeToken(request.sourceChainId);\n\n const requestOutput: QuoteRequest = {\n ...request,\n sourceTokenAddress: isPolygonNativeSource\n ? NATIVE_TOKEN_ADDRESS\n : request.sourceTokenAddress,\n targetChainId: isHyperliquidDeposit ? toHex(1337) : request.targetChainId,\n targetTokenAddress: isHyperliquidDeposit\n ? '0x00000000000000000000000000000000'\n : request.targetTokenAddress,\n targetAmountMinimum: isHyperliquidDeposit\n ? new BigNumber(request.targetAmountMinimum).shiftedBy(2).toString(10)\n : request.targetAmountMinimum,\n };\n\n if (isHyperliquidDeposit) {\n log('Converting Arbitrum Hyperliquid deposit to direct deposit', {\n originalRequest: request,\n normalizedRequest: requestOutput,\n });\n }\n\n return {\n request: requestOutput,\n isSkipTransaction: isHyperliquidDeposit,\n };\n}\n\n/**\n * Normalizes a Relay quote into a TransactionPayQuote.\n *\n * @param quote - Relay quote.\n * @param request - Original quote request.\n * @param fullRequest - Full quotes request.\n * @returns Normalized quote.\n */\nfunction normalizeQuote(\n quote: RelayQuote,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): TransactionPayQuote<RelayQuote> {\n const { messenger, transaction } = fullRequest;\n const { details } = quote;\n const { currencyIn, currencyOut } = details;\n\n const { usdToFiatRate } = getFiatRates(messenger, request);\n\n const dust = getFiatValueFromUsd(\n calculateDustUsd(quote, request),\n usdToFiatRate,\n );\n\n const provider = getFiatValueFromUsd(\n new BigNumber(currencyIn.amountUsd).minus(currencyOut.amountUsd),\n usdToFiatRate,\n );\n\n const sourceNetwork = calculateSourceNetworkCost(quote, messenger);\n\n const targetNetwork = quote.skipTransaction\n ? {\n usd: '0',\n fiat: '0',\n }\n : calculateTransactionGasCost(transaction, messenger);\n\n return {\n dust,\n estimatedDuration: details.timeEstimate,\n fees: {\n provider,\n sourceNetwork,\n targetNetwork,\n },\n original: quote,\n request,\n strategy: TransactionPayStrategy.Relay,\n };\n}\n\n/**\n * Calculate dust USD value.\n *\n * @param quote - Relay quote.\n * @param request - Quote request.\n * @returns Dust value in USD and fiat.\n */\nfunction calculateDustUsd(quote: RelayQuote, request: QuoteRequest) {\n const { currencyOut } = quote.details;\n const { amountUsd, amountFormatted, minimumAmount } = currencyOut;\n const { decimals: targetDecimals } = currencyOut.currency;\n\n const targetUsdRate = new BigNumber(amountUsd).dividedBy(amountFormatted);\n\n const dustRaw = new BigNumber(minimumAmount).minus(\n request.targetAmountMinimum,\n );\n\n return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);\n}\n\n/**\n * Converts USD value to fiat value.\n *\n * @param usdValue - USD value.\n * @param usdToFiatRate - USD to fiat rate.\n * @returns Fiat value.\n */\nfunction getFiatValueFromUsd(\n usdValue: BigNumber,\n usdToFiatRate: BigNumber,\n): FiatValue {\n const fiatValue = usdValue.multipliedBy(usdToFiatRate);\n\n return {\n usd: usdValue.toString(10),\n fiat: fiatValue.toString(10),\n };\n}\n\n/**\n * Calculates USD to fiat rate.\n *\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @returns USD to fiat rate.\n */\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n) {\n const { sourceChainId, sourceTokenAddress } = request;\n\n const finalSourceTokenAddress =\n sourceChainId === CHAIN_ID_POLYGON &&\n sourceTokenAddress === NATIVE_TOKEN_ADDRESS\n ? getNativeToken(sourceChainId)\n : sourceTokenAddress;\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n finalSourceTokenAddress,\n sourceChainId,\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, usdToFiatRate };\n}\n\n/**\n * Gets feature flags for Relay quotes.\n *\n * @param messenger - Controller messenger.\n * @returns Feature flags.\n */\nfunction getFeatureFlags(messenger: TransactionPayControllerMessenger) {\n const featureFlagState = messenger.call(\n 'RemoteFeatureFlagController:getState',\n );\n\n const featureFlags = featureFlagState.remoteFeatureFlags\n ?.confirmations_pay as Record<string, string> | undefined;\n\n const relayQuoteUrl = featureFlags?.relayQuoteUrl ?? RELAY_URL_QUOTE;\n\n return {\n relayQuoteUrl,\n };\n}\n\n/**\n * Calculates source network cost from a Relay quote.\n *\n * @param quote - Relay quote.\n * @param messenger - Controller messenger.\n * @returns Total source network cost in USD and fiat.\n */\nfunction calculateSourceNetworkCost(\n quote: RelayQuote,\n messenger: TransactionPayControllerMessenger,\n) {\n const allParams = quote.steps[0].items.map((i) => i.data);\n const totalGasLimit = calculateSourceNetworkGasLimit(allParams);\n\n return calculateGasCost({\n chainId: allParams[0].chainId,\n gas: totalGasLimit,\n messenger,\n });\n}\n\n/**\n * Calculate the total gas limit for the source network transactions.\n *\n * @param params - Array of transaction parameters.\n * @returns - Total gas limit.\n */\nfunction calculateSourceNetworkGasLimit(\n params: RelayQuote['steps'][0]['items'][0]['data'][],\n): number {\n const allParamsHasGas = params.every((p) => p.gas !== undefined);\n\n if (allParamsHasGas) {\n return params.reduce(\n (total, p) => total + new BigNumber(p.gas as string).toNumber(),\n 0,\n );\n }\n\n // In future, call `TransactionController:estimateGas`\n // or `TransactionController:estimateGasBatch` based on params length.\n\n return params.reduce(\n (total, p) =>\n total + new BigNumber(p.gas ?? RELAY_FALLBACK_GAS_LIMIT).toNumber(),\n 0,\n );\n}\n"]}
1
+ {"version":3,"file":"relay-quotes.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":";;;AAAA,4CAA+C;AAC/C,iEAA6D;AAE7D,2CAAqD;AACrD,+CAAyC;AAEzC,+CAOqB;AAErB,uCAA+C;AAE/C,mDAAuD;AACvD,6CAA6C;AAQ7C,6CAAmD;AACnD,iDAAqE;AAErE,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,gBAAgB,CAAC,CAAC;AAEhE;;;;;GAKG;AACI,KAAK,UAAU,cAAc,CAClC,OAAoC;IAEpC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAE7B,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAEjC,IAAI,CAAC;QACH,MAAM,kBAAkB,GAAG,QAAQ;YACjC,gCAAgC;aAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,mBAAmB,KAAK,GAAG,CAAC;aAC5C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnC,GAAG,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAAC;QAE/C,OAAO,MAAM,OAAO,CAAC,GAAG,CACtB,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAC1D,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,iCAAiC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAtBD,wCAsBC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,cAAc,CAC3B,OAAqB,EACrB,WAAwC;IAExC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG;YACX,MAAM,EAAE,OAAO,CAAC,mBAAmB;YACnC,kBAAkB,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;YACjD,mBAAmB,EAAE,OAAO,CAAC,kBAAkB;YAC/C,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;YAC5C,cAAc,EAAE,OAAO,CAAC,kBAAkB;YAC1C,SAAS,EAAE,OAAO,CAAC,IAAI;YACvB,SAAS,EAAE,iBAAiB;YAC5B,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC;QAEF,MAAM,mBAAmB,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QAEjE,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC;QAErD,GAAG,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAEnC,MAAM,QAAQ,GAAG,MAAM,IAAA,kCAAe,EAAC,GAAG,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAe,CAAC;QAEpD,GAAG,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QAElC,OAAO,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,mBAAmB,CAChC,WAA4B,EAC5B,OAAqB,EACrB,WAA6C,EAC7C,SAA4C;IAE5C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC;IAE7C,0BAA0B;IAC1B,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC;IAE5E,MAAM,cAAc,GAClB,WAAW,IAAI,OAAO,CAAC,aAAa,KAAK,8BAAkB,CAAC;IAE9D,IAAI,cAAc,EAAE,CAAC;QACnB,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAClD,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,IAAI,CACrC,mDAAmD,EACnD,EAAE,WAAW,EAAE,CAChB,CAAC;IAEF,MAAM,2BAA2B,GAAG,UAAU,CAAC,iBAAiB,EAAE,GAAG,CACnE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACN,GAAG,CAAC;QACJ,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC1B,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACtB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;KAC3B,CAAC,CACH,CAAC;IAEF,MAAM,iBAAiB,GAAG,IAAI,eAAS,CAAC;QACtC,+CAA+C;KAChD,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE;QAChC,OAAO,CAAC,IAAI;QACZ,OAAO,CAAC,mBAAmB;KAC5B,CAAC,CAAC;IAEH,WAAW,CAAC,iBAAiB,GAAG,2BAA2B,CAAC;IAC5D,WAAW,CAAC,SAAS,GAAG,cAAc,CAAC;IAEvC,WAAW,CAAC,GAAG,GAAG;QAChB;YACE,EAAE,EAAE,OAAO,CAAC,kBAAkB;YAC9B,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,KAAK;SACb;QACD;YACE,EAAE,EAAE,UAAU,CAAC,EAAE;YACjB,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAAqB;IAC7C,MAAM,oBAAoB,GACxB,OAAO,CAAC,aAAa,KAAK,6BAAiB;QAC3C,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE;YACtC,iCAAqB,CAAC,WAAW,EAAE,CAAC;IAExC,MAAM,qBAAqB,GACzB,OAAO,CAAC,aAAa,KAAK,4BAAgB;QAC1C,OAAO,CAAC,kBAAkB,KAAK,IAAA,sBAAc,EAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvE,MAAM,aAAa,GAAiB;QAClC,GAAG,OAAO;QACV,kBAAkB,EAAE,qBAAqB;YACvC,CAAC,CAAC,gCAAoB;YACtB,CAAC,CAAC,OAAO,CAAC,kBAAkB;QAC9B,aAAa,EAAE,oBAAoB;YACjC,CAAC,CAAC,8BAAkB;YACpB,CAAC,CAAC,OAAO,CAAC,aAAa;QACzB,kBAAkB,EAAE,oBAAoB;YACtC,CAAC,CAAC,oCAAoC;YACtC,CAAC,CAAC,OAAO,CAAC,kBAAkB;QAC9B,mBAAmB,EAAE,oBAAoB;YACvC,CAAC,CAAC,IAAI,wBAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtE,CAAC,CAAC,OAAO,CAAC,mBAAmB;KAChC,CAAC;IAEF,IAAI,oBAAoB,EAAE,CAAC;QACzB,GAAG,CAAC,2DAA2D,EAAE;YAC/D,eAAe,EAAE,OAAO;YACxB,iBAAiB,EAAE,aAAa;SACjC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CACrB,KAAiB,EACjB,OAAqB,EACrB,WAAwC;IAExC,MAAM,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC;IAClC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAEhC,MAAM,EAAE,aAAa,EAAE,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE3D,MAAM,IAAI,GAAG,mBAAmB,CAC9B,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,EAChC,aAAa,CACd,CAAC;IAEF,MAAM,QAAQ,GAAG,mBAAmB,CAClC,IAAI,wBAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EACrC,aAAa,CACd,CAAC;IAEF,MAAM,aAAa,GAAG,0BAA0B,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAEnE,MAAM,aAAa,GAAG;QACpB,GAAG,EAAE,GAAG;QACR,IAAI,EAAE,GAAG;KACV,CAAC;IAEF,OAAO;QACL,IAAI;QACJ,iBAAiB,EAAE,OAAO,CAAC,YAAY;QACvC,IAAI,EAAE;YACJ,QAAQ;YACR,aAAa;YACb,aAAa;SACd;QACD,QAAQ,EAAE,KAAK;QACf,OAAO;QACP,QAAQ,EAAE,0BAAsB,CAAC,KAAK;KACvC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,KAAiB,EAAE,OAAqB;IAChE,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;IACtC,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,WAAW,CAAC;IAClE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC;IAE1D,MAAM,aAAa,GAAG,IAAI,wBAAS,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAE1E,MAAM,OAAO,GAAG,IAAI,wBAAS,CAAC,aAAa,CAAC,CAAC,KAAK,CAChD,OAAO,CAAC,mBAAmB,CAC5B,CAAC;IAEF,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,mBAAmB,CAC1B,QAAmB,EACnB,aAAwB;IAExB,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAEvD,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CACnB,SAA4C,EAC5C,OAAqB;IAErB,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC;IAEtD,MAAM,uBAAuB,GAC3B,aAAa,KAAK,4BAAgB;QAClC,kBAAkB,KAAK,gCAAoB;QACzC,CAAC,CAAC,IAAA,sBAAc,EAAC,aAAa,CAAC;QAC/B,CAAC,CAAC,kBAAkB,CAAC;IAEzB,MAAM,cAAc,GAAG,IAAA,wBAAgB,EACrC,SAAS,EACT,uBAAuB,EACvB,aAAa,CACd,CAAC;IAEF,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,wBAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,SAAS,CACpE,cAAc,CAAC,OAAO,CACvB,CAAC;IAEF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,SAA4C;IACnE,MAAM,gBAAgB,GAAG,SAAS,CAAC,IAAI,CACrC,sCAAsC,CACvC,CAAC;IAEF,MAAM,YAAY,GAAG,gBAAgB,CAAC,kBAAkB;QACtD,EAAE,iBAAuD,CAAC;IAE5D,MAAM,aAAa,GAAG,YAAY,EAAE,aAAa,IAAI,2BAAe,CAAC;IAErE,OAAO;QACL,aAAa;KACd,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,0BAA0B,CACjC,KAAiB,EACjB,SAA4C;IAE5C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,aAAa,GAAG,8BAA8B,CAAC,SAAS,CAAC,CAAC;IAEhE,OAAO,IAAA,sBAAgB,EAAC;QACtB,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO;QAC7B,GAAG,EAAE,aAAa;QAClB,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAS,8BAA8B,CACrC,MAAoD;IAEpD,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;IAEjE,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,IAAI,wBAAS,CAAC,CAAC,CAAC,GAAa,CAAC,CAAC,QAAQ,EAAE,EAC/D,CAAC,CACF,CAAC;IACJ,CAAC;IAED,sDAAsD;IACtD,sEAAsE;IAEtE,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CACX,KAAK,GAAG,IAAI,wBAAS,CAAC,CAAC,CAAC,GAAG,IAAI,oCAAwB,CAAC,CAAC,QAAQ,EAAE,EACrE,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { successfulFetch } from '@metamask/controller-utils';\nimport type { Json } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n CHAIN_ID_POLYGON,\n RELAY_FALLBACK_GAS_LIMIT,\n RELAY_URL_QUOTE,\n} from './constants';\nimport type { RelayQuote } from './types';\nimport { TransactionPayStrategy } from '../..';\nimport type { TransactionMeta } from '../../../../transaction-controller/src';\nimport { NATIVE_TOKEN_ADDRESS } from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n FiatValue,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { calculateGasCost } from '../../utils/gas';\nimport { getNativeToken, getTokenFiatRate } from '../../utils/token';\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Fetches Relay quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getRelayQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const normalizedRequests = requests\n // Ignore gas fee token requests\n .filter((r) => r.targetAmountMinimum !== '0')\n .map((r) => normalizeRequest(r));\n\n log('Normalized requests', normalizedRequests);\n\n return await Promise.all(\n normalizedRequests.map((r) => getSingleQuote(r, request)),\n );\n } catch (error) {\n log('Error fetching quotes', { error });\n throw new Error(`Failed to fetch Relay quotes: ${String(error)}`);\n }\n}\n\n/**\n * Fetches a single Relay quote.\n *\n * @param request - Quote request.\n * @param fullRequest - Full quotes request.\n * @returns Single quote.\n */\nasync function getSingleQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger, transaction } = fullRequest;\n\n try {\n const body = {\n amount: request.targetAmountMinimum,\n destinationChainId: Number(request.targetChainId),\n destinationCurrency: request.targetTokenAddress,\n originChainId: Number(request.sourceChainId),\n originCurrency: request.sourceTokenAddress,\n recipient: request.from,\n tradeType: 'EXPECTED_OUTPUT',\n user: request.from,\n };\n\n await processTransactions(transaction, request, body, messenger);\n\n const url = getFeatureFlags(messenger).relayQuoteUrl;\n\n log('Request body', { body, url });\n\n const response = await successfulFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const quote = (await response.json()) as RelayQuote;\n\n log('Fetched relay quote', quote);\n\n return normalizeQuote(quote, request, fullRequest);\n } catch (e) {\n log('Error fetching relay quote', e);\n throw e;\n }\n}\n\n/**\n * Add tranasction data to request body if needed.\n *\n * @param transaction - Transaction metadata.\n * @param request - Quote request.\n * @param requestBody - Request body to populate.\n * @param messenger - Controller messenger.\n */\nasync function processTransactions(\n transaction: TransactionMeta,\n request: QuoteRequest,\n requestBody: Record<string, Json | undefined>,\n messenger: TransactionPayControllerMessenger,\n) {\n const { data, value } = transaction.txParams;\n\n /* istanbul ignore next */\n const hasNoParams = (!data || data === '0x') && (!value || value === '0x0');\n\n const skipDelegation =\n hasNoParams || request.targetChainId === CHAIN_ID_HYPERCORE;\n\n if (skipDelegation) {\n log('Skipping delegation as no transaction data');\n return;\n }\n\n const delegation = await messenger.call(\n 'TransactionPayController:getDelegationTransaction',\n { transaction },\n );\n\n const normalizedAuthorizationList = delegation.authorizationList?.map(\n (a) => ({\n ...a,\n chainId: Number(a.chainId),\n nonce: Number(a.nonce),\n yParity: Number(a.yParity),\n }),\n );\n\n const tokenTransferData = new Interface([\n 'function transfer(address to, uint256 amount)',\n ]).encodeFunctionData('transfer', [\n request.from,\n request.targetAmountMinimum,\n ]);\n\n requestBody.authorizationList = normalizedAuthorizationList;\n requestBody.tradeType = 'EXACT_OUTPUT';\n\n requestBody.txs = [\n {\n to: request.targetTokenAddress,\n data: tokenTransferData,\n value: '0x0',\n },\n {\n to: delegation.to,\n data: delegation.data,\n value: delegation.value,\n },\n ];\n}\n\n/**\n * Normalizes requests for Relay.\n *\n * @param request - Quote request to normalize.\n * @returns Normalized request.\n */\nfunction normalizeRequest(request: QuoteRequest) {\n const isHyperliquidDeposit =\n request.targetChainId === CHAIN_ID_ARBITRUM &&\n request.targetTokenAddress.toLowerCase() ===\n ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n const isPolygonNativeSource =\n request.sourceChainId === CHAIN_ID_POLYGON &&\n request.sourceTokenAddress === getNativeToken(request.sourceChainId);\n\n const requestOutput: QuoteRequest = {\n ...request,\n sourceTokenAddress: isPolygonNativeSource\n ? NATIVE_TOKEN_ADDRESS\n : request.sourceTokenAddress,\n targetChainId: isHyperliquidDeposit\n ? CHAIN_ID_HYPERCORE\n : request.targetChainId,\n targetTokenAddress: isHyperliquidDeposit\n ? '0x00000000000000000000000000000000'\n : request.targetTokenAddress,\n targetAmountMinimum: isHyperliquidDeposit\n ? new BigNumber(request.targetAmountMinimum).shiftedBy(2).toString(10)\n : request.targetAmountMinimum,\n };\n\n if (isHyperliquidDeposit) {\n log('Converting Arbitrum Hyperliquid deposit to direct deposit', {\n originalRequest: request,\n normalizedRequest: requestOutput,\n });\n }\n\n return requestOutput;\n}\n\n/**\n * Normalizes a Relay quote into a TransactionPayQuote.\n *\n * @param quote - Relay quote.\n * @param request - Original quote request.\n * @param fullRequest - Full quotes request.\n * @returns Normalized quote.\n */\nfunction normalizeQuote(\n quote: RelayQuote,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): TransactionPayQuote<RelayQuote> {\n const { messenger } = fullRequest;\n const { details, fees } = quote;\n\n const { usdToFiatRate } = getFiatRates(messenger, request);\n\n const dust = getFiatValueFromUsd(\n calculateDustUsd(quote, request),\n usdToFiatRate,\n );\n\n const provider = getFiatValueFromUsd(\n new BigNumber(fees.relayer.amountUsd),\n usdToFiatRate,\n );\n\n const sourceNetwork = calculateSourceNetworkCost(quote, messenger);\n\n const targetNetwork = {\n usd: '0',\n fiat: '0',\n };\n\n return {\n dust,\n estimatedDuration: details.timeEstimate,\n fees: {\n provider,\n sourceNetwork,\n targetNetwork,\n },\n original: quote,\n request,\n strategy: TransactionPayStrategy.Relay,\n };\n}\n\n/**\n * Calculate dust USD value.\n *\n * @param quote - Relay quote.\n * @param request - Quote request.\n * @returns Dust value in USD and fiat.\n */\nfunction calculateDustUsd(quote: RelayQuote, request: QuoteRequest) {\n const { currencyOut } = quote.details;\n const { amountUsd, amountFormatted, minimumAmount } = currencyOut;\n const { decimals: targetDecimals } = currencyOut.currency;\n\n const targetUsdRate = new BigNumber(amountUsd).dividedBy(amountFormatted);\n\n const dustRaw = new BigNumber(minimumAmount).minus(\n request.targetAmountMinimum,\n );\n\n return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);\n}\n\n/**\n * Converts USD value to fiat value.\n *\n * @param usdValue - USD value.\n * @param usdToFiatRate - USD to fiat rate.\n * @returns Fiat value.\n */\nfunction getFiatValueFromUsd(\n usdValue: BigNumber,\n usdToFiatRate: BigNumber,\n): FiatValue {\n const fiatValue = usdValue.multipliedBy(usdToFiatRate);\n\n return {\n usd: usdValue.toString(10),\n fiat: fiatValue.toString(10),\n };\n}\n\n/**\n * Calculates USD to fiat rate.\n *\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @returns USD to fiat rate.\n */\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n) {\n const { sourceChainId, sourceTokenAddress } = request;\n\n const finalSourceTokenAddress =\n sourceChainId === CHAIN_ID_POLYGON &&\n sourceTokenAddress === NATIVE_TOKEN_ADDRESS\n ? getNativeToken(sourceChainId)\n : sourceTokenAddress;\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n finalSourceTokenAddress,\n sourceChainId,\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, usdToFiatRate };\n}\n\n/**\n * Gets feature flags for Relay quotes.\n *\n * @param messenger - Controller messenger.\n * @returns Feature flags.\n */\nfunction getFeatureFlags(messenger: TransactionPayControllerMessenger) {\n const featureFlagState = messenger.call(\n 'RemoteFeatureFlagController:getState',\n );\n\n const featureFlags = featureFlagState.remoteFeatureFlags\n ?.confirmations_pay as Record<string, string> | undefined;\n\n const relayQuoteUrl = featureFlags?.relayQuoteUrl ?? RELAY_URL_QUOTE;\n\n return {\n relayQuoteUrl,\n };\n}\n\n/**\n * Calculates source network cost from a Relay quote.\n *\n * @param quote - Relay quote.\n * @param messenger - Controller messenger.\n * @returns Total source network cost in USD and fiat.\n */\nfunction calculateSourceNetworkCost(\n quote: RelayQuote,\n messenger: TransactionPayControllerMessenger,\n) {\n const allParams = quote.steps[0].items.map((i) => i.data);\n const totalGasLimit = calculateSourceNetworkGasLimit(allParams);\n\n return calculateGasCost({\n chainId: allParams[0].chainId,\n gas: totalGasLimit,\n messenger,\n });\n}\n\n/**\n * Calculate the total gas limit for the source network transactions.\n *\n * @param params - Array of transaction parameters.\n * @returns - Total gas limit.\n */\nfunction calculateSourceNetworkGasLimit(\n params: RelayQuote['steps'][0]['items'][0]['data'][],\n): number {\n const allParamsHasGas = params.every((p) => p.gas !== undefined);\n\n if (allParamsHasGas) {\n return params.reduce(\n (total, p) => total + new BigNumber(p.gas as string).toNumber(),\n 0,\n );\n }\n\n // In future, call `TransactionController:estimateGas`\n // or `TransactionController:estimateGasBatch` based on params length.\n\n return params.reduce(\n (total, p) =>\n total + new BigNumber(p.gas ?? RELAY_FALLBACK_GAS_LIMIT).toNumber(),\n 0,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"relay-quotes.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAgB;AAI1C,OAAO,KAAK,EAEV,2BAA2B,EAG3B,mBAAmB,EACpB,wBAAoB;AAMrB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAyB5C"}
1
+ {"version":3,"file":"relay-quotes.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAgB;AAK1C,OAAO,KAAK,EAEV,2BAA2B,EAG3B,mBAAmB,EACpB,wBAAoB;AAMrB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAoB5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"relay-quotes.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAgB;AAI1C,OAAO,KAAK,EAEV,2BAA2B,EAG3B,mBAAmB,EACpB,wBAAoB;AAMrB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAyB5C"}
1
+ {"version":3,"file":"relay-quotes.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAgB;AAK1C,OAAO,KAAK,EAEV,2BAA2B,EAG3B,mBAAmB,EACpB,wBAAoB;AAMrB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAoB5C"}
@@ -1,11 +1,12 @@
1
- import { successfulFetch, toHex } from "@metamask/controller-utils";
1
+ import { Interface } from "@ethersproject/abi";
2
+ import { successfulFetch } from "@metamask/controller-utils";
2
3
  import { createModuleLogger } from "@metamask/utils";
3
4
  import { BigNumber } from "bignumber.js";
4
- import { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM, CHAIN_ID_POLYGON, RELAY_FALLBACK_GAS_LIMIT, RELAY_URL_QUOTE } from "./constants.mjs";
5
+ import { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM, CHAIN_ID_HYPERCORE, CHAIN_ID_POLYGON, RELAY_FALLBACK_GAS_LIMIT, RELAY_URL_QUOTE } from "./constants.mjs";
5
6
  import { TransactionPayStrategy } from "../../index.mjs";
6
7
  import { NATIVE_TOKEN_ADDRESS } from "../../constants.mjs";
7
8
  import { projectLogger } from "../../logger.mjs";
8
- import { calculateGasCost, calculateTransactionGasCost } from "../../utils/gas.mjs";
9
+ import { calculateGasCost } from "../../utils/gas.mjs";
9
10
  import { getNativeToken, getTokenFiatRate } from "../../utils/token.mjs";
10
11
  const log = createModuleLogger(projectLogger, 'relay-strategy');
11
12
  /**
@@ -18,14 +19,12 @@ export async function getRelayQuotes(request) {
18
19
  const { requests } = request;
19
20
  log('Fetching quotes', requests);
20
21
  try {
21
- const result = requests
22
+ const normalizedRequests = requests
22
23
  // Ignore gas fee token requests
23
24
  .filter((r) => r.targetAmountMinimum !== '0')
24
25
  .map((r) => normalizeRequest(r));
25
- const normalizedRequests = result.map((r) => r.request);
26
- const isSkipTransaction = result.some((r) => r.isSkipTransaction);
27
- log('Normalized requests', { normalizedRequests, isSkipTransaction });
28
- return await Promise.all(normalizedRequests.map((r) => getSingleQuote(r, isSkipTransaction, request)));
26
+ log('Normalized requests', normalizedRequests);
27
+ return await Promise.all(normalizedRequests.map((r) => getSingleQuote(r, request)));
29
28
  }
30
29
  catch (error) {
31
30
  log('Error fetching quotes', { error });
@@ -36,12 +35,11 @@ export async function getRelayQuotes(request) {
36
35
  * Fetches a single Relay quote.
37
36
  *
38
37
  * @param request - Quote request.
39
- * @param isSkipTransaction - Whether to skip the transaction.
40
38
  * @param fullRequest - Full quotes request.
41
39
  * @returns Single quote.
42
40
  */
43
- async function getSingleQuote(request, isSkipTransaction, fullRequest) {
44
- const { messenger } = fullRequest;
41
+ async function getSingleQuote(request, fullRequest) {
42
+ const { messenger, transaction } = fullRequest;
45
43
  try {
46
44
  const body = {
47
45
  amount: request.targetAmountMinimum,
@@ -53,15 +51,16 @@ async function getSingleQuote(request, isSkipTransaction, fullRequest) {
53
51
  tradeType: 'EXPECTED_OUTPUT',
54
52
  user: request.from,
55
53
  };
54
+ await processTransactions(transaction, request, body, messenger);
56
55
  const url = getFeatureFlags(messenger).relayQuoteUrl;
56
+ log('Request body', { body, url });
57
57
  const response = await successfulFetch(url, {
58
58
  method: 'POST',
59
59
  headers: { 'Content-Type': 'application/json' },
60
60
  body: JSON.stringify(body),
61
61
  });
62
62
  const quote = (await response.json());
63
- quote.skipTransaction = isSkipTransaction;
64
- log('Fetched relay quote', { quote, url });
63
+ log('Fetched relay quote', quote);
65
64
  return normalizeQuote(quote, request, fullRequest);
66
65
  }
67
66
  catch (e) {
@@ -69,6 +68,51 @@ async function getSingleQuote(request, isSkipTransaction, fullRequest) {
69
68
  throw e;
70
69
  }
71
70
  }
71
+ /**
72
+ * Add tranasction data to request body if needed.
73
+ *
74
+ * @param transaction - Transaction metadata.
75
+ * @param request - Quote request.
76
+ * @param requestBody - Request body to populate.
77
+ * @param messenger - Controller messenger.
78
+ */
79
+ async function processTransactions(transaction, request, requestBody, messenger) {
80
+ const { data, value } = transaction.txParams;
81
+ /* istanbul ignore next */
82
+ const hasNoParams = (!data || data === '0x') && (!value || value === '0x0');
83
+ const skipDelegation = hasNoParams || request.targetChainId === CHAIN_ID_HYPERCORE;
84
+ if (skipDelegation) {
85
+ log('Skipping delegation as no transaction data');
86
+ return;
87
+ }
88
+ const delegation = await messenger.call('TransactionPayController:getDelegationTransaction', { transaction });
89
+ const normalizedAuthorizationList = delegation.authorizationList?.map((a) => ({
90
+ ...a,
91
+ chainId: Number(a.chainId),
92
+ nonce: Number(a.nonce),
93
+ yParity: Number(a.yParity),
94
+ }));
95
+ const tokenTransferData = new Interface([
96
+ 'function transfer(address to, uint256 amount)',
97
+ ]).encodeFunctionData('transfer', [
98
+ request.from,
99
+ request.targetAmountMinimum,
100
+ ]);
101
+ requestBody.authorizationList = normalizedAuthorizationList;
102
+ requestBody.tradeType = 'EXACT_OUTPUT';
103
+ requestBody.txs = [
104
+ {
105
+ to: request.targetTokenAddress,
106
+ data: tokenTransferData,
107
+ value: '0x0',
108
+ },
109
+ {
110
+ to: delegation.to,
111
+ data: delegation.data,
112
+ value: delegation.value,
113
+ },
114
+ ];
115
+ }
72
116
  /**
73
117
  * Normalizes requests for Relay.
74
118
  *
@@ -86,7 +130,9 @@ function normalizeRequest(request) {
86
130
  sourceTokenAddress: isPolygonNativeSource
87
131
  ? NATIVE_TOKEN_ADDRESS
88
132
  : request.sourceTokenAddress,
89
- targetChainId: isHyperliquidDeposit ? toHex(1337) : request.targetChainId,
133
+ targetChainId: isHyperliquidDeposit
134
+ ? CHAIN_ID_HYPERCORE
135
+ : request.targetChainId,
90
136
  targetTokenAddress: isHyperliquidDeposit
91
137
  ? '0x00000000000000000000000000000000'
92
138
  : request.targetTokenAddress,
@@ -100,10 +146,7 @@ function normalizeRequest(request) {
100
146
  normalizedRequest: requestOutput,
101
147
  });
102
148
  }
103
- return {
104
- request: requestOutput,
105
- isSkipTransaction: isHyperliquidDeposit,
106
- };
149
+ return requestOutput;
107
150
  }
108
151
  /**
109
152
  * Normalizes a Relay quote into a TransactionPayQuote.
@@ -114,19 +157,16 @@ function normalizeRequest(request) {
114
157
  * @returns Normalized quote.
115
158
  */
116
159
  function normalizeQuote(quote, request, fullRequest) {
117
- const { messenger, transaction } = fullRequest;
118
- const { details } = quote;
119
- const { currencyIn, currencyOut } = details;
160
+ const { messenger } = fullRequest;
161
+ const { details, fees } = quote;
120
162
  const { usdToFiatRate } = getFiatRates(messenger, request);
121
163
  const dust = getFiatValueFromUsd(calculateDustUsd(quote, request), usdToFiatRate);
122
- const provider = getFiatValueFromUsd(new BigNumber(currencyIn.amountUsd).minus(currencyOut.amountUsd), usdToFiatRate);
164
+ const provider = getFiatValueFromUsd(new BigNumber(fees.relayer.amountUsd), usdToFiatRate);
123
165
  const sourceNetwork = calculateSourceNetworkCost(quote, messenger);
124
- const targetNetwork = quote.skipTransaction
125
- ? {
126
- usd: '0',
127
- fiat: '0',
128
- }
129
- : calculateTransactionGasCost(transaction, messenger);
166
+ const targetNetwork = {
167
+ usd: '0',
168
+ fiat: '0',
169
+ };
130
170
  return {
131
171
  dust,
132
172
  estimatedDuration: details.timeEstimate,
@@ -1 +1 @@
1
- {"version":3,"file":"relay-quotes.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { successfulFetch, toHex } from '@metamask/controller-utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_POLYGON,\n RELAY_FALLBACK_GAS_LIMIT,\n RELAY_URL_QUOTE,\n} from './constants';\nimport type { RelayQuote } from './types';\nimport { TransactionPayStrategy } from '../..';\nimport { NATIVE_TOKEN_ADDRESS } from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n FiatValue,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { calculateGasCost, calculateTransactionGasCost } from '../../utils/gas';\nimport { getNativeToken, getTokenFiatRate } from '../../utils/token';\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Fetches Relay quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getRelayQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const result = requests\n // Ignore gas fee token requests\n .filter((r) => r.targetAmountMinimum !== '0')\n .map((r) => normalizeRequest(r));\n\n const normalizedRequests = result.map((r) => r.request);\n const isSkipTransaction = result.some((r) => r.isSkipTransaction);\n\n log('Normalized requests', { normalizedRequests, isSkipTransaction });\n\n return await Promise.all(\n normalizedRequests.map((r) =>\n getSingleQuote(r, isSkipTransaction, request),\n ),\n );\n } catch (error) {\n log('Error fetching quotes', { error });\n throw new Error(`Failed to fetch Relay quotes: ${String(error)}`);\n }\n}\n\n/**\n * Fetches a single Relay quote.\n *\n * @param request - Quote request.\n * @param isSkipTransaction - Whether to skip the transaction.\n * @param fullRequest - Full quotes request.\n * @returns Single quote.\n */\nasync function getSingleQuote(\n request: QuoteRequest,\n isSkipTransaction: boolean,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n\n try {\n const body = {\n amount: request.targetAmountMinimum,\n destinationChainId: Number(request.targetChainId),\n destinationCurrency: request.targetTokenAddress,\n originChainId: Number(request.sourceChainId),\n originCurrency: request.sourceTokenAddress,\n recipient: request.from,\n tradeType: 'EXPECTED_OUTPUT',\n user: request.from,\n };\n\n const url = getFeatureFlags(messenger).relayQuoteUrl;\n\n const response = await successfulFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const quote = (await response.json()) as RelayQuote;\n quote.skipTransaction = isSkipTransaction;\n\n log('Fetched relay quote', { quote, url });\n\n return normalizeQuote(quote, request, fullRequest);\n } catch (e) {\n log('Error fetching relay quote', e);\n throw e;\n }\n}\n\n/**\n * Normalizes requests for Relay.\n *\n * @param request - Quote request to normalize.\n * @returns Normalized request.\n */\nfunction normalizeRequest(request: QuoteRequest) {\n const isHyperliquidDeposit =\n request.targetChainId === CHAIN_ID_ARBITRUM &&\n request.targetTokenAddress.toLowerCase() ===\n ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n const isPolygonNativeSource =\n request.sourceChainId === CHAIN_ID_POLYGON &&\n request.sourceTokenAddress === getNativeToken(request.sourceChainId);\n\n const requestOutput: QuoteRequest = {\n ...request,\n sourceTokenAddress: isPolygonNativeSource\n ? NATIVE_TOKEN_ADDRESS\n : request.sourceTokenAddress,\n targetChainId: isHyperliquidDeposit ? toHex(1337) : request.targetChainId,\n targetTokenAddress: isHyperliquidDeposit\n ? '0x00000000000000000000000000000000'\n : request.targetTokenAddress,\n targetAmountMinimum: isHyperliquidDeposit\n ? new BigNumber(request.targetAmountMinimum).shiftedBy(2).toString(10)\n : request.targetAmountMinimum,\n };\n\n if (isHyperliquidDeposit) {\n log('Converting Arbitrum Hyperliquid deposit to direct deposit', {\n originalRequest: request,\n normalizedRequest: requestOutput,\n });\n }\n\n return {\n request: requestOutput,\n isSkipTransaction: isHyperliquidDeposit,\n };\n}\n\n/**\n * Normalizes a Relay quote into a TransactionPayQuote.\n *\n * @param quote - Relay quote.\n * @param request - Original quote request.\n * @param fullRequest - Full quotes request.\n * @returns Normalized quote.\n */\nfunction normalizeQuote(\n quote: RelayQuote,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): TransactionPayQuote<RelayQuote> {\n const { messenger, transaction } = fullRequest;\n const { details } = quote;\n const { currencyIn, currencyOut } = details;\n\n const { usdToFiatRate } = getFiatRates(messenger, request);\n\n const dust = getFiatValueFromUsd(\n calculateDustUsd(quote, request),\n usdToFiatRate,\n );\n\n const provider = getFiatValueFromUsd(\n new BigNumber(currencyIn.amountUsd).minus(currencyOut.amountUsd),\n usdToFiatRate,\n );\n\n const sourceNetwork = calculateSourceNetworkCost(quote, messenger);\n\n const targetNetwork = quote.skipTransaction\n ? {\n usd: '0',\n fiat: '0',\n }\n : calculateTransactionGasCost(transaction, messenger);\n\n return {\n dust,\n estimatedDuration: details.timeEstimate,\n fees: {\n provider,\n sourceNetwork,\n targetNetwork,\n },\n original: quote,\n request,\n strategy: TransactionPayStrategy.Relay,\n };\n}\n\n/**\n * Calculate dust USD value.\n *\n * @param quote - Relay quote.\n * @param request - Quote request.\n * @returns Dust value in USD and fiat.\n */\nfunction calculateDustUsd(quote: RelayQuote, request: QuoteRequest) {\n const { currencyOut } = quote.details;\n const { amountUsd, amountFormatted, minimumAmount } = currencyOut;\n const { decimals: targetDecimals } = currencyOut.currency;\n\n const targetUsdRate = new BigNumber(amountUsd).dividedBy(amountFormatted);\n\n const dustRaw = new BigNumber(minimumAmount).minus(\n request.targetAmountMinimum,\n );\n\n return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);\n}\n\n/**\n * Converts USD value to fiat value.\n *\n * @param usdValue - USD value.\n * @param usdToFiatRate - USD to fiat rate.\n * @returns Fiat value.\n */\nfunction getFiatValueFromUsd(\n usdValue: BigNumber,\n usdToFiatRate: BigNumber,\n): FiatValue {\n const fiatValue = usdValue.multipliedBy(usdToFiatRate);\n\n return {\n usd: usdValue.toString(10),\n fiat: fiatValue.toString(10),\n };\n}\n\n/**\n * Calculates USD to fiat rate.\n *\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @returns USD to fiat rate.\n */\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n) {\n const { sourceChainId, sourceTokenAddress } = request;\n\n const finalSourceTokenAddress =\n sourceChainId === CHAIN_ID_POLYGON &&\n sourceTokenAddress === NATIVE_TOKEN_ADDRESS\n ? getNativeToken(sourceChainId)\n : sourceTokenAddress;\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n finalSourceTokenAddress,\n sourceChainId,\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, usdToFiatRate };\n}\n\n/**\n * Gets feature flags for Relay quotes.\n *\n * @param messenger - Controller messenger.\n * @returns Feature flags.\n */\nfunction getFeatureFlags(messenger: TransactionPayControllerMessenger) {\n const featureFlagState = messenger.call(\n 'RemoteFeatureFlagController:getState',\n );\n\n const featureFlags = featureFlagState.remoteFeatureFlags\n ?.confirmations_pay as Record<string, string> | undefined;\n\n const relayQuoteUrl = featureFlags?.relayQuoteUrl ?? RELAY_URL_QUOTE;\n\n return {\n relayQuoteUrl,\n };\n}\n\n/**\n * Calculates source network cost from a Relay quote.\n *\n * @param quote - Relay quote.\n * @param messenger - Controller messenger.\n * @returns Total source network cost in USD and fiat.\n */\nfunction calculateSourceNetworkCost(\n quote: RelayQuote,\n messenger: TransactionPayControllerMessenger,\n) {\n const allParams = quote.steps[0].items.map((i) => i.data);\n const totalGasLimit = calculateSourceNetworkGasLimit(allParams);\n\n return calculateGasCost({\n chainId: allParams[0].chainId,\n gas: totalGasLimit,\n messenger,\n });\n}\n\n/**\n * Calculate the total gas limit for the source network transactions.\n *\n * @param params - Array of transaction parameters.\n * @returns - Total gas limit.\n */\nfunction calculateSourceNetworkGasLimit(\n params: RelayQuote['steps'][0]['items'][0]['data'][],\n): number {\n const allParamsHasGas = params.every((p) => p.gas !== undefined);\n\n if (allParamsHasGas) {\n return params.reduce(\n (total, p) => total + new BigNumber(p.gas as string).toNumber(),\n 0,\n );\n }\n\n // In future, call `TransactionController:estimateGas`\n // or `TransactionController:estimateGasBatch` based on params length.\n\n return params.reduce(\n (total, p) =>\n total + new BigNumber(p.gas ?? RELAY_FALLBACK_GAS_LIMIT).toNumber(),\n 0,\n );\n}\n"]}
1
+ {"version":3,"file":"relay-quotes.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { successfulFetch } from '@metamask/controller-utils';\nimport type { Json } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n CHAIN_ID_POLYGON,\n RELAY_FALLBACK_GAS_LIMIT,\n RELAY_URL_QUOTE,\n} from './constants';\nimport type { RelayQuote } from './types';\nimport { TransactionPayStrategy } from '../..';\nimport type { TransactionMeta } from '../../../../transaction-controller/src';\nimport { NATIVE_TOKEN_ADDRESS } from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n FiatValue,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport { calculateGasCost } from '../../utils/gas';\nimport { getNativeToken, getTokenFiatRate } from '../../utils/token';\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n/**\n * Fetches Relay quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getRelayQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const normalizedRequests = requests\n // Ignore gas fee token requests\n .filter((r) => r.targetAmountMinimum !== '0')\n .map((r) => normalizeRequest(r));\n\n log('Normalized requests', normalizedRequests);\n\n return await Promise.all(\n normalizedRequests.map((r) => getSingleQuote(r, request)),\n );\n } catch (error) {\n log('Error fetching quotes', { error });\n throw new Error(`Failed to fetch Relay quotes: ${String(error)}`);\n }\n}\n\n/**\n * Fetches a single Relay quote.\n *\n * @param request - Quote request.\n * @param fullRequest - Full quotes request.\n * @returns Single quote.\n */\nasync function getSingleQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger, transaction } = fullRequest;\n\n try {\n const body = {\n amount: request.targetAmountMinimum,\n destinationChainId: Number(request.targetChainId),\n destinationCurrency: request.targetTokenAddress,\n originChainId: Number(request.sourceChainId),\n originCurrency: request.sourceTokenAddress,\n recipient: request.from,\n tradeType: 'EXPECTED_OUTPUT',\n user: request.from,\n };\n\n await processTransactions(transaction, request, body, messenger);\n\n const url = getFeatureFlags(messenger).relayQuoteUrl;\n\n log('Request body', { body, url });\n\n const response = await successfulFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n const quote = (await response.json()) as RelayQuote;\n\n log('Fetched relay quote', quote);\n\n return normalizeQuote(quote, request, fullRequest);\n } catch (e) {\n log('Error fetching relay quote', e);\n throw e;\n }\n}\n\n/**\n * Add tranasction data to request body if needed.\n *\n * @param transaction - Transaction metadata.\n * @param request - Quote request.\n * @param requestBody - Request body to populate.\n * @param messenger - Controller messenger.\n */\nasync function processTransactions(\n transaction: TransactionMeta,\n request: QuoteRequest,\n requestBody: Record<string, Json | undefined>,\n messenger: TransactionPayControllerMessenger,\n) {\n const { data, value } = transaction.txParams;\n\n /* istanbul ignore next */\n const hasNoParams = (!data || data === '0x') && (!value || value === '0x0');\n\n const skipDelegation =\n hasNoParams || request.targetChainId === CHAIN_ID_HYPERCORE;\n\n if (skipDelegation) {\n log('Skipping delegation as no transaction data');\n return;\n }\n\n const delegation = await messenger.call(\n 'TransactionPayController:getDelegationTransaction',\n { transaction },\n );\n\n const normalizedAuthorizationList = delegation.authorizationList?.map(\n (a) => ({\n ...a,\n chainId: Number(a.chainId),\n nonce: Number(a.nonce),\n yParity: Number(a.yParity),\n }),\n );\n\n const tokenTransferData = new Interface([\n 'function transfer(address to, uint256 amount)',\n ]).encodeFunctionData('transfer', [\n request.from,\n request.targetAmountMinimum,\n ]);\n\n requestBody.authorizationList = normalizedAuthorizationList;\n requestBody.tradeType = 'EXACT_OUTPUT';\n\n requestBody.txs = [\n {\n to: request.targetTokenAddress,\n data: tokenTransferData,\n value: '0x0',\n },\n {\n to: delegation.to,\n data: delegation.data,\n value: delegation.value,\n },\n ];\n}\n\n/**\n * Normalizes requests for Relay.\n *\n * @param request - Quote request to normalize.\n * @returns Normalized request.\n */\nfunction normalizeRequest(request: QuoteRequest) {\n const isHyperliquidDeposit =\n request.targetChainId === CHAIN_ID_ARBITRUM &&\n request.targetTokenAddress.toLowerCase() ===\n ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n const isPolygonNativeSource =\n request.sourceChainId === CHAIN_ID_POLYGON &&\n request.sourceTokenAddress === getNativeToken(request.sourceChainId);\n\n const requestOutput: QuoteRequest = {\n ...request,\n sourceTokenAddress: isPolygonNativeSource\n ? NATIVE_TOKEN_ADDRESS\n : request.sourceTokenAddress,\n targetChainId: isHyperliquidDeposit\n ? CHAIN_ID_HYPERCORE\n : request.targetChainId,\n targetTokenAddress: isHyperliquidDeposit\n ? '0x00000000000000000000000000000000'\n : request.targetTokenAddress,\n targetAmountMinimum: isHyperliquidDeposit\n ? new BigNumber(request.targetAmountMinimum).shiftedBy(2).toString(10)\n : request.targetAmountMinimum,\n };\n\n if (isHyperliquidDeposit) {\n log('Converting Arbitrum Hyperliquid deposit to direct deposit', {\n originalRequest: request,\n normalizedRequest: requestOutput,\n });\n }\n\n return requestOutput;\n}\n\n/**\n * Normalizes a Relay quote into a TransactionPayQuote.\n *\n * @param quote - Relay quote.\n * @param request - Original quote request.\n * @param fullRequest - Full quotes request.\n * @returns Normalized quote.\n */\nfunction normalizeQuote(\n quote: RelayQuote,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): TransactionPayQuote<RelayQuote> {\n const { messenger } = fullRequest;\n const { details, fees } = quote;\n\n const { usdToFiatRate } = getFiatRates(messenger, request);\n\n const dust = getFiatValueFromUsd(\n calculateDustUsd(quote, request),\n usdToFiatRate,\n );\n\n const provider = getFiatValueFromUsd(\n new BigNumber(fees.relayer.amountUsd),\n usdToFiatRate,\n );\n\n const sourceNetwork = calculateSourceNetworkCost(quote, messenger);\n\n const targetNetwork = {\n usd: '0',\n fiat: '0',\n };\n\n return {\n dust,\n estimatedDuration: details.timeEstimate,\n fees: {\n provider,\n sourceNetwork,\n targetNetwork,\n },\n original: quote,\n request,\n strategy: TransactionPayStrategy.Relay,\n };\n}\n\n/**\n * Calculate dust USD value.\n *\n * @param quote - Relay quote.\n * @param request - Quote request.\n * @returns Dust value in USD and fiat.\n */\nfunction calculateDustUsd(quote: RelayQuote, request: QuoteRequest) {\n const { currencyOut } = quote.details;\n const { amountUsd, amountFormatted, minimumAmount } = currencyOut;\n const { decimals: targetDecimals } = currencyOut.currency;\n\n const targetUsdRate = new BigNumber(amountUsd).dividedBy(amountFormatted);\n\n const dustRaw = new BigNumber(minimumAmount).minus(\n request.targetAmountMinimum,\n );\n\n return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);\n}\n\n/**\n * Converts USD value to fiat value.\n *\n * @param usdValue - USD value.\n * @param usdToFiatRate - USD to fiat rate.\n * @returns Fiat value.\n */\nfunction getFiatValueFromUsd(\n usdValue: BigNumber,\n usdToFiatRate: BigNumber,\n): FiatValue {\n const fiatValue = usdValue.multipliedBy(usdToFiatRate);\n\n return {\n usd: usdValue.toString(10),\n fiat: fiatValue.toString(10),\n };\n}\n\n/**\n * Calculates USD to fiat rate.\n *\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @returns USD to fiat rate.\n */\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n) {\n const { sourceChainId, sourceTokenAddress } = request;\n\n const finalSourceTokenAddress =\n sourceChainId === CHAIN_ID_POLYGON &&\n sourceTokenAddress === NATIVE_TOKEN_ADDRESS\n ? getNativeToken(sourceChainId)\n : sourceTokenAddress;\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n finalSourceTokenAddress,\n sourceChainId,\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, usdToFiatRate };\n}\n\n/**\n * Gets feature flags for Relay quotes.\n *\n * @param messenger - Controller messenger.\n * @returns Feature flags.\n */\nfunction getFeatureFlags(messenger: TransactionPayControllerMessenger) {\n const featureFlagState = messenger.call(\n 'RemoteFeatureFlagController:getState',\n );\n\n const featureFlags = featureFlagState.remoteFeatureFlags\n ?.confirmations_pay as Record<string, string> | undefined;\n\n const relayQuoteUrl = featureFlags?.relayQuoteUrl ?? RELAY_URL_QUOTE;\n\n return {\n relayQuoteUrl,\n };\n}\n\n/**\n * Calculates source network cost from a Relay quote.\n *\n * @param quote - Relay quote.\n * @param messenger - Controller messenger.\n * @returns Total source network cost in USD and fiat.\n */\nfunction calculateSourceNetworkCost(\n quote: RelayQuote,\n messenger: TransactionPayControllerMessenger,\n) {\n const allParams = quote.steps[0].items.map((i) => i.data);\n const totalGasLimit = calculateSourceNetworkGasLimit(allParams);\n\n return calculateGasCost({\n chainId: allParams[0].chainId,\n gas: totalGasLimit,\n messenger,\n });\n}\n\n/**\n * Calculate the total gas limit for the source network transactions.\n *\n * @param params - Array of transaction parameters.\n * @returns - Total gas limit.\n */\nfunction calculateSourceNetworkGasLimit(\n params: RelayQuote['steps'][0]['items'][0]['data'][],\n): number {\n const allParamsHasGas = params.every((p) => p.gas !== undefined);\n\n if (allParamsHasGas) {\n return params.reduce(\n (total, p) => total + new BigNumber(p.gas as string).toNumber(),\n 0,\n );\n }\n\n // In future, call `TransactionController:estimateGas`\n // or `TransactionController:estimateGasBatch` based on params length.\n\n return params.reduce(\n (total, p) =>\n total + new BigNumber(p.gas ?? RELAY_FALLBACK_GAS_LIMIT).toNumber(),\n 0,\n );\n}\n"]}