@metamask-previews/transaction-pay-controller 24.0.3-preview-2fd14c0c3 → 24.0.3-preview-10d0bd75c
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 +10 -0
- package/dist/strategy/server/perps.cjs +18 -1
- package/dist/strategy/server/perps.cjs.map +1 -1
- package/dist/strategy/server/perps.d.cts +5 -1
- package/dist/strategy/server/perps.d.cts.map +1 -1
- package/dist/strategy/server/perps.d.mts +5 -1
- package/dist/strategy/server/perps.d.mts.map +1 -1
- package/dist/strategy/server/perps.mjs +18 -1
- package/dist/strategy/server/perps.mjs.map +1 -1
- package/dist/strategy/server/server-quotes.cjs +68 -19
- package/dist/strategy/server/server-quotes.cjs.map +1 -1
- package/dist/strategy/server/server-quotes.d.cts.map +1 -1
- package/dist/strategy/server/server-quotes.d.mts.map +1 -1
- package/dist/strategy/server/server-quotes.mjs +69 -20
- package/dist/strategy/server/server-quotes.mjs.map +1 -1
- package/dist/strategy/server/server-submit.cjs +389 -61
- package/dist/strategy/server/server-submit.cjs.map +1 -1
- package/dist/strategy/server/server-submit.d.cts.map +1 -1
- package/dist/strategy/server/server-submit.d.mts.map +1 -1
- package/dist/strategy/server/server-submit.mjs +390 -62
- package/dist/strategy/server/server-submit.mjs.map +1 -1
- package/dist/strategy/server/types.cjs.map +1 -1
- package/dist/strategy/server/types.d.cts +20 -4
- package/dist/strategy/server/types.d.cts.map +1 -1
- package/dist/strategy/server/types.d.mts +20 -4
- package/dist/strategy/server/types.d.mts.map +1 -1
- package/dist/strategy/server/types.mjs.map +1 -1
- package/dist/utils/transaction.cjs +4 -1
- package/dist/utils/transaction.cjs.map +1 -1
- package/dist/utils/transaction.d.cts.map +1 -1
- package/dist/utils/transaction.d.mts.map +1 -1
- package/dist/utils/transaction.mjs +4 -1
- package/dist/utils/transaction.mjs.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add generic signature steps to the server pay strategy, supporting EIP-712 sign-then-POST flows ([#9051](https://github.com/MetaMask/core/pull/9051))
|
|
13
|
+
- Trigger quote refresh when `txParams.to` or `requiredAssets` changes on a transaction, in addition to the existing `txParams.data` trigger
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Bump `@metamask/assets-controller` from `^10.2.1` to `^11.0.0` ([#9485](https://github.com/MetaMask/core/pull/9485))
|
|
18
|
+
- Bump `@metamask/ramps-controller` from `^16.0.0` to `^17.0.0` ([#9491](https://github.com/MetaMask/core/pull/9491))
|
|
19
|
+
|
|
10
20
|
## [24.0.3]
|
|
11
21
|
|
|
12
22
|
### Changed
|
|
@@ -42,11 +42,18 @@ exports.isServerPerpsDepositRequest = isServerPerpsDepositRequest;
|
|
|
42
42
|
* 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is
|
|
43
43
|
* shifted accordingly.
|
|
44
44
|
*
|
|
45
|
+
* Also handles the perps-withdraw direction: when `request.isHyperliquidSource`
|
|
46
|
+
* is set the source is rewritten to the HyperCore sentinel and the amount is
|
|
47
|
+
* shifted from 8 to 6 decimals.
|
|
48
|
+
*
|
|
45
49
|
* @param request - Quote request from the transaction-pay controller.
|
|
46
50
|
* @param transaction - Parent transaction whose calldata is inspected.
|
|
47
|
-
* @returns Normalized request, or the original request if not a perps
|
|
51
|
+
* @returns Normalized request, or the original request if not a perps flow.
|
|
48
52
|
*/
|
|
49
53
|
function normalizeServerPerpsRequest(request, transaction) {
|
|
54
|
+
if (request.isHyperliquidSource) {
|
|
55
|
+
return normalizePerpsWithdrawRequest(request);
|
|
56
|
+
}
|
|
50
57
|
if (!isServerPerpsDepositRequest(request, transaction)) {
|
|
51
58
|
return request;
|
|
52
59
|
}
|
|
@@ -60,6 +67,16 @@ function normalizeServerPerpsRequest(request, transaction) {
|
|
|
60
67
|
};
|
|
61
68
|
}
|
|
62
69
|
exports.normalizeServerPerpsRequest = normalizeServerPerpsRequest;
|
|
70
|
+
function normalizePerpsWithdrawRequest(request) {
|
|
71
|
+
return {
|
|
72
|
+
...request,
|
|
73
|
+
sourceChainId: constants_1.CHAIN_ID_HYPERCORE,
|
|
74
|
+
sourceTokenAddress: exports.SERVER_HYPERCORE_USDC_PERPS_ADDRESS,
|
|
75
|
+
sourceTokenAmount: new bignumber_js_1.BigNumber(request.sourceTokenAmount)
|
|
76
|
+
.shiftedBy(constants_1.USDC_DECIMALS - constants_1.HYPERCORE_USDC_DECIMALS)
|
|
77
|
+
.toFixed(0),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
63
80
|
function transactionDataReferencesBridge(transaction) {
|
|
64
81
|
const fragments = [
|
|
65
82
|
transaction.txParams?.to,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perps.cjs","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":";;;AAEA,+CAAyC;AAEzC,mDAMyB;AAGzB;;;;;GAKG;AACU,QAAA,mCAAmC,GAC9C,4CAAmD,CAAC;AAEtD,MAAM,gCAAgC,GACpC,4CAA4C,CAAC;AAE/C,MAAM,oCAAoC,GACxC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,SAAgB,2BAA2B,CACzC,OAGC,EACD,WAAqE;IAErE,IACE,OAAO,CAAC,WAAW,KAAK,IAAI;QAC5B,OAAO,CAAC,aAAa,KAAK,6BAAiB;QAC3C,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE;YACtC,iCAAqB,CAAC,WAAW,EAAE,EACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,+BAA+B,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC;AAjBD,kEAiBC;AAED
|
|
1
|
+
{"version":3,"file":"perps.cjs","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":";;;AAEA,+CAAyC;AAEzC,mDAMyB;AAGzB;;;;;GAKG;AACU,QAAA,mCAAmC,GAC9C,4CAAmD,CAAC;AAEtD,MAAM,gCAAgC,GACpC,4CAA4C,CAAC;AAE/C,MAAM,oCAAoC,GACxC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,SAAgB,2BAA2B,CACzC,OAGC,EACD,WAAqE;IAErE,IACE,OAAO,CAAC,WAAW,KAAK,IAAI;QAC5B,OAAO,CAAC,aAAa,KAAK,6BAAiB;QAC3C,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE;YACtC,iCAAqB,CAAC,WAAW,EAAE,EACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,+BAA+B,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC;AAjBD,kEAiBC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,2BAA2B,CACzC,OAAqB,EACrB,WAAqE;IAErE,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAChC,OAAO,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,CAAC,2BAA2B,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;QACvD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,GAAG,OAAO;QACV,mBAAmB,EAAE,IAAI,wBAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC;aAC5D,SAAS,CAAC,mCAAuB,GAAG,yBAAa,CAAC;aAClD,OAAO,CAAC,CAAC,CAAC;QACb,aAAa,EAAE,8BAAkB;QACjC,kBAAkB,EAAE,2CAAmC;KACxD,CAAC;AACJ,CAAC;AApBD,kEAoBC;AAED,SAAS,6BAA6B,CAAC,OAAqB;IAC1D,OAAO;QACL,GAAG,OAAO;QACV,aAAa,EAAE,8BAAkB;QACjC,kBAAkB,EAAE,2CAAmC;QACvD,iBAAiB,EAAE,IAAI,wBAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC;aACxD,SAAS,CAAC,yBAAa,GAAG,mCAAuB,CAAC;aAClD,OAAO,CAAC,CAAC,CAAC;KACd,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,WAAqE;IAErE,MAAM,SAAS,GAA2B;QACxC,WAAW,CAAC,QAAQ,EAAE,EAAE;QACxB,GAAG,CAAC,WAAW,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KAC7D,CAAC;IAEF,OAAO,SAAS,CAAC,IAAI,CACnB,CAAC,KAAK,EAAE,EAAE,CACR,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC,CACrE,CAAC;AACJ,CAAC","sourcesContent":["import type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n HYPERCORE_USDC_DECIMALS,\n USDC_DECIMALS,\n} from '../../constants';\nimport type { QuoteRequest } from '../../types';\n\n/**\n * Shared 20-byte sentinel address emitted by the server strategy to flag a\n * Hyperliquid perps deposit. Backend providers translate this to their own\n * on-chain destination (e.g. Relay's 16-byte HyperCore USDC sentinel, Across's\n * native USDC-PERPS token at the same address).\n */\nexport const SERVER_HYPERCORE_USDC_PERPS_ADDRESS =\n '0x2100000000000000000000000000000000000000' as Hex;\n\nconst HYPERLIQUID_BRIDGE_ADDRESS_LOWER =\n '0x2df1c51e09aecf9cacb7bc98cb1742757f163df7';\n\nconst HYPERLIQUID_BRIDGE_CALLDATA_FRAGMENT =\n HYPERLIQUID_BRIDGE_ADDRESS_LOWER.slice(2);\n\n/**\n * Detect whether a quote request represents a Hyperliquid perps deposit by\n * sniffing the parent transaction calldata for a reference to the Hyperliquid\n * bridge contract. Transaction type is intentionally NOT consulted so that any\n * caller funnelling a bridge deposit through Pay is supported.\n *\n * @param request - Quote request from the transaction-pay controller.\n * @param transaction - Parent transaction whose calldata is inspected.\n * @returns Whether the request matches a Hyperliquid bridge deposit.\n */\nexport function isServerPerpsDepositRequest(\n request: Pick<\n QuoteRequest,\n 'isPostQuote' | 'targetChainId' | 'targetTokenAddress'\n >,\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): boolean {\n if (\n request.isPostQuote === true ||\n request.targetChainId !== CHAIN_ID_ARBITRUM ||\n request.targetTokenAddress.toLowerCase() !==\n ARBITRUM_USDC_ADDRESS.toLowerCase()\n ) {\n return false;\n }\n\n return transactionDataReferencesBridge(transaction);\n}\n\n/**\n * Translate a Hyperliquid perps-deposit quote request into the HyperCore\n * direct-deposit shape with a provider-agnostic sentinel destination. Backend\n * providers detect the sentinel and rewrite it to their respective on-chain\n * destinations.\n *\n * Transaction pay starts from the parent on-chain asset (Arbitrum USDC,\n * 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is\n * shifted accordingly.\n *\n * Also handles the perps-withdraw direction: when `request.isHyperliquidSource`\n * is set the source is rewritten to the HyperCore sentinel and the amount is\n * shifted from 8 to 6 decimals.\n *\n * @param request - Quote request from the transaction-pay controller.\n * @param transaction - Parent transaction whose calldata is inspected.\n * @returns Normalized request, or the original request if not a perps flow.\n */\nexport function normalizeServerPerpsRequest(\n request: QuoteRequest,\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): QuoteRequest {\n if (request.isHyperliquidSource) {\n return normalizePerpsWithdrawRequest(request);\n }\n\n if (!isServerPerpsDepositRequest(request, transaction)) {\n return request;\n }\n\n return {\n ...request,\n targetAmountMinimum: new BigNumber(request.targetAmountMinimum)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toFixed(0),\n targetChainId: CHAIN_ID_HYPERCORE,\n targetTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,\n };\n}\n\nfunction normalizePerpsWithdrawRequest(request: QuoteRequest): QuoteRequest {\n return {\n ...request,\n sourceChainId: CHAIN_ID_HYPERCORE,\n sourceTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,\n sourceTokenAmount: new BigNumber(request.sourceTokenAmount)\n .shiftedBy(USDC_DECIMALS - HYPERCORE_USDC_DECIMALS)\n .toFixed(0),\n };\n}\n\nfunction transactionDataReferencesBridge(\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): boolean {\n const fragments: (string | undefined)[] = [\n transaction.txParams?.to,\n ...(transaction.nestedTransactions ?? []).map((tx) => tx.to),\n ];\n\n return fragments.some(\n (value) =>\n typeof value === 'string' &&\n value.toLowerCase().includes(HYPERLIQUID_BRIDGE_CALLDATA_FRAGMENT),\n );\n}\n"]}
|
|
@@ -28,9 +28,13 @@ export declare function isServerPerpsDepositRequest(request: Pick<QuoteRequest,
|
|
|
28
28
|
* 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is
|
|
29
29
|
* shifted accordingly.
|
|
30
30
|
*
|
|
31
|
+
* Also handles the perps-withdraw direction: when `request.isHyperliquidSource`
|
|
32
|
+
* is set the source is rewritten to the HyperCore sentinel and the amount is
|
|
33
|
+
* shifted from 8 to 6 decimals.
|
|
34
|
+
*
|
|
31
35
|
* @param request - Quote request from the transaction-pay controller.
|
|
32
36
|
* @param transaction - Parent transaction whose calldata is inspected.
|
|
33
|
-
* @returns Normalized request, or the original request if not a perps
|
|
37
|
+
* @returns Normalized request, or the original request if not a perps flow.
|
|
34
38
|
*/
|
|
35
39
|
export declare function normalizeServerPerpsRequest(request: QuoteRequest, transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>): QuoteRequest;
|
|
36
40
|
//# sourceMappingURL=perps.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perps.d.cts","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAoB;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,eACK,CAAC;AAQtD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,IAAI,CACX,YAAY,EACZ,aAAa,GAAG,eAAe,GAAG,oBAAoB,CACvD,EACD,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,oBAAoB,CAAC,GACpE,OAAO,CAWT;AAED
|
|
1
|
+
{"version":3,"file":"perps.d.cts","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAoB;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,eACK,CAAC;AAQtD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,IAAI,CACX,YAAY,EACZ,aAAa,GAAG,eAAe,GAAG,oBAAoB,CACvD,EACD,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,oBAAoB,CAAC,GACpE,OAAO,CAWT;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,oBAAoB,CAAC,GACpE,YAAY,CAiBd"}
|
|
@@ -28,9 +28,13 @@ export declare function isServerPerpsDepositRequest(request: Pick<QuoteRequest,
|
|
|
28
28
|
* 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is
|
|
29
29
|
* shifted accordingly.
|
|
30
30
|
*
|
|
31
|
+
* Also handles the perps-withdraw direction: when `request.isHyperliquidSource`
|
|
32
|
+
* is set the source is rewritten to the HyperCore sentinel and the amount is
|
|
33
|
+
* shifted from 8 to 6 decimals.
|
|
34
|
+
*
|
|
31
35
|
* @param request - Quote request from the transaction-pay controller.
|
|
32
36
|
* @param transaction - Parent transaction whose calldata is inspected.
|
|
33
|
-
* @returns Normalized request, or the original request if not a perps
|
|
37
|
+
* @returns Normalized request, or the original request if not a perps flow.
|
|
34
38
|
*/
|
|
35
39
|
export declare function normalizeServerPerpsRequest(request: QuoteRequest, transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>): QuoteRequest;
|
|
36
40
|
//# sourceMappingURL=perps.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perps.d.mts","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAoB;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,eACK,CAAC;AAQtD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,IAAI,CACX,YAAY,EACZ,aAAa,GAAG,eAAe,GAAG,oBAAoB,CACvD,EACD,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,oBAAoB,CAAC,GACpE,OAAO,CAWT;AAED
|
|
1
|
+
{"version":3,"file":"perps.d.mts","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAWxE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAoB;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC,eACK,CAAC;AAQtD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,IAAI,CACX,YAAY,EACZ,aAAa,GAAG,eAAe,GAAG,oBAAoB,CACvD,EACD,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,oBAAoB,CAAC,GACpE,OAAO,CAWT;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,oBAAoB,CAAC,GACpE,YAAY,CAiBd"}
|
|
@@ -38,11 +38,18 @@ export function isServerPerpsDepositRequest(request, transaction) {
|
|
|
38
38
|
* 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is
|
|
39
39
|
* shifted accordingly.
|
|
40
40
|
*
|
|
41
|
+
* Also handles the perps-withdraw direction: when `request.isHyperliquidSource`
|
|
42
|
+
* is set the source is rewritten to the HyperCore sentinel and the amount is
|
|
43
|
+
* shifted from 8 to 6 decimals.
|
|
44
|
+
*
|
|
41
45
|
* @param request - Quote request from the transaction-pay controller.
|
|
42
46
|
* @param transaction - Parent transaction whose calldata is inspected.
|
|
43
|
-
* @returns Normalized request, or the original request if not a perps
|
|
47
|
+
* @returns Normalized request, or the original request if not a perps flow.
|
|
44
48
|
*/
|
|
45
49
|
export function normalizeServerPerpsRequest(request, transaction) {
|
|
50
|
+
if (request.isHyperliquidSource) {
|
|
51
|
+
return normalizePerpsWithdrawRequest(request);
|
|
52
|
+
}
|
|
46
53
|
if (!isServerPerpsDepositRequest(request, transaction)) {
|
|
47
54
|
return request;
|
|
48
55
|
}
|
|
@@ -55,6 +62,16 @@ export function normalizeServerPerpsRequest(request, transaction) {
|
|
|
55
62
|
targetTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,
|
|
56
63
|
};
|
|
57
64
|
}
|
|
65
|
+
function normalizePerpsWithdrawRequest(request) {
|
|
66
|
+
return {
|
|
67
|
+
...request,
|
|
68
|
+
sourceChainId: CHAIN_ID_HYPERCORE,
|
|
69
|
+
sourceTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,
|
|
70
|
+
sourceTokenAmount: new BigNumber(request.sourceTokenAmount)
|
|
71
|
+
.shiftedBy(USDC_DECIMALS - HYPERCORE_USDC_DECIMALS)
|
|
72
|
+
.toFixed(0),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
58
75
|
function transactionDataReferencesBridge(transaction) {
|
|
59
76
|
const fragments = [
|
|
60
77
|
transaction.txParams?.to,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perps.mjs","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,qBAAqB;AAEzC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACd,4BAAwB;AAGzB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAC9C,4CAAmD,CAAC;AAEtD,MAAM,gCAAgC,GACpC,4CAA4C,CAAC;AAE/C,MAAM,oCAAoC,GACxC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAGC,EACD,WAAqE;IAErE,IACE,OAAO,CAAC,WAAW,KAAK,IAAI;QAC5B,OAAO,CAAC,aAAa,KAAK,iBAAiB;QAC3C,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE;YACtC,qBAAqB,CAAC,WAAW,EAAE,EACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,+BAA+B,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"perps.mjs","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,qBAAqB;AAEzC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACd,4BAAwB;AAGzB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAC9C,4CAAmD,CAAC;AAEtD,MAAM,gCAAgC,GACpC,4CAA4C,CAAC;AAE/C,MAAM,oCAAoC,GACxC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAGC,EACD,WAAqE;IAErE,IACE,OAAO,CAAC,WAAW,KAAK,IAAI;QAC5B,OAAO,CAAC,aAAa,KAAK,iBAAiB;QAC3C,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE;YACtC,qBAAqB,CAAC,WAAW,EAAE,EACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,+BAA+B,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAqB,EACrB,WAAqE;IAErE,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAChC,OAAO,6BAA6B,CAAC,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,CAAC,2BAA2B,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;QACvD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,GAAG,OAAO;QACV,mBAAmB,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC;aAC5D,SAAS,CAAC,uBAAuB,GAAG,aAAa,CAAC;aAClD,OAAO,CAAC,CAAC,CAAC;QACb,aAAa,EAAE,kBAAkB;QACjC,kBAAkB,EAAE,mCAAmC;KACxD,CAAC;AACJ,CAAC;AAED,SAAS,6BAA6B,CAAC,OAAqB;IAC1D,OAAO;QACL,GAAG,OAAO;QACV,aAAa,EAAE,kBAAkB;QACjC,kBAAkB,EAAE,mCAAmC;QACvD,iBAAiB,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC;aACxD,SAAS,CAAC,aAAa,GAAG,uBAAuB,CAAC;aAClD,OAAO,CAAC,CAAC,CAAC;KACd,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,WAAqE;IAErE,MAAM,SAAS,GAA2B;QACxC,WAAW,CAAC,QAAQ,EAAE,EAAE;QACxB,GAAG,CAAC,WAAW,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KAC7D,CAAC;IAEF,OAAO,SAAS,CAAC,IAAI,CACnB,CAAC,KAAK,EAAE,EAAE,CACR,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC,CACrE,CAAC;AACJ,CAAC","sourcesContent":["import type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n HYPERCORE_USDC_DECIMALS,\n USDC_DECIMALS,\n} from '../../constants';\nimport type { QuoteRequest } from '../../types';\n\n/**\n * Shared 20-byte sentinel address emitted by the server strategy to flag a\n * Hyperliquid perps deposit. Backend providers translate this to their own\n * on-chain destination (e.g. Relay's 16-byte HyperCore USDC sentinel, Across's\n * native USDC-PERPS token at the same address).\n */\nexport const SERVER_HYPERCORE_USDC_PERPS_ADDRESS =\n '0x2100000000000000000000000000000000000000' as Hex;\n\nconst HYPERLIQUID_BRIDGE_ADDRESS_LOWER =\n '0x2df1c51e09aecf9cacb7bc98cb1742757f163df7';\n\nconst HYPERLIQUID_BRIDGE_CALLDATA_FRAGMENT =\n HYPERLIQUID_BRIDGE_ADDRESS_LOWER.slice(2);\n\n/**\n * Detect whether a quote request represents a Hyperliquid perps deposit by\n * sniffing the parent transaction calldata for a reference to the Hyperliquid\n * bridge contract. Transaction type is intentionally NOT consulted so that any\n * caller funnelling a bridge deposit through Pay is supported.\n *\n * @param request - Quote request from the transaction-pay controller.\n * @param transaction - Parent transaction whose calldata is inspected.\n * @returns Whether the request matches a Hyperliquid bridge deposit.\n */\nexport function isServerPerpsDepositRequest(\n request: Pick<\n QuoteRequest,\n 'isPostQuote' | 'targetChainId' | 'targetTokenAddress'\n >,\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): boolean {\n if (\n request.isPostQuote === true ||\n request.targetChainId !== CHAIN_ID_ARBITRUM ||\n request.targetTokenAddress.toLowerCase() !==\n ARBITRUM_USDC_ADDRESS.toLowerCase()\n ) {\n return false;\n }\n\n return transactionDataReferencesBridge(transaction);\n}\n\n/**\n * Translate a Hyperliquid perps-deposit quote request into the HyperCore\n * direct-deposit shape with a provider-agnostic sentinel destination. Backend\n * providers detect the sentinel and rewrite it to their respective on-chain\n * destinations.\n *\n * Transaction pay starts from the parent on-chain asset (Arbitrum USDC,\n * 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is\n * shifted accordingly.\n *\n * Also handles the perps-withdraw direction: when `request.isHyperliquidSource`\n * is set the source is rewritten to the HyperCore sentinel and the amount is\n * shifted from 8 to 6 decimals.\n *\n * @param request - Quote request from the transaction-pay controller.\n * @param transaction - Parent transaction whose calldata is inspected.\n * @returns Normalized request, or the original request if not a perps flow.\n */\nexport function normalizeServerPerpsRequest(\n request: QuoteRequest,\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): QuoteRequest {\n if (request.isHyperliquidSource) {\n return normalizePerpsWithdrawRequest(request);\n }\n\n if (!isServerPerpsDepositRequest(request, transaction)) {\n return request;\n }\n\n return {\n ...request,\n targetAmountMinimum: new BigNumber(request.targetAmountMinimum)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toFixed(0),\n targetChainId: CHAIN_ID_HYPERCORE,\n targetTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,\n };\n}\n\nfunction normalizePerpsWithdrawRequest(request: QuoteRequest): QuoteRequest {\n return {\n ...request,\n sourceChainId: CHAIN_ID_HYPERCORE,\n sourceTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,\n sourceTokenAmount: new BigNumber(request.sourceTokenAmount)\n .shiftedBy(USDC_DECIMALS - HYPERCORE_USDC_DECIMALS)\n .toFixed(0),\n };\n}\n\nfunction transactionDataReferencesBridge(\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): boolean {\n const fragments: (string | undefined)[] = [\n transaction.txParams?.to,\n ...(transaction.nestedTransactions ?? []).map((tx) => tx.to),\n ];\n\n return fragments.some(\n (value) =>\n typeof value === 'string' &&\n value.toLowerCase().includes(HYPERLIQUID_BRIDGE_CALLDATA_FRAGMENT),\n );\n}\n"]}
|
|
@@ -23,6 +23,9 @@ const TRANSFER_INTERFACE = new abi_1.Interface([
|
|
|
23
23
|
]);
|
|
24
24
|
const ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };
|
|
25
25
|
const ZERO_FIAT_VALUE = { fiat: '0', usd: '0' };
|
|
26
|
+
function isTransactionStep(step) {
|
|
27
|
+
return step.type === 'transaction';
|
|
28
|
+
}
|
|
26
29
|
/**
|
|
27
30
|
* Fetch server intents-api quotes and normalize them into Transaction Pay quotes.
|
|
28
31
|
*
|
|
@@ -55,8 +58,10 @@ async function getQuotesForRequest(quoteRequest, fullRequest) {
|
|
|
55
58
|
}
|
|
56
59
|
async function buildServerQuoteRequest(quoteRequest, transaction, messenger, accountSupports7702) {
|
|
57
60
|
const normalizedRequest = (0, perps_1.normalizeServerPerpsRequest)(quoteRequest, transaction);
|
|
58
|
-
const { from, isMaxAmount, isPostQuote, sourceChainId, sourceTokenAddress, sourceTokenAmount, targetAmountMinimum, targetChainId, targetTokenAddress, } = normalizedRequest;
|
|
59
|
-
const useExactInput = (isMaxAmount ?? false) ||
|
|
61
|
+
const { from, isMaxAmount, isPostQuote, paymentOverride, sourceChainId, sourceTokenAddress, sourceTokenAmount, targetAmountMinimum, targetChainId, targetTokenAddress, } = normalizedRequest;
|
|
62
|
+
const useExactInput = (isMaxAmount ?? false) ||
|
|
63
|
+
(isPostQuote ?? false) ||
|
|
64
|
+
Boolean(normalizedRequest.isHyperliquidSource);
|
|
60
65
|
const singleData = getSingleTransactionData(transaction);
|
|
61
66
|
const isHypercore = targetChainId === constants_1.CHAIN_ID_HYPERCORE;
|
|
62
67
|
const isTokenTransfer = !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));
|
|
@@ -64,7 +69,10 @@ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, acc
|
|
|
64
69
|
if (isTokenTransfer && singleData) {
|
|
65
70
|
recipient = decodeTransferRecipient(singleData);
|
|
66
71
|
}
|
|
67
|
-
const
|
|
72
|
+
const isHypercoreSource = sourceChainId === constants_1.CHAIN_ID_HYPERCORE;
|
|
73
|
+
const supportsGasless = !isHypercoreSource &&
|
|
74
|
+
accountSupports7702 &&
|
|
75
|
+
(0, feature_flags_1.isEIP7702Chain)(messenger, sourceChainId);
|
|
68
76
|
const body = {
|
|
69
77
|
source: { chainId: Number(sourceChainId), token: sourceTokenAddress },
|
|
70
78
|
target: { chainId: Number(targetChainId), token: targetTokenAddress },
|
|
@@ -81,9 +89,13 @@ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, acc
|
|
|
81
89
|
const skipDelegation = hasNoData ||
|
|
82
90
|
isTokenTransfer ||
|
|
83
91
|
isHypercore ||
|
|
92
|
+
isHypercoreSource ||
|
|
84
93
|
(isPostQuote ?? false) ||
|
|
85
94
|
(isMaxAmount ?? false);
|
|
86
|
-
if (
|
|
95
|
+
if (isPostQuote && paymentOverride === constants_1.PaymentOverride.MoneyAccount) {
|
|
96
|
+
await processMoneyAccountPostQuote(transaction, normalizedRequest, body, messenger);
|
|
97
|
+
}
|
|
98
|
+
else if (!skipDelegation) {
|
|
87
99
|
const delegation = await messenger.call('TransactionPayController:getDelegationTransaction', { transaction });
|
|
88
100
|
body.calls = [
|
|
89
101
|
{
|
|
@@ -98,31 +110,72 @@ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, acc
|
|
|
98
110
|
},
|
|
99
111
|
];
|
|
100
112
|
if (delegation.authorizationList?.length) {
|
|
101
|
-
body.authorizationList = delegation.authorizationList
|
|
102
|
-
address: entry.address,
|
|
103
|
-
chainId: Number(entry.chainId),
|
|
104
|
-
nonce: Number(entry.nonce),
|
|
105
|
-
r: entry.r,
|
|
106
|
-
s: entry.s,
|
|
107
|
-
yParity: Number(entry.yParity),
|
|
108
|
-
}));
|
|
113
|
+
body.authorizationList = normalizeAuthorizationList(delegation.authorizationList);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
return body;
|
|
112
117
|
}
|
|
118
|
+
function normalizeAuthorizationList(authorizationList) {
|
|
119
|
+
return authorizationList.map((entry) => ({
|
|
120
|
+
address: entry.address,
|
|
121
|
+
chainId: Number(entry.chainId),
|
|
122
|
+
nonce: Number(entry.nonce),
|
|
123
|
+
r: entry.r,
|
|
124
|
+
s: entry.s,
|
|
125
|
+
yParity: Number(entry.yParity),
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
async function processMoneyAccountPostQuote(transaction, request, body, messenger) {
|
|
129
|
+
const { transactionData: transactionDataList } = messenger.call('TransactionPayController:getState');
|
|
130
|
+
const transactionData = transactionDataList[transaction.id];
|
|
131
|
+
const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0';
|
|
132
|
+
const { calls: overrideCalls, recipient, authorizationList, } = await messenger.call('TransactionPayController:getPaymentOverrideData', {
|
|
133
|
+
amount: amountHuman,
|
|
134
|
+
transaction,
|
|
135
|
+
transactionData,
|
|
136
|
+
});
|
|
137
|
+
if (!overrideCalls.length) {
|
|
138
|
+
log('No payment override calls for money account post-quote');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const fundingRecipient = recipient ?? request.from;
|
|
142
|
+
body.tradeType = types_1.ServerTradeType.ExactInput;
|
|
143
|
+
body.amount = request.sourceTokenAmount;
|
|
144
|
+
body.calls = [
|
|
145
|
+
{
|
|
146
|
+
data: buildTransferData(fundingRecipient, request.sourceTokenAmount),
|
|
147
|
+
to: request.targetTokenAddress,
|
|
148
|
+
value: '0x0',
|
|
149
|
+
},
|
|
150
|
+
...overrideCalls.map((call) => ({
|
|
151
|
+
data: call.data,
|
|
152
|
+
to: call.to,
|
|
153
|
+
value: call.value ?? '0x0',
|
|
154
|
+
})),
|
|
155
|
+
];
|
|
156
|
+
if (authorizationList?.length) {
|
|
157
|
+
body.authorizationList = normalizeAuthorizationList(authorizationList);
|
|
158
|
+
}
|
|
159
|
+
log('Added money account post-quote calls to server quote body', {
|
|
160
|
+
callCount: overrideCalls.length,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
113
163
|
function shouldRequestQuote(quoteRequest) {
|
|
114
164
|
return (quoteRequest.targetAmountMinimum !== '0' ||
|
|
115
165
|
Boolean(quoteRequest.isPostQuote) ||
|
|
116
|
-
Boolean(quoteRequest.isMaxAmount)
|
|
166
|
+
Boolean(quoteRequest.isMaxAmount) ||
|
|
167
|
+
Boolean(quoteRequest.isHyperliquidSource));
|
|
117
168
|
}
|
|
118
169
|
async function normalizeQuote(result, quoteRequest, messenger) {
|
|
119
170
|
const { quote } = result;
|
|
120
171
|
const { gasless } = quote;
|
|
172
|
+
const transactionSteps = quote.steps.filter(isTransactionStep);
|
|
173
|
+
const isSignatureOnly = transactionSteps.length === 0;
|
|
121
174
|
const sourceNetwork = await calculateSourceNetworkCost({
|
|
122
|
-
gasless,
|
|
175
|
+
gasless: gasless || isSignatureOnly,
|
|
123
176
|
messenger,
|
|
124
177
|
quoteRequest,
|
|
125
|
-
steps:
|
|
178
|
+
steps: transactionSteps,
|
|
126
179
|
});
|
|
127
180
|
const sourceFiatRate = (0, token_1.getTokenFiatRate)(messenger, quoteRequest.sourceTokenAddress, quoteRequest.sourceChainId);
|
|
128
181
|
const usdToFiatRate = sourceFiatRate
|
|
@@ -196,10 +249,6 @@ async function calculateSourceNetworkCost({ gasless, messenger, quoteRequest, st
|
|
|
196
249
|
log('Zeroing source network fees for gasless quote');
|
|
197
250
|
return noFees;
|
|
198
251
|
}
|
|
199
|
-
if (steps.length === 0) {
|
|
200
|
-
log('No quote steps; zeroing source network fees');
|
|
201
|
-
return noFees;
|
|
202
|
-
}
|
|
203
252
|
const { from, sourceChainId, sourceTokenAddress } = quoteRequest;
|
|
204
253
|
const firstStep = steps[0];
|
|
205
254
|
const chainIdHex = (0, controller_utils_1.toHex)(firstStep.chainId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-quotes.cjs","sourceRoot":"","sources":["../../../src/strategy/server/server-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { CHAIN_ID_HYPERCORE, TransactionPayStrategy } from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayFees,\n TransactionPayQuote,\n} from '../../types';\nimport { getFiatValueFromUsd } from '../../utils/amounts';\nimport {\n getFeatureFlags,\n getSlippage,\n isEIP7702Chain,\n} from '../../utils/feature-flags';\nimport { calculateGasCost, getGasFee } from '../../utils/gas';\nimport {\n getGasStationCostInSourceTokenRaw,\n getGasStationEligibility,\n} from '../../utils/gas-station';\nimport { estimateQuoteGasLimits } from '../../utils/quote-gas';\nimport type { QuoteGasTransaction } from '../../utils/quote-gas';\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenFiatRate,\n} from '../../utils/token';\nimport { normalizeServerPerpsRequest } from './perps';\nimport { fetchServerQuote } from './server-api';\nimport type {\n ServerQuote,\n ServerQuoteRequest,\n ServerQuoteResult,\n ServerQuoteStep,\n} from './types';\nimport { ServerTradeType } from './types';\n\nconst log = createModuleLogger(projectLogger, 'server-quotes');\nconst TOKEN_TRANSFER_FOUR_BYTE = '0xa9059cbb';\nconst TRANSFER_INTERFACE = new Interface([\n 'function transfer(address to, uint256 amount)',\n]);\nconst ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };\nconst ZERO_FIAT_VALUE = { fiat: '0', usd: '0' };\n\ntype FulfilledServerQuoteResult = ServerQuoteResult & {\n quote: NonNullable<ServerQuoteResult['quote']>;\n};\n\ntype SourceNetworkCost = Pick<\n TransactionPayFees['sourceNetwork'],\n 'estimate' | 'max'\n> & {\n gasLimits: number[];\n is7702: boolean;\n isSourceGasFeeToken?: boolean;\n maxFeePerGas: string | undefined;\n maxPriorityFeePerGas: string | undefined;\n};\n\n/**\n * Fetch server intents-api quotes and normalize them into Transaction Pay quotes.\n *\n * @param request - Quote request context.\n * @returns Normalized server strategy quotes.\n */\nexport async function getServerQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<ServerQuote>[]> {\n const quoteRequests = request.requests.filter(shouldRequestQuote);\n\n log('Fetching quotes', { quoteRequests });\n\n const quotes = await Promise.all(\n quoteRequests.map((quoteRequest) =>\n getQuotesForRequest(quoteRequest, request),\n ),\n );\n\n return quotes.flat();\n}\n\nasync function getQuotesForRequest(\n quoteRequest: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<ServerQuote>[]> {\n const { accountSupports7702, messenger, signal, transaction } = fullRequest;\n\n const body = await buildServerQuoteRequest(\n quoteRequest,\n transaction,\n messenger,\n accountSupports7702,\n );\n\n try {\n log('Request body', body);\n\n const response = await fetchServerQuote(messenger, body, signal);\n\n log('Raw quote response', response);\n\n const fulfilledResults = response.results.filter(isFulfilledResult);\n\n const normalized = await Promise.all(\n fulfilledResults.map((result) =>\n normalizeQuote(result, quoteRequest, messenger),\n ),\n );\n\n log('Normalized quotes', normalized);\n\n return normalized;\n } catch (error) {\n log('Error fetching quotes', { error });\n return [];\n }\n}\n\nasync function buildServerQuoteRequest(\n quoteRequest: QuoteRequest,\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n accountSupports7702: boolean,\n): Promise<ServerQuoteRequest> {\n const normalizedRequest = normalizeServerPerpsRequest(\n quoteRequest,\n transaction,\n );\n const {\n from,\n isMaxAmount,\n isPostQuote,\n sourceChainId,\n sourceTokenAddress,\n sourceTokenAmount,\n targetAmountMinimum,\n targetChainId,\n targetTokenAddress,\n } = normalizedRequest;\n\n const useExactInput = (isMaxAmount ?? false) || (isPostQuote ?? false);\n const singleData = getSingleTransactionData(transaction);\n const isHypercore = targetChainId === CHAIN_ID_HYPERCORE;\n const isTokenTransfer =\n !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));\n\n let recipient = from;\n\n if (isTokenTransfer && singleData) {\n recipient = decodeTransferRecipient(singleData);\n }\n\n const supportsGasless =\n accountSupports7702 && isEIP7702Chain(messenger, sourceChainId);\n\n const body: ServerQuoteRequest = {\n source: { chainId: Number(sourceChainId), token: sourceTokenAddress },\n target: { chainId: Number(targetChainId), token: targetTokenAddress },\n amount: useExactInput ? sourceTokenAmount : targetAmountMinimum,\n tradeType: useExactInput\n ? ServerTradeType.ExactInput\n : ServerTradeType.ExpectedOutput,\n sender: from,\n recipient,\n slippage: Math.round(\n getSlippage(messenger, sourceChainId, sourceTokenAddress) * 10000,\n ),\n supportsGasless,\n };\n\n const hasNoData = singleData === undefined || singleData === '0x';\n const skipDelegation =\n hasNoData ||\n isTokenTransfer ||\n isHypercore ||\n (isPostQuote ?? false) ||\n (isMaxAmount ?? false);\n\n if (!skipDelegation) {\n const delegation = await messenger.call(\n 'TransactionPayController:getDelegationTransaction',\n { transaction },\n );\n\n body.calls = [\n {\n data: buildTransferData(from, targetAmountMinimum),\n to: targetTokenAddress,\n value: '0x0',\n },\n {\n data: delegation.data,\n to: delegation.to,\n value: delegation.value,\n },\n ];\n\n if (delegation.authorizationList?.length) {\n body.authorizationList = delegation.authorizationList.map((entry) => ({\n address: entry.address,\n chainId: Number(entry.chainId),\n nonce: Number(entry.nonce),\n r: entry.r as Hex,\n s: entry.s as Hex,\n yParity: Number(entry.yParity),\n }));\n }\n }\n\n return body;\n}\n\nfunction shouldRequestQuote(quoteRequest: QuoteRequest): boolean {\n return (\n quoteRequest.targetAmountMinimum !== '0' ||\n Boolean(quoteRequest.isPostQuote) ||\n Boolean(quoteRequest.isMaxAmount)\n );\n}\n\nasync function normalizeQuote(\n result: FulfilledServerQuoteResult,\n quoteRequest: QuoteRequest,\n messenger: TransactionPayControllerMessenger,\n): Promise<TransactionPayQuote<ServerQuote>> {\n const { quote } = result;\n const { gasless } = quote;\n const sourceNetwork = await calculateSourceNetworkCost({\n gasless,\n messenger,\n quoteRequest,\n steps: quote.steps,\n });\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n quoteRequest.sourceTokenAddress,\n quoteRequest.sourceChainId,\n );\n\n const usdToFiatRate = sourceFiatRate\n ? new BigNumber(sourceFiatRate.fiatRate).dividedBy(sourceFiatRate.usdRate)\n : new BigNumber(1);\n\n const metaMask = getFiatValueFromUsd(\n new BigNumber(quote.fees.metamask),\n usdToFiatRate,\n );\n\n const provider = getFiatValueFromUsd(\n new BigNumber(quote.fees.provider),\n usdToFiatRate,\n );\n\n return {\n dust: ZERO_FIAT_VALUE,\n estimatedDuration: quote.duration,\n fees: {\n ...(sourceNetwork.isSourceGasFeeToken\n ? { isSourceGasFeeToken: true }\n : {}),\n metaMask,\n provider,\n sourceNetwork: {\n estimate: sourceNetwork.estimate,\n max: sourceNetwork.max,\n },\n targetNetwork: ZERO_FIAT_VALUE,\n },\n original: {\n client: {\n gasLimits: sourceNetwork.gasLimits,\n is7702: sourceNetwork.is7702,\n maxFeePerGas: sourceNetwork.maxFeePerGas,\n maxPriorityFeePerGas: sourceNetwork.maxPriorityFeePerGas,\n },\n duration: quote.duration,\n fees: quote.fees,\n gasless,\n id: quote.id,\n input: quote.input,\n output: quote.output,\n provider: result.provider,\n steps: quote.steps,\n },\n request: quoteRequest,\n sourceAmount: {\n fiat: sourceFiatRate\n ? new BigNumber(quote.input.formatted)\n .multipliedBy(sourceFiatRate.fiatRate)\n .toString(10)\n : '0',\n human: quote.input.formatted,\n raw: quote.input.raw,\n usd: sourceFiatRate\n ? new BigNumber(quote.input.formatted)\n .multipliedBy(sourceFiatRate.usdRate)\n .toString(10)\n : '0',\n },\n strategy: TransactionPayStrategy.Server,\n targetAmount: {\n fiat: '0',\n usd: '0',\n },\n };\n}\n\nasync function calculateSourceNetworkCost({\n gasless,\n messenger,\n quoteRequest,\n steps,\n}: {\n gasless: boolean;\n messenger: TransactionPayControllerMessenger;\n quoteRequest: QuoteRequest;\n steps: ServerQuoteStep[];\n}): Promise<SourceNetworkCost> {\n const noFees = {\n estimate: ZERO_AMOUNT,\n gasLimits: [],\n is7702: false,\n max: ZERO_AMOUNT,\n maxFeePerGas: undefined,\n maxPriorityFeePerGas: undefined,\n };\n\n if (gasless) {\n log('Zeroing source network fees for gasless quote');\n return noFees;\n }\n\n if (steps.length === 0) {\n log('No quote steps; zeroing source network fees');\n return noFees;\n }\n\n const { from, sourceChainId, sourceTokenAddress } = quoteRequest;\n const firstStep = steps[0];\n const chainIdHex = toHex(firstStep.chainId);\n\n const needsGasFeeEstimate =\n !firstStep.maxFeePerGas && !firstStep.maxPriorityFeePerGas;\n\n const gasFeeEstimate = needsGasFeeEstimate\n ? getGasFee(chainIdHex, messenger)\n : { maxFeePerGas: undefined, maxPriorityFeePerGas: undefined };\n\n const maxFeePerGas = firstStep.maxFeePerGas ?? gasFeeEstimate.maxFeePerGas;\n const maxPriorityFeePerGas =\n firstStep.maxPriorityFeePerGas ?? gasFeeEstimate.maxPriorityFeePerGas;\n\n const gasTransactions = steps.map((step) => stepToGasTransaction(step, from));\n\n const gasResult = await estimateQuoteGasLimits({\n fallbackGas: getFeatureFlags(messenger).relayFallbackGas,\n fallbackOnSimulationFailure: true,\n messenger,\n transactions: gasTransactions,\n });\n\n const { is7702 } = gasResult;\n const gasLimits = is7702\n ? [gasResult.gasLimits[0].max]\n : gasResult.gasLimits.map((gasLimit) => gasLimit.max);\n\n const estimate = calculateGasCost({\n chainId: chainIdHex,\n gas: gasResult.totalGasEstimate,\n maxFeePerGas: maxFeePerGas ?? '0',\n maxPriorityFeePerGas: maxPriorityFeePerGas ?? '0',\n messenger,\n });\n\n const max = calculateGasCost({\n chainId: chainIdHex,\n gas: gasResult.totalGasLimit,\n isMax: true,\n maxFeePerGas: maxFeePerGas ?? '0',\n maxPriorityFeePerGas: maxPriorityFeePerGas ?? '0',\n messenger,\n });\n\n const nativeBalance = getTokenBalance(\n messenger,\n from,\n sourceChainId,\n getNativeToken(sourceChainId),\n );\n\n const fees = { maxFeePerGas, maxPriorityFeePerGas };\n\n if (new BigNumber(nativeBalance).isGreaterThanOrEqualTo(max.raw)) {\n return { estimate, gasLimits, is7702, max, ...fees };\n }\n\n const eligibility = getGasStationEligibility(messenger, sourceChainId);\n\n if (eligibility.isDisabledChain || !eligibility.chainSupportsGasStation) {\n log('Skipping gas station for source network', {\n isDisabledChain: eligibility.isDisabledChain,\n sourceChainId,\n supportsGasStation: eligibility.chainSupportsGasStation,\n });\n return { estimate, gasLimits, is7702, max, ...fees };\n }\n\n log('Checking gas fee tokens due to insufficient native balance', {\n max: max.raw,\n nativeBalance,\n });\n\n const gasFeeTokenCost = await getGasStationCostInSourceTokenRaw({\n firstStepData: {\n data: firstStep.data,\n to: firstStep.to,\n value: firstStep.value as Hex,\n },\n messenger,\n request: {\n from,\n sourceChainId,\n sourceTokenAddress,\n },\n totalGasEstimate: gasResult.totalGasEstimate,\n totalItemCount: steps.length,\n });\n\n if (!gasFeeTokenCost) {\n return { estimate, gasLimits, is7702, max, ...fees };\n }\n\n log('Using gas fee token for source network', { gasFeeTokenCost });\n\n return {\n estimate: gasFeeTokenCost,\n gasLimits,\n is7702,\n isSourceGasFeeToken: true,\n max: gasFeeTokenCost,\n ...fees,\n };\n}\n\nfunction stepToGasTransaction(\n step: ServerQuoteStep,\n from: Hex,\n): QuoteGasTransaction {\n return {\n chainId: toHex(step.chainId),\n data: step.data,\n from,\n to: step.to,\n value: step.value,\n };\n}\n\nfunction getSingleTransactionData(\n transaction: TransactionMeta,\n): Hex | undefined {\n for (const nested of transaction.nestedTransactions ?? []) {\n if (nested.data && nested.data !== '0x') {\n return nested.data;\n }\n }\n\n return transaction.txParams?.data as Hex | undefined;\n}\n\nfunction isFulfilledResult(\n result: ServerQuoteResult,\n): result is FulfilledServerQuoteResult {\n return (\n result.quote?.id !== undefined &&\n result.quote.input !== undefined &&\n result.quote.output !== undefined\n );\n}\n\nfunction decodeTransferRecipient(data: Hex): Hex {\n return TRANSFER_INTERFACE.decodeFunctionData(\n 'transfer',\n data,\n ).to.toLowerCase() as Hex;\n}\n\nfunction buildTransferData(recipient: Hex, amountRaw: string): Hex {\n return TRANSFER_INTERFACE.encodeFunctionData('transfer', [\n recipient,\n amountRaw,\n ]) as Hex;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server-quotes.cjs","sourceRoot":"","sources":["../../../src/strategy/server/server-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n CHAIN_ID_HYPERCORE,\n PaymentOverride,\n TransactionPayStrategy,\n} from '../../constants';\nimport { projectLogger } from '../../logger';\nimport type {\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayFees,\n TransactionPayQuote,\n} from '../../types';\nimport { getFiatValueFromUsd } from '../../utils/amounts';\nimport {\n getFeatureFlags,\n getSlippage,\n isEIP7702Chain,\n} from '../../utils/feature-flags';\nimport { calculateGasCost, getGasFee } from '../../utils/gas';\nimport {\n getGasStationCostInSourceTokenRaw,\n getGasStationEligibility,\n} from '../../utils/gas-station';\nimport { estimateQuoteGasLimits } from '../../utils/quote-gas';\nimport type { QuoteGasTransaction } from '../../utils/quote-gas';\nimport {\n getNativeToken,\n getTokenBalance,\n getTokenFiatRate,\n} from '../../utils/token';\nimport { normalizeServerPerpsRequest } from './perps';\nimport { fetchServerQuote } from './server-api';\nimport type {\n ServerQuote,\n ServerQuoteRequest,\n ServerQuoteResult,\n ServerTransactionStep,\n} from './types';\nimport { ServerTradeType } from './types';\n\nconst log = createModuleLogger(projectLogger, 'server-quotes');\nconst TOKEN_TRANSFER_FOUR_BYTE = '0xa9059cbb';\nconst TRANSFER_INTERFACE = new Interface([\n 'function transfer(address to, uint256 amount)',\n]);\nconst ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };\nconst ZERO_FIAT_VALUE = { fiat: '0', usd: '0' };\n\ntype FulfilledServerQuoteResult = ServerQuoteResult & {\n quote: NonNullable<ServerQuoteResult['quote']>;\n};\n\ntype SourceNetworkCost = Pick<\n TransactionPayFees['sourceNetwork'],\n 'estimate' | 'max'\n> & {\n gasLimits: number[];\n is7702: boolean;\n isSourceGasFeeToken?: boolean;\n maxFeePerGas: string | undefined;\n maxPriorityFeePerGas: string | undefined;\n};\n\nfunction isTransactionStep(\n step: ServerQuote['steps'][number],\n): step is ServerTransactionStep {\n return step.type === 'transaction';\n}\n\n/**\n * Fetch server intents-api quotes and normalize them into Transaction Pay quotes.\n *\n * @param request - Quote request context.\n * @returns Normalized server strategy quotes.\n */\nexport async function getServerQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<ServerQuote>[]> {\n const quoteRequests = request.requests.filter(shouldRequestQuote);\n\n log('Fetching quotes', { quoteRequests });\n\n const quotes = await Promise.all(\n quoteRequests.map((quoteRequest) =>\n getQuotesForRequest(quoteRequest, request),\n ),\n );\n\n return quotes.flat();\n}\n\nasync function getQuotesForRequest(\n quoteRequest: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<ServerQuote>[]> {\n const { accountSupports7702, messenger, signal, transaction } = fullRequest;\n\n const body = await buildServerQuoteRequest(\n quoteRequest,\n transaction,\n messenger,\n accountSupports7702,\n );\n\n try {\n log('Request body', body);\n\n const response = await fetchServerQuote(messenger, body, signal);\n\n log('Raw quote response', response);\n\n const fulfilledResults = response.results.filter(isFulfilledResult);\n\n const normalized = await Promise.all(\n fulfilledResults.map((result) =>\n normalizeQuote(result, quoteRequest, messenger),\n ),\n );\n\n log('Normalized quotes', normalized);\n\n return normalized;\n } catch (error) {\n log('Error fetching quotes', { error });\n return [];\n }\n}\n\nasync function buildServerQuoteRequest(\n quoteRequest: QuoteRequest,\n transaction: TransactionMeta,\n messenger: TransactionPayControllerMessenger,\n accountSupports7702: boolean,\n): Promise<ServerQuoteRequest> {\n const normalizedRequest = normalizeServerPerpsRequest(\n quoteRequest,\n transaction,\n );\n const {\n from,\n isMaxAmount,\n isPostQuote,\n paymentOverride,\n sourceChainId,\n sourceTokenAddress,\n sourceTokenAmount,\n targetAmountMinimum,\n targetChainId,\n targetTokenAddress,\n } = normalizedRequest;\n\n const useExactInput =\n (isMaxAmount ?? false) ||\n (isPostQuote ?? false) ||\n Boolean(normalizedRequest.isHyperliquidSource);\n const singleData = getSingleTransactionData(transaction);\n const isHypercore = targetChainId === CHAIN_ID_HYPERCORE;\n const isTokenTransfer =\n !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));\n\n let recipient = from;\n\n if (isTokenTransfer && singleData) {\n recipient = decodeTransferRecipient(singleData);\n }\n\n const isHypercoreSource = sourceChainId === CHAIN_ID_HYPERCORE;\n const supportsGasless =\n !isHypercoreSource &&\n accountSupports7702 &&\n isEIP7702Chain(messenger, sourceChainId);\n\n const body: ServerQuoteRequest = {\n source: { chainId: Number(sourceChainId), token: sourceTokenAddress },\n target: { chainId: Number(targetChainId), token: targetTokenAddress },\n amount: useExactInput ? sourceTokenAmount : targetAmountMinimum,\n tradeType: useExactInput\n ? ServerTradeType.ExactInput\n : ServerTradeType.ExpectedOutput,\n sender: from,\n recipient,\n slippage: Math.round(\n getSlippage(messenger, sourceChainId, sourceTokenAddress) * 10000,\n ),\n supportsGasless,\n };\n\n const hasNoData = singleData === undefined || singleData === '0x';\n const skipDelegation =\n hasNoData ||\n isTokenTransfer ||\n isHypercore ||\n isHypercoreSource ||\n (isPostQuote ?? false) ||\n (isMaxAmount ?? false);\n\n if (isPostQuote && paymentOverride === PaymentOverride.MoneyAccount) {\n await processMoneyAccountPostQuote(\n transaction,\n normalizedRequest,\n body,\n messenger,\n );\n } else if (!skipDelegation) {\n const delegation = await messenger.call(\n 'TransactionPayController:getDelegationTransaction',\n { transaction },\n );\n\n body.calls = [\n {\n data: buildTransferData(from, targetAmountMinimum),\n to: targetTokenAddress,\n value: '0x0',\n },\n {\n data: delegation.data,\n to: delegation.to,\n value: delegation.value,\n },\n ];\n\n if (delegation.authorizationList?.length) {\n body.authorizationList = normalizeAuthorizationList(\n delegation.authorizationList,\n );\n }\n }\n\n return body;\n}\n\nfunction normalizeAuthorizationList(\n authorizationList: AuthorizationList,\n): NonNullable<ServerQuoteRequest['authorizationList']> {\n return authorizationList.map((entry) => ({\n address: entry.address,\n chainId: Number(entry.chainId),\n nonce: Number(entry.nonce),\n r: entry.r as Hex,\n s: entry.s as Hex,\n yParity: Number(entry.yParity),\n }));\n}\n\nasync function processMoneyAccountPostQuote(\n transaction: TransactionMeta,\n request: QuoteRequest,\n body: ServerQuoteRequest,\n messenger: TransactionPayControllerMessenger,\n): Promise<void> {\n const { transactionData: transactionDataList } = messenger.call(\n 'TransactionPayController:getState',\n );\n\n const transactionData = transactionDataList[transaction.id];\n const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0';\n\n const {\n calls: overrideCalls,\n recipient,\n authorizationList,\n } = await messenger.call('TransactionPayController:getPaymentOverrideData', {\n amount: amountHuman,\n transaction,\n transactionData,\n });\n\n if (!overrideCalls.length) {\n log('No payment override calls for money account post-quote');\n return;\n }\n\n const fundingRecipient = recipient ?? request.from;\n\n body.tradeType = ServerTradeType.ExactInput;\n body.amount = request.sourceTokenAmount;\n\n body.calls = [\n {\n data: buildTransferData(fundingRecipient, request.sourceTokenAmount),\n to: request.targetTokenAddress,\n value: '0x0',\n },\n ...overrideCalls.map((call) => ({\n data: call.data as Hex,\n to: call.to as Hex,\n value: call.value ?? '0x0',\n })),\n ];\n\n if (authorizationList?.length) {\n body.authorizationList = normalizeAuthorizationList(authorizationList);\n }\n\n log('Added money account post-quote calls to server quote body', {\n callCount: overrideCalls.length,\n });\n}\n\nfunction shouldRequestQuote(quoteRequest: QuoteRequest): boolean {\n return (\n quoteRequest.targetAmountMinimum !== '0' ||\n Boolean(quoteRequest.isPostQuote) ||\n Boolean(quoteRequest.isMaxAmount) ||\n Boolean(quoteRequest.isHyperliquidSource)\n );\n}\n\nasync function normalizeQuote(\n result: FulfilledServerQuoteResult,\n quoteRequest: QuoteRequest,\n messenger: TransactionPayControllerMessenger,\n): Promise<TransactionPayQuote<ServerQuote>> {\n const { quote } = result;\n const { gasless } = quote;\n const transactionSteps = quote.steps.filter(isTransactionStep);\n const isSignatureOnly = transactionSteps.length === 0;\n const sourceNetwork = await calculateSourceNetworkCost({\n gasless: gasless || isSignatureOnly,\n messenger,\n quoteRequest,\n steps: transactionSteps,\n });\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n quoteRequest.sourceTokenAddress,\n quoteRequest.sourceChainId,\n );\n\n const usdToFiatRate = sourceFiatRate\n ? new BigNumber(sourceFiatRate.fiatRate).dividedBy(sourceFiatRate.usdRate)\n : new BigNumber(1);\n\n const metaMask = getFiatValueFromUsd(\n new BigNumber(quote.fees.metamask),\n usdToFiatRate,\n );\n\n const provider = getFiatValueFromUsd(\n new BigNumber(quote.fees.provider),\n usdToFiatRate,\n );\n\n return {\n dust: ZERO_FIAT_VALUE,\n estimatedDuration: quote.duration,\n fees: {\n ...(sourceNetwork.isSourceGasFeeToken\n ? { isSourceGasFeeToken: true }\n : {}),\n metaMask,\n provider,\n sourceNetwork: {\n estimate: sourceNetwork.estimate,\n max: sourceNetwork.max,\n },\n targetNetwork: ZERO_FIAT_VALUE,\n },\n original: {\n client: {\n gasLimits: sourceNetwork.gasLimits,\n is7702: sourceNetwork.is7702,\n maxFeePerGas: sourceNetwork.maxFeePerGas,\n maxPriorityFeePerGas: sourceNetwork.maxPriorityFeePerGas,\n },\n duration: quote.duration,\n fees: quote.fees,\n gasless,\n id: quote.id,\n input: quote.input,\n output: quote.output,\n provider: result.provider,\n steps: quote.steps,\n },\n request: quoteRequest,\n sourceAmount: {\n fiat: sourceFiatRate\n ? new BigNumber(quote.input.formatted)\n .multipliedBy(sourceFiatRate.fiatRate)\n .toString(10)\n : '0',\n human: quote.input.formatted,\n raw: quote.input.raw,\n usd: sourceFiatRate\n ? new BigNumber(quote.input.formatted)\n .multipliedBy(sourceFiatRate.usdRate)\n .toString(10)\n : '0',\n },\n strategy: TransactionPayStrategy.Server,\n targetAmount: {\n fiat: '0',\n usd: '0',\n },\n };\n}\n\nasync function calculateSourceNetworkCost({\n gasless,\n messenger,\n quoteRequest,\n steps,\n}: {\n gasless: boolean;\n messenger: TransactionPayControllerMessenger;\n quoteRequest: QuoteRequest;\n steps: ServerTransactionStep[];\n}): Promise<SourceNetworkCost> {\n const noFees = {\n estimate: ZERO_AMOUNT,\n gasLimits: [],\n is7702: false,\n max: ZERO_AMOUNT,\n maxFeePerGas: undefined,\n maxPriorityFeePerGas: undefined,\n };\n\n if (gasless) {\n log('Zeroing source network fees for gasless quote');\n return noFees;\n }\n\n const { from, sourceChainId, sourceTokenAddress } = quoteRequest;\n const firstStep = steps[0];\n const chainIdHex = toHex(firstStep.chainId);\n\n const needsGasFeeEstimate =\n !firstStep.maxFeePerGas && !firstStep.maxPriorityFeePerGas;\n\n const gasFeeEstimate = needsGasFeeEstimate\n ? getGasFee(chainIdHex, messenger)\n : { maxFeePerGas: undefined, maxPriorityFeePerGas: undefined };\n\n const maxFeePerGas = firstStep.maxFeePerGas ?? gasFeeEstimate.maxFeePerGas;\n const maxPriorityFeePerGas =\n firstStep.maxPriorityFeePerGas ?? gasFeeEstimate.maxPriorityFeePerGas;\n\n const gasTransactions = steps.map((step) => stepToGasTransaction(step, from));\n\n const gasResult = await estimateQuoteGasLimits({\n fallbackGas: getFeatureFlags(messenger).relayFallbackGas,\n fallbackOnSimulationFailure: true,\n messenger,\n transactions: gasTransactions,\n });\n\n const { is7702 } = gasResult;\n const gasLimits = is7702\n ? [gasResult.gasLimits[0].max]\n : gasResult.gasLimits.map((gasLimit) => gasLimit.max);\n\n const estimate = calculateGasCost({\n chainId: chainIdHex,\n gas: gasResult.totalGasEstimate,\n maxFeePerGas: maxFeePerGas ?? '0',\n maxPriorityFeePerGas: maxPriorityFeePerGas ?? '0',\n messenger,\n });\n\n const max = calculateGasCost({\n chainId: chainIdHex,\n gas: gasResult.totalGasLimit,\n isMax: true,\n maxFeePerGas: maxFeePerGas ?? '0',\n maxPriorityFeePerGas: maxPriorityFeePerGas ?? '0',\n messenger,\n });\n\n const nativeBalance = getTokenBalance(\n messenger,\n from,\n sourceChainId,\n getNativeToken(sourceChainId),\n );\n\n const fees = { maxFeePerGas, maxPriorityFeePerGas };\n\n if (new BigNumber(nativeBalance).isGreaterThanOrEqualTo(max.raw)) {\n return { estimate, gasLimits, is7702, max, ...fees };\n }\n\n const eligibility = getGasStationEligibility(messenger, sourceChainId);\n\n if (eligibility.isDisabledChain || !eligibility.chainSupportsGasStation) {\n log('Skipping gas station for source network', {\n isDisabledChain: eligibility.isDisabledChain,\n sourceChainId,\n supportsGasStation: eligibility.chainSupportsGasStation,\n });\n return { estimate, gasLimits, is7702, max, ...fees };\n }\n\n log('Checking gas fee tokens due to insufficient native balance', {\n max: max.raw,\n nativeBalance,\n });\n\n const gasFeeTokenCost = await getGasStationCostInSourceTokenRaw({\n firstStepData: {\n data: firstStep.data,\n to: firstStep.to,\n value: firstStep.value as Hex,\n },\n messenger,\n request: {\n from,\n sourceChainId,\n sourceTokenAddress,\n },\n totalGasEstimate: gasResult.totalGasEstimate,\n totalItemCount: steps.length,\n });\n\n if (!gasFeeTokenCost) {\n return { estimate, gasLimits, is7702, max, ...fees };\n }\n\n log('Using gas fee token for source network', { gasFeeTokenCost });\n\n return {\n estimate: gasFeeTokenCost,\n gasLimits,\n is7702,\n isSourceGasFeeToken: true,\n max: gasFeeTokenCost,\n ...fees,\n };\n}\n\nfunction stepToGasTransaction(\n step: ServerTransactionStep,\n from: Hex,\n): QuoteGasTransaction {\n return {\n chainId: toHex(step.chainId),\n data: step.data,\n from,\n to: step.to,\n value: step.value,\n };\n}\n\nfunction getSingleTransactionData(\n transaction: TransactionMeta,\n): Hex | undefined {\n for (const nested of transaction.nestedTransactions ?? []) {\n if (nested.data && nested.data !== '0x') {\n return nested.data;\n }\n }\n\n return transaction.txParams?.data as Hex | undefined;\n}\n\nfunction isFulfilledResult(\n result: ServerQuoteResult,\n): result is FulfilledServerQuoteResult {\n return (\n result.quote?.id !== undefined &&\n result.quote.input !== undefined &&\n result.quote.output !== undefined\n );\n}\n\nfunction decodeTransferRecipient(data: Hex): Hex {\n return TRANSFER_INTERFACE.decodeFunctionData(\n 'transfer',\n data,\n ).to.toLowerCase() as Hex;\n}\n\nfunction buildTransferData(recipient: Hex, amountRaw: string): Hex {\n return TRANSFER_INTERFACE.encodeFunctionData('transfer', [\n recipient,\n amountRaw,\n ]) as Hex;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-quotes.d.cts","sourceRoot":"","sources":["../../../src/strategy/server/server-quotes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-quotes.d.cts","sourceRoot":"","sources":["../../../src/strategy/server/server-quotes.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,wBAAoB;AAqBrB,OAAO,KAAK,EACV,WAAW,EAIZ,oBAAgB;AAgCjB;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC,CAY7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-quotes.d.mts","sourceRoot":"","sources":["../../../src/strategy/server/server-quotes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-quotes.d.mts","sourceRoot":"","sources":["../../../src/strategy/server/server-quotes.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,2BAA2B,EAI3B,mBAAmB,EACpB,wBAAoB;AAqBrB,OAAO,KAAK,EACV,WAAW,EAIZ,oBAAgB;AAgCjB;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC,CAY7C"}
|
|
@@ -2,7 +2,7 @@ import { Interface } from "@ethersproject/abi";
|
|
|
2
2
|
import { toHex } from "@metamask/controller-utils";
|
|
3
3
|
import { createModuleLogger } from "@metamask/utils";
|
|
4
4
|
import { BigNumber } from "bignumber.js";
|
|
5
|
-
import { CHAIN_ID_HYPERCORE, TransactionPayStrategy } from "../../constants.mjs";
|
|
5
|
+
import { CHAIN_ID_HYPERCORE, PaymentOverride, TransactionPayStrategy } from "../../constants.mjs";
|
|
6
6
|
import { projectLogger } from "../../logger.mjs";
|
|
7
7
|
import { getFiatValueFromUsd } from "../../utils/amounts.mjs";
|
|
8
8
|
import { getFeatureFlags, getSlippage, isEIP7702Chain } from "../../utils/feature-flags.mjs";
|
|
@@ -20,6 +20,9 @@ const TRANSFER_INTERFACE = new Interface([
|
|
|
20
20
|
]);
|
|
21
21
|
const ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };
|
|
22
22
|
const ZERO_FIAT_VALUE = { fiat: '0', usd: '0' };
|
|
23
|
+
function isTransactionStep(step) {
|
|
24
|
+
return step.type === 'transaction';
|
|
25
|
+
}
|
|
23
26
|
/**
|
|
24
27
|
* Fetch server intents-api quotes and normalize them into Transaction Pay quotes.
|
|
25
28
|
*
|
|
@@ -51,8 +54,10 @@ async function getQuotesForRequest(quoteRequest, fullRequest) {
|
|
|
51
54
|
}
|
|
52
55
|
async function buildServerQuoteRequest(quoteRequest, transaction, messenger, accountSupports7702) {
|
|
53
56
|
const normalizedRequest = normalizeServerPerpsRequest(quoteRequest, transaction);
|
|
54
|
-
const { from, isMaxAmount, isPostQuote, sourceChainId, sourceTokenAddress, sourceTokenAmount, targetAmountMinimum, targetChainId, targetTokenAddress, } = normalizedRequest;
|
|
55
|
-
const useExactInput = (isMaxAmount ?? false) ||
|
|
57
|
+
const { from, isMaxAmount, isPostQuote, paymentOverride, sourceChainId, sourceTokenAddress, sourceTokenAmount, targetAmountMinimum, targetChainId, targetTokenAddress, } = normalizedRequest;
|
|
58
|
+
const useExactInput = (isMaxAmount ?? false) ||
|
|
59
|
+
(isPostQuote ?? false) ||
|
|
60
|
+
Boolean(normalizedRequest.isHyperliquidSource);
|
|
56
61
|
const singleData = getSingleTransactionData(transaction);
|
|
57
62
|
const isHypercore = targetChainId === CHAIN_ID_HYPERCORE;
|
|
58
63
|
const isTokenTransfer = !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));
|
|
@@ -60,7 +65,10 @@ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, acc
|
|
|
60
65
|
if (isTokenTransfer && singleData) {
|
|
61
66
|
recipient = decodeTransferRecipient(singleData);
|
|
62
67
|
}
|
|
63
|
-
const
|
|
68
|
+
const isHypercoreSource = sourceChainId === CHAIN_ID_HYPERCORE;
|
|
69
|
+
const supportsGasless = !isHypercoreSource &&
|
|
70
|
+
accountSupports7702 &&
|
|
71
|
+
isEIP7702Chain(messenger, sourceChainId);
|
|
64
72
|
const body = {
|
|
65
73
|
source: { chainId: Number(sourceChainId), token: sourceTokenAddress },
|
|
66
74
|
target: { chainId: Number(targetChainId), token: targetTokenAddress },
|
|
@@ -77,9 +85,13 @@ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, acc
|
|
|
77
85
|
const skipDelegation = hasNoData ||
|
|
78
86
|
isTokenTransfer ||
|
|
79
87
|
isHypercore ||
|
|
88
|
+
isHypercoreSource ||
|
|
80
89
|
(isPostQuote ?? false) ||
|
|
81
90
|
(isMaxAmount ?? false);
|
|
82
|
-
if (
|
|
91
|
+
if (isPostQuote && paymentOverride === PaymentOverride.MoneyAccount) {
|
|
92
|
+
await processMoneyAccountPostQuote(transaction, normalizedRequest, body, messenger);
|
|
93
|
+
}
|
|
94
|
+
else if (!skipDelegation) {
|
|
83
95
|
const delegation = await messenger.call('TransactionPayController:getDelegationTransaction', { transaction });
|
|
84
96
|
body.calls = [
|
|
85
97
|
{
|
|
@@ -94,31 +106,72 @@ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, acc
|
|
|
94
106
|
},
|
|
95
107
|
];
|
|
96
108
|
if (delegation.authorizationList?.length) {
|
|
97
|
-
body.authorizationList = delegation.authorizationList
|
|
98
|
-
address: entry.address,
|
|
99
|
-
chainId: Number(entry.chainId),
|
|
100
|
-
nonce: Number(entry.nonce),
|
|
101
|
-
r: entry.r,
|
|
102
|
-
s: entry.s,
|
|
103
|
-
yParity: Number(entry.yParity),
|
|
104
|
-
}));
|
|
109
|
+
body.authorizationList = normalizeAuthorizationList(delegation.authorizationList);
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
return body;
|
|
108
113
|
}
|
|
114
|
+
function normalizeAuthorizationList(authorizationList) {
|
|
115
|
+
return authorizationList.map((entry) => ({
|
|
116
|
+
address: entry.address,
|
|
117
|
+
chainId: Number(entry.chainId),
|
|
118
|
+
nonce: Number(entry.nonce),
|
|
119
|
+
r: entry.r,
|
|
120
|
+
s: entry.s,
|
|
121
|
+
yParity: Number(entry.yParity),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
async function processMoneyAccountPostQuote(transaction, request, body, messenger) {
|
|
125
|
+
const { transactionData: transactionDataList } = messenger.call('TransactionPayController:getState');
|
|
126
|
+
const transactionData = transactionDataList[transaction.id];
|
|
127
|
+
const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0';
|
|
128
|
+
const { calls: overrideCalls, recipient, authorizationList, } = await messenger.call('TransactionPayController:getPaymentOverrideData', {
|
|
129
|
+
amount: amountHuman,
|
|
130
|
+
transaction,
|
|
131
|
+
transactionData,
|
|
132
|
+
});
|
|
133
|
+
if (!overrideCalls.length) {
|
|
134
|
+
log('No payment override calls for money account post-quote');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const fundingRecipient = recipient ?? request.from;
|
|
138
|
+
body.tradeType = ServerTradeType.ExactInput;
|
|
139
|
+
body.amount = request.sourceTokenAmount;
|
|
140
|
+
body.calls = [
|
|
141
|
+
{
|
|
142
|
+
data: buildTransferData(fundingRecipient, request.sourceTokenAmount),
|
|
143
|
+
to: request.targetTokenAddress,
|
|
144
|
+
value: '0x0',
|
|
145
|
+
},
|
|
146
|
+
...overrideCalls.map((call) => ({
|
|
147
|
+
data: call.data,
|
|
148
|
+
to: call.to,
|
|
149
|
+
value: call.value ?? '0x0',
|
|
150
|
+
})),
|
|
151
|
+
];
|
|
152
|
+
if (authorizationList?.length) {
|
|
153
|
+
body.authorizationList = normalizeAuthorizationList(authorizationList);
|
|
154
|
+
}
|
|
155
|
+
log('Added money account post-quote calls to server quote body', {
|
|
156
|
+
callCount: overrideCalls.length,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
109
159
|
function shouldRequestQuote(quoteRequest) {
|
|
110
160
|
return (quoteRequest.targetAmountMinimum !== '0' ||
|
|
111
161
|
Boolean(quoteRequest.isPostQuote) ||
|
|
112
|
-
Boolean(quoteRequest.isMaxAmount)
|
|
162
|
+
Boolean(quoteRequest.isMaxAmount) ||
|
|
163
|
+
Boolean(quoteRequest.isHyperliquidSource));
|
|
113
164
|
}
|
|
114
165
|
async function normalizeQuote(result, quoteRequest, messenger) {
|
|
115
166
|
const { quote } = result;
|
|
116
167
|
const { gasless } = quote;
|
|
168
|
+
const transactionSteps = quote.steps.filter(isTransactionStep);
|
|
169
|
+
const isSignatureOnly = transactionSteps.length === 0;
|
|
117
170
|
const sourceNetwork = await calculateSourceNetworkCost({
|
|
118
|
-
gasless,
|
|
171
|
+
gasless: gasless || isSignatureOnly,
|
|
119
172
|
messenger,
|
|
120
173
|
quoteRequest,
|
|
121
|
-
steps:
|
|
174
|
+
steps: transactionSteps,
|
|
122
175
|
});
|
|
123
176
|
const sourceFiatRate = getTokenFiatRate(messenger, quoteRequest.sourceTokenAddress, quoteRequest.sourceChainId);
|
|
124
177
|
const usdToFiatRate = sourceFiatRate
|
|
@@ -192,10 +245,6 @@ async function calculateSourceNetworkCost({ gasless, messenger, quoteRequest, st
|
|
|
192
245
|
log('Zeroing source network fees for gasless quote');
|
|
193
246
|
return noFees;
|
|
194
247
|
}
|
|
195
|
-
if (steps.length === 0) {
|
|
196
|
-
log('No quote steps; zeroing source network fees');
|
|
197
|
-
return noFees;
|
|
198
|
-
}
|
|
199
248
|
const { from, sourceChainId, sourceTokenAddress } = quoteRequest;
|
|
200
249
|
const firstStep = steps[0];
|
|
201
250
|
const chainIdHex = toHex(firstStep.chainId);
|