@metamask/transaction-pay-controller 24.0.3 → 25.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.
- package/CHANGELOG.md +28 -1
- package/dist/constants.cjs +8 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +7 -1
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +7 -1
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +8 -2
- package/dist/constants.mjs.map +1 -1
- package/dist/helpers/QuoteRefresher.cjs +2 -1
- package/dist/helpers/QuoteRefresher.cjs.map +1 -1
- package/dist/helpers/QuoteRefresher.d.cts.map +1 -1
- package/dist/helpers/QuoteRefresher.d.mts.map +1 -1
- package/dist/helpers/QuoteRefresher.mjs +2 -1
- package/dist/helpers/QuoteRefresher.mjs.map +1 -1
- package/dist/helpers/TransactionPayPublishHook.cjs +5 -3
- package/dist/helpers/TransactionPayPublishHook.cjs.map +1 -1
- package/dist/helpers/TransactionPayPublishHook.d.cts.map +1 -1
- package/dist/helpers/TransactionPayPublishHook.d.mts.map +1 -1
- package/dist/helpers/TransactionPayPublishHook.mjs +5 -3
- package/dist/helpers/TransactionPayPublishHook.mjs.map +1 -1
- package/dist/strategy/relay/relay-quotes.cjs +6 -6
- package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
- package/dist/strategy/relay/relay-quotes.d.cts.map +1 -1
- package/dist/strategy/relay/relay-quotes.d.mts.map +1 -1
- package/dist/strategy/relay/relay-quotes.mjs +8 -8
- package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
- 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/feature-flags.cjs +24 -1
- package/dist/utils/feature-flags.cjs.map +1 -1
- package/dist/utils/feature-flags.d.cts +9 -0
- package/dist/utils/feature-flags.d.cts.map +1 -1
- package/dist/utils/feature-flags.d.mts +9 -0
- package/dist/utils/feature-flags.d.mts.map +1 -1
- package/dist/utils/feature-flags.mjs +23 -1
- package/dist/utils/feature-flags.mjs.map +1 -1
- package/dist/utils/no-op-quote.cjs +55 -0
- package/dist/utils/no-op-quote.cjs.map +1 -0
- package/dist/utils/no-op-quote.d.cts +18 -0
- package/dist/utils/no-op-quote.d.cts.map +1 -0
- package/dist/utils/no-op-quote.d.mts +18 -0
- package/dist/utils/no-op-quote.d.mts.map +1 -0
- package/dist/utils/no-op-quote.mjs +51 -0
- package/dist/utils/no-op-quote.mjs.map +1 -0
- package/dist/utils/quotes.cjs +29 -6
- package/dist/utils/quotes.cjs.map +1 -1
- package/dist/utils/quotes.d.cts.map +1 -1
- package/dist/utils/quotes.d.mts.map +1 -1
- package/dist/utils/quotes.mjs +29 -6
- package/dist/utils/quotes.mjs.map +1 -1
- package/dist/utils/token.cjs +1 -1
- package/dist/utils/token.cjs.map +1 -1
- package/dist/utils/token.d.cts.map +1 -1
- package/dist/utils/token.d.mts.map +1 -1
- package/dist/utils/token.mjs +3 -3
- package/dist/utils/token.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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildNoOpQuote = void 0;
|
|
4
|
+
const constants_1 = require("../constants.cjs");
|
|
5
|
+
function zeroFiat() {
|
|
6
|
+
return { fiat: '0', usd: '0' };
|
|
7
|
+
}
|
|
8
|
+
function zeroAmount() {
|
|
9
|
+
return { ...zeroFiat(), human: '0', raw: '0' };
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Build a no-op quote for a transaction that needs no conversion.
|
|
13
|
+
*
|
|
14
|
+
* Stored instead of an empty quotes array when a payment token is selected
|
|
15
|
+
* but the route is direct (e.g. same token and chain, or sufficient balance).
|
|
16
|
+
* This gives clients and the publish hook an explicit marker to distinguish
|
|
17
|
+
* "no quote needed" from "quote needed but missing". No-op quotes use the
|
|
18
|
+
* `TransactionPayStrategy.None` strategy, cannot be executed, and must be
|
|
19
|
+
* ignored by fee totals and quote refreshes.
|
|
20
|
+
*
|
|
21
|
+
* @param from - Resolved wallet address for the transaction.
|
|
22
|
+
* @param paymentToken - Selected payment token.
|
|
23
|
+
* @returns The no-op quote.
|
|
24
|
+
*/
|
|
25
|
+
function buildNoOpQuote(from, paymentToken) {
|
|
26
|
+
return {
|
|
27
|
+
dust: zeroFiat(),
|
|
28
|
+
estimatedDuration: 0,
|
|
29
|
+
fees: {
|
|
30
|
+
metaMask: zeroFiat(),
|
|
31
|
+
provider: zeroFiat(),
|
|
32
|
+
sourceNetwork: {
|
|
33
|
+
estimate: zeroAmount(),
|
|
34
|
+
max: zeroAmount(),
|
|
35
|
+
},
|
|
36
|
+
targetNetwork: zeroFiat(),
|
|
37
|
+
},
|
|
38
|
+
original: null,
|
|
39
|
+
request: {
|
|
40
|
+
from,
|
|
41
|
+
sourceBalanceRaw: paymentToken.balanceRaw,
|
|
42
|
+
sourceChainId: paymentToken.chainId,
|
|
43
|
+
sourceTokenAddress: paymentToken.address,
|
|
44
|
+
sourceTokenAmount: '0',
|
|
45
|
+
targetAmountMinimum: '0',
|
|
46
|
+
targetChainId: paymentToken.chainId,
|
|
47
|
+
targetTokenAddress: paymentToken.address,
|
|
48
|
+
},
|
|
49
|
+
sourceAmount: zeroAmount(),
|
|
50
|
+
strategy: constants_1.TransactionPayStrategy.None,
|
|
51
|
+
targetAmount: zeroFiat(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
exports.buildNoOpQuote = buildNoOpQuote;
|
|
55
|
+
//# sourceMappingURL=no-op-quote.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-op-quote.cjs","sourceRoot":"","sources":["../../src/utils/no-op-quote.ts"],"names":[],"mappings":";;;AAEA,gDAAsD;AAQtD,SAAS,QAAQ;IACf,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,EAAE,GAAG,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,cAAc,CAC5B,IAAS,EACT,YAAqC;IAErC,OAAO;QACL,IAAI,EAAE,QAAQ,EAAE;QAChB,iBAAiB,EAAE,CAAC;QACpB,IAAI,EAAE;YACJ,QAAQ,EAAE,QAAQ,EAAE;YACpB,QAAQ,EAAE,QAAQ,EAAE;YACpB,aAAa,EAAE;gBACb,QAAQ,EAAE,UAAU,EAAE;gBACtB,GAAG,EAAE,UAAU,EAAE;aAClB;YACD,aAAa,EAAE,QAAQ,EAAE;SAC1B;QACD,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE;YACP,IAAI;YACJ,gBAAgB,EAAE,YAAY,CAAC,UAAU;YACzC,aAAa,EAAE,YAAY,CAAC,OAAO;YACnC,kBAAkB,EAAE,YAAY,CAAC,OAAO;YACxC,iBAAiB,EAAE,GAAG;YACtB,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,YAAY,CAAC,OAAO;YACnC,kBAAkB,EAAE,YAAY,CAAC,OAAO;SACzC;QACD,YAAY,EAAE,UAAU,EAAE;QAC1B,QAAQ,EAAE,kCAAsB,CAAC,IAAI;QACrC,YAAY,EAAE,QAAQ,EAAE;KACzB,CAAC;AACJ,CAAC;AA/BD,wCA+BC","sourcesContent":["import type { Hex, Json } from '@metamask/utils';\n\nimport { TransactionPayStrategy } from '../constants';\nimport type {\n Amount,\n FiatValue,\n TransactionPaymentToken,\n TransactionPayQuote,\n} from '../types';\n\nfunction zeroFiat(): FiatValue {\n return { fiat: '0', usd: '0' };\n}\n\nfunction zeroAmount(): Amount {\n return { ...zeroFiat(), human: '0', raw: '0' };\n}\n\n/**\n * Build a no-op quote for a transaction that needs no conversion.\n *\n * Stored instead of an empty quotes array when a payment token is selected\n * but the route is direct (e.g. same token and chain, or sufficient balance).\n * This gives clients and the publish hook an explicit marker to distinguish\n * \"no quote needed\" from \"quote needed but missing\". No-op quotes use the\n * `TransactionPayStrategy.None` strategy, cannot be executed, and must be\n * ignored by fee totals and quote refreshes.\n *\n * @param from - Resolved wallet address for the transaction.\n * @param paymentToken - Selected payment token.\n * @returns The no-op quote.\n */\nexport function buildNoOpQuote(\n from: Hex,\n paymentToken: TransactionPaymentToken,\n): TransactionPayQuote<Json> {\n return {\n dust: zeroFiat(),\n estimatedDuration: 0,\n fees: {\n metaMask: zeroFiat(),\n provider: zeroFiat(),\n sourceNetwork: {\n estimate: zeroAmount(),\n max: zeroAmount(),\n },\n targetNetwork: zeroFiat(),\n },\n original: null,\n request: {\n from,\n sourceBalanceRaw: paymentToken.balanceRaw,\n sourceChainId: paymentToken.chainId,\n sourceTokenAddress: paymentToken.address,\n sourceTokenAmount: '0',\n targetAmountMinimum: '0',\n targetChainId: paymentToken.chainId,\n targetTokenAddress: paymentToken.address,\n },\n sourceAmount: zeroAmount(),\n strategy: TransactionPayStrategy.None,\n targetAmount: zeroFiat(),\n };\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Hex, Json } from "@metamask/utils";
|
|
2
|
+
import type { TransactionPaymentToken, TransactionPayQuote } from "../types.cjs";
|
|
3
|
+
/**
|
|
4
|
+
* Build a no-op quote for a transaction that needs no conversion.
|
|
5
|
+
*
|
|
6
|
+
* Stored instead of an empty quotes array when a payment token is selected
|
|
7
|
+
* but the route is direct (e.g. same token and chain, or sufficient balance).
|
|
8
|
+
* This gives clients and the publish hook an explicit marker to distinguish
|
|
9
|
+
* "no quote needed" from "quote needed but missing". No-op quotes use the
|
|
10
|
+
* `TransactionPayStrategy.None` strategy, cannot be executed, and must be
|
|
11
|
+
* ignored by fee totals and quote refreshes.
|
|
12
|
+
*
|
|
13
|
+
* @param from - Resolved wallet address for the transaction.
|
|
14
|
+
* @param paymentToken - Selected payment token.
|
|
15
|
+
* @returns The no-op quote.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildNoOpQuote(from: Hex, paymentToken: TransactionPaymentToken): TransactionPayQuote<Json>;
|
|
18
|
+
//# sourceMappingURL=no-op-quote.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-op-quote.d.cts","sourceRoot":"","sources":["../../src/utils/no-op-quote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,wBAAwB;AAGjD,OAAO,KAAK,EAGV,uBAAuB,EACvB,mBAAmB,EACpB,qBAAiB;AAUlB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,uBAAuB,GACpC,mBAAmB,CAAC,IAAI,CAAC,CA4B3B"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Hex, Json } from "@metamask/utils";
|
|
2
|
+
import type { TransactionPaymentToken, TransactionPayQuote } from "../types.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Build a no-op quote for a transaction that needs no conversion.
|
|
5
|
+
*
|
|
6
|
+
* Stored instead of an empty quotes array when a payment token is selected
|
|
7
|
+
* but the route is direct (e.g. same token and chain, or sufficient balance).
|
|
8
|
+
* This gives clients and the publish hook an explicit marker to distinguish
|
|
9
|
+
* "no quote needed" from "quote needed but missing". No-op quotes use the
|
|
10
|
+
* `TransactionPayStrategy.None` strategy, cannot be executed, and must be
|
|
11
|
+
* ignored by fee totals and quote refreshes.
|
|
12
|
+
*
|
|
13
|
+
* @param from - Resolved wallet address for the transaction.
|
|
14
|
+
* @param paymentToken - Selected payment token.
|
|
15
|
+
* @returns The no-op quote.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildNoOpQuote(from: Hex, paymentToken: TransactionPaymentToken): TransactionPayQuote<Json>;
|
|
18
|
+
//# sourceMappingURL=no-op-quote.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-op-quote.d.mts","sourceRoot":"","sources":["../../src/utils/no-op-quote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,wBAAwB;AAGjD,OAAO,KAAK,EAGV,uBAAuB,EACvB,mBAAmB,EACpB,qBAAiB;AAUlB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,GAAG,EACT,YAAY,EAAE,uBAAuB,GACpC,mBAAmB,CAAC,IAAI,CAAC,CA4B3B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { TransactionPayStrategy } from "../constants.mjs";
|
|
2
|
+
function zeroFiat() {
|
|
3
|
+
return { fiat: '0', usd: '0' };
|
|
4
|
+
}
|
|
5
|
+
function zeroAmount() {
|
|
6
|
+
return { ...zeroFiat(), human: '0', raw: '0' };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Build a no-op quote for a transaction that needs no conversion.
|
|
10
|
+
*
|
|
11
|
+
* Stored instead of an empty quotes array when a payment token is selected
|
|
12
|
+
* but the route is direct (e.g. same token and chain, or sufficient balance).
|
|
13
|
+
* This gives clients and the publish hook an explicit marker to distinguish
|
|
14
|
+
* "no quote needed" from "quote needed but missing". No-op quotes use the
|
|
15
|
+
* `TransactionPayStrategy.None` strategy, cannot be executed, and must be
|
|
16
|
+
* ignored by fee totals and quote refreshes.
|
|
17
|
+
*
|
|
18
|
+
* @param from - Resolved wallet address for the transaction.
|
|
19
|
+
* @param paymentToken - Selected payment token.
|
|
20
|
+
* @returns The no-op quote.
|
|
21
|
+
*/
|
|
22
|
+
export function buildNoOpQuote(from, paymentToken) {
|
|
23
|
+
return {
|
|
24
|
+
dust: zeroFiat(),
|
|
25
|
+
estimatedDuration: 0,
|
|
26
|
+
fees: {
|
|
27
|
+
metaMask: zeroFiat(),
|
|
28
|
+
provider: zeroFiat(),
|
|
29
|
+
sourceNetwork: {
|
|
30
|
+
estimate: zeroAmount(),
|
|
31
|
+
max: zeroAmount(),
|
|
32
|
+
},
|
|
33
|
+
targetNetwork: zeroFiat(),
|
|
34
|
+
},
|
|
35
|
+
original: null,
|
|
36
|
+
request: {
|
|
37
|
+
from,
|
|
38
|
+
sourceBalanceRaw: paymentToken.balanceRaw,
|
|
39
|
+
sourceChainId: paymentToken.chainId,
|
|
40
|
+
sourceTokenAddress: paymentToken.address,
|
|
41
|
+
sourceTokenAmount: '0',
|
|
42
|
+
targetAmountMinimum: '0',
|
|
43
|
+
targetChainId: paymentToken.chainId,
|
|
44
|
+
targetTokenAddress: paymentToken.address,
|
|
45
|
+
},
|
|
46
|
+
sourceAmount: zeroAmount(),
|
|
47
|
+
strategy: TransactionPayStrategy.None,
|
|
48
|
+
targetAmount: zeroFiat(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=no-op-quote.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-op-quote.mjs","sourceRoot":"","sources":["../../src/utils/no-op-quote.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,yBAAqB;AAQtD,SAAS,QAAQ;IACf,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,EAAE,GAAG,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAS,EACT,YAAqC;IAErC,OAAO;QACL,IAAI,EAAE,QAAQ,EAAE;QAChB,iBAAiB,EAAE,CAAC;QACpB,IAAI,EAAE;YACJ,QAAQ,EAAE,QAAQ,EAAE;YACpB,QAAQ,EAAE,QAAQ,EAAE;YACpB,aAAa,EAAE;gBACb,QAAQ,EAAE,UAAU,EAAE;gBACtB,GAAG,EAAE,UAAU,EAAE;aAClB;YACD,aAAa,EAAE,QAAQ,EAAE;SAC1B;QACD,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE;YACP,IAAI;YACJ,gBAAgB,EAAE,YAAY,CAAC,UAAU;YACzC,aAAa,EAAE,YAAY,CAAC,OAAO;YACnC,kBAAkB,EAAE,YAAY,CAAC,OAAO;YACxC,iBAAiB,EAAE,GAAG;YACtB,mBAAmB,EAAE,GAAG;YACxB,aAAa,EAAE,YAAY,CAAC,OAAO;YACnC,kBAAkB,EAAE,YAAY,CAAC,OAAO;SACzC;QACD,YAAY,EAAE,UAAU,EAAE;QAC1B,QAAQ,EAAE,sBAAsB,CAAC,IAAI;QACrC,YAAY,EAAE,QAAQ,EAAE;KACzB,CAAC;AACJ,CAAC","sourcesContent":["import type { Hex, Json } from '@metamask/utils';\n\nimport { TransactionPayStrategy } from '../constants';\nimport type {\n Amount,\n FiatValue,\n TransactionPaymentToken,\n TransactionPayQuote,\n} from '../types';\n\nfunction zeroFiat(): FiatValue {\n return { fiat: '0', usd: '0' };\n}\n\nfunction zeroAmount(): Amount {\n return { ...zeroFiat(), human: '0', raw: '0' };\n}\n\n/**\n * Build a no-op quote for a transaction that needs no conversion.\n *\n * Stored instead of an empty quotes array when a payment token is selected\n * but the route is direct (e.g. same token and chain, or sufficient balance).\n * This gives clients and the publish hook an explicit marker to distinguish\n * \"no quote needed\" from \"quote needed but missing\". No-op quotes use the\n * `TransactionPayStrategy.None` strategy, cannot be executed, and must be\n * ignored by fee totals and quote refreshes.\n *\n * @param from - Resolved wallet address for the transaction.\n * @param paymentToken - Selected payment token.\n * @returns The no-op quote.\n */\nexport function buildNoOpQuote(\n from: Hex,\n paymentToken: TransactionPaymentToken,\n): TransactionPayQuote<Json> {\n return {\n dust: zeroFiat(),\n estimatedDuration: 0,\n fees: {\n metaMask: zeroFiat(),\n provider: zeroFiat(),\n sourceNetwork: {\n estimate: zeroAmount(),\n max: zeroAmount(),\n },\n targetNetwork: zeroFiat(),\n },\n original: null,\n request: {\n from,\n sourceBalanceRaw: paymentToken.balanceRaw,\n sourceChainId: paymentToken.chainId,\n sourceTokenAddress: paymentToken.address,\n sourceTokenAmount: '0',\n targetAmountMinimum: '0',\n targetChainId: paymentToken.chainId,\n targetTokenAddress: paymentToken.address,\n },\n sourceAmount: zeroAmount(),\n strategy: TransactionPayStrategy.None,\n targetAmount: zeroFiat(),\n };\n}\n"]}
|
package/dist/utils/quotes.cjs
CHANGED
|
@@ -6,6 +6,7 @@ const utils_1 = require("@metamask/utils");
|
|
|
6
6
|
const constants_1 = require("../constants.cjs");
|
|
7
7
|
const logger_1 = require("../logger.cjs");
|
|
8
8
|
const _7702_1 = require("./7702.cjs");
|
|
9
|
+
const no_op_quote_1 = require("./no-op-quote.cjs");
|
|
9
10
|
const strategy_1 = require("./strategy.cjs");
|
|
10
11
|
const token_1 = require("./token.cjs");
|
|
11
12
|
const totals_1 = require("./totals.cjs");
|
|
@@ -34,7 +35,7 @@ async function updateQuotes(request) {
|
|
|
34
35
|
return false;
|
|
35
36
|
}
|
|
36
37
|
log('Updating quotes', { transactionId });
|
|
37
|
-
const { accountOverride, isMaxAmount, isPostQuote, isHyperliquidSource, isPolymarketDepositWallet, paymentOverride, paymentToken: originalPaymentToken, fiatPayment, refundTo, sourceAmounts, tokens, } = transactionData;
|
|
38
|
+
const { accountOverride, isMaxAmount, isPostQuote, isHyperliquidSource, isPolymarketDepositWallet, isQuoteRequired, paymentOverride, paymentToken: originalPaymentToken, fiatPayment, refundTo, sourceAmounts, tokens, } = transactionData;
|
|
38
39
|
const from = accountOverride ?? transaction.txParams.from;
|
|
39
40
|
const controller = abortPreviousAndCreateController(transactionId);
|
|
40
41
|
const { signal } = controller;
|
|
@@ -68,16 +69,20 @@ async function updateQuotes(request) {
|
|
|
68
69
|
transactionId,
|
|
69
70
|
});
|
|
70
71
|
const supports7702 = (0, _7702_1.accountSupports7702)(messenger, from);
|
|
71
|
-
const { batchTransactions, quotes } = await getQuotes(transaction, from, requests, supports7702, getStrategies, messenger, fiatPayment?.selectedPaymentMethodId, signal);
|
|
72
|
+
const { batchTransactions, quotes } = await getQuotes(transaction, from, requests, paymentToken, isQuoteRequired ?? false, supports7702, getStrategies, messenger, fiatPayment?.selectedPaymentMethodId, signal);
|
|
72
73
|
if (signal.aborted) {
|
|
73
74
|
log('Quote request aborted before persisting results', { transactionId });
|
|
74
75
|
return false;
|
|
75
76
|
}
|
|
77
|
+
// No-op quotes mark direct routes. They have no fees or amounts and the
|
|
78
|
+
// transaction is signed and submitted locally, so totals and transaction
|
|
79
|
+
// sync must treat them as "no quotes".
|
|
80
|
+
const executableQuotes = quotes.filter((quote) => quote.strategy !== constants_1.TransactionPayStrategy.None);
|
|
76
81
|
const totals = (0, totals_1.calculateTotals)({
|
|
77
82
|
fiatPaymentAmount: fiatPayment?.amountFiat,
|
|
78
83
|
isMaxAmount,
|
|
79
84
|
messenger,
|
|
80
|
-
quotes:
|
|
85
|
+
quotes: executableQuotes,
|
|
81
86
|
tokens,
|
|
82
87
|
transaction,
|
|
83
88
|
});
|
|
@@ -85,7 +90,7 @@ async function updateQuotes(request) {
|
|
|
85
90
|
syncTransaction({
|
|
86
91
|
batchTransactions,
|
|
87
92
|
selectedFiatPayment: fiatPayment?.selectedPaymentMethodId,
|
|
88
|
-
hasQuotes:
|
|
93
|
+
hasQuotes: executableQuotes.length > 0,
|
|
89
94
|
isPostQuote,
|
|
90
95
|
messenger: messenger,
|
|
91
96
|
paymentToken,
|
|
@@ -181,6 +186,11 @@ async function refreshQuotes(messenger, updateTransactionData, getStrategies) {
|
|
|
181
186
|
if (isLoading || !quotes?.length) {
|
|
182
187
|
continue;
|
|
183
188
|
}
|
|
189
|
+
// No-op quotes mark direct routes and have nothing to refresh. They are
|
|
190
|
+
// regenerated whenever the transaction data changes.
|
|
191
|
+
if (quotes.every((quote) => quote.strategy === constants_1.TransactionPayStrategy.None)) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
184
194
|
const strategyName = quotes[0].strategy;
|
|
185
195
|
const strategy = (0, strategy_1.getStrategyByName)(strategyName);
|
|
186
196
|
const refreshInterval = (await strategy.getRefreshInterval?.({
|
|
@@ -364,6 +374,8 @@ async function refreshPaymentTokenBalance({ from, messenger, paymentToken, signa
|
|
|
364
374
|
* @param transaction - Transaction metadata.
|
|
365
375
|
* @param from - Resolved wallet address (`accountOverride ?? txParams.from`).
|
|
366
376
|
* @param requests - Quote requests.
|
|
377
|
+
* @param paymentToken - Selected payment token, if any.
|
|
378
|
+
* @param isQuoteRequired - Whether a quote is always required for the transaction.
|
|
367
379
|
* @param isAccountEIP7702Compatible - Whether the account supports EIP-7702.
|
|
368
380
|
* @param getStrategies - Callback to get ordered strategy names for a transaction.
|
|
369
381
|
* @param messenger - Controller messenger.
|
|
@@ -371,7 +383,7 @@ async function refreshPaymentTokenBalance({ from, messenger, paymentToken, signa
|
|
|
371
383
|
* @param signal - Signal that aborts when the quote request is superseded.
|
|
372
384
|
* @returns An object containing batch transactions and quotes.
|
|
373
385
|
*/
|
|
374
|
-
async function getQuotes(transaction, from, requests, isAccountEIP7702Compatible, getStrategies, messenger, fiatPaymentMethod, signal) {
|
|
386
|
+
async function getQuotes(transaction, from, requests, paymentToken, isQuoteRequired, isAccountEIP7702Compatible, getStrategies, messenger, fiatPaymentMethod, signal) {
|
|
375
387
|
const { id: transactionId } = transaction;
|
|
376
388
|
const strategies = (0, strategy_1.getStrategiesByName)(getStrategies(transaction), (strategyName) => {
|
|
377
389
|
log('Skipping unknown strategy', {
|
|
@@ -380,9 +392,20 @@ async function getQuotes(transaction, from, requests, isAccountEIP7702Compatible
|
|
|
380
392
|
});
|
|
381
393
|
});
|
|
382
394
|
if (!requests?.length && !fiatPaymentMethod) {
|
|
395
|
+
// A selected payment token with no conversion requests means the route is
|
|
396
|
+
// direct. Return an explicit no-op quote so clients and the publish hook
|
|
397
|
+
// can distinguish "no conversion needed" from "quote needed but missing".
|
|
398
|
+
// Not applicable when a quote is always required, as an empty requests
|
|
399
|
+
// list then means the source amounts could not be calculated.
|
|
400
|
+
const noOpQuote = paymentToken && !isQuoteRequired
|
|
401
|
+
? (0, no_op_quote_1.buildNoOpQuote)(from, paymentToken)
|
|
402
|
+
: undefined;
|
|
403
|
+
if (noOpQuote) {
|
|
404
|
+
log('Built no-op quote for direct route', { transactionId });
|
|
405
|
+
}
|
|
383
406
|
return {
|
|
384
407
|
batchTransactions: [],
|
|
385
|
-
quotes: [],
|
|
408
|
+
quotes: noOpQuote ? [noOpQuote] : [],
|
|
386
409
|
};
|
|
387
410
|
}
|
|
388
411
|
const request = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes.cjs","sourceRoot":"","sources":["../../src/utils/quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { TransactionStatus } from '@metamask/transaction-controller';\nimport type { BatchTransaction } from '@metamask/transaction-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex, Json } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { PaymentOverride, TransactionPayStrategy } from '../constants';\nimport { projectLogger } from '../logger';\nimport type {\n QuoteRequest,\n TransactionData,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n TransactionPayRequiredToken,\n TransactionPaySourceAmount,\n TransactionPayTotals,\n TransactionPaymentToken,\n UpdateTransactionDataCallback,\n} from '../types';\nimport { accountSupports7702 } from './7702';\nimport {\n checkStrategyQuoteSupport,\n checkStrategySupport,\n getStrategiesByName,\n getStrategyByName,\n} from './strategy';\nimport {\n computeTokenAmounts,\n getLiveTokenBalance,\n getTokenFiatRate,\n} from './token';\nimport { calculateTotals } from './totals';\nimport { getTransaction, updateTransaction } from './transaction';\n\nconst DEFAULT_REFRESH_INTERVAL = 30 * 1000; // 30 Seconds\n\nconst log = createModuleLogger(projectLogger, 'quotes');\n\nconst inFlightQuoteRequests = new Map<string, AbortController>();\n\nexport type UpdateQuotesRequest = {\n getStrategies: (transaction: TransactionMeta) => TransactionPayStrategy[];\n messenger: TransactionPayControllerMessenger;\n transactionData: TransactionData | undefined;\n transactionId: string;\n updateTransactionData: UpdateTransactionDataCallback;\n};\n\n/**\n * Update the quotes for a specific transaction.\n *\n * Calls for the same `transactionId` are serialised: a fresh call aborts any\n * previous in-flight call so a slower stale response cannot overwrite a newer\n * one in state.\n *\n * @param request - Request parameters.\n * @returns Boolean indicating if the quotes were updated. Returns `false` when\n * the call was aborted by a subsequent call for the same transaction.\n */\nexport async function updateQuotes(\n request: UpdateQuotesRequest,\n): Promise<boolean> {\n const {\n getStrategies,\n messenger,\n transactionData,\n transactionId,\n updateTransactionData,\n } = request;\n\n const transaction = getTransaction(transactionId, messenger);\n\n if (!transaction || !transactionData) {\n throw new Error('Transaction not found');\n }\n\n if (transaction?.status !== TransactionStatus.unapproved) {\n return false;\n }\n\n log('Updating quotes', { transactionId });\n\n const {\n accountOverride,\n isMaxAmount,\n isPostQuote,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n paymentToken: originalPaymentToken,\n fiatPayment,\n refundTo,\n sourceAmounts,\n tokens,\n } = transactionData;\n\n const from = accountOverride ?? (transaction.txParams.from as Hex);\n\n const controller = abortPreviousAndCreateController(transactionId);\n const { signal } = controller;\n\n updateTransactionData(transactionId, (data) => {\n data.isLoading = true;\n });\n\n try {\n const paymentToken = await refreshPaymentTokenBalance({\n from,\n messenger,\n paymentToken: originalPaymentToken,\n signal,\n transactionId,\n updateTransactionData,\n });\n\n if (signal.aborted) {\n log('Quote request aborted before building requests', { transactionId });\n return false;\n }\n\n const requests = buildQuoteRequests({\n from,\n isMaxAmount: isMaxAmount ?? false,\n isPostQuote,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n paymentToken,\n refundTo,\n sourceAmounts,\n tokens,\n transactionId,\n });\n\n const supports7702 = accountSupports7702(messenger, from);\n\n const { batchTransactions, quotes } = await getQuotes(\n transaction,\n from,\n requests,\n supports7702,\n getStrategies,\n messenger,\n fiatPayment?.selectedPaymentMethodId,\n signal,\n );\n\n if (signal.aborted) {\n log('Quote request aborted before persisting results', { transactionId });\n return false;\n }\n\n const totals = calculateTotals({\n fiatPaymentAmount: fiatPayment?.amountFiat,\n isMaxAmount,\n messenger,\n quotes: quotes as TransactionPayQuote<unknown>[],\n tokens,\n transaction,\n });\n\n log('Calculated totals', { transactionId, totals });\n\n syncTransaction({\n batchTransactions,\n selectedFiatPayment: fiatPayment?.selectedPaymentMethodId,\n hasQuotes: quotes.length > 0,\n isPostQuote,\n messenger: messenger as never,\n paymentToken,\n totals,\n transactionId,\n });\n\n updateTransactionData(transactionId, (data) => {\n data.quotes = quotes as never;\n data.quotesLastUpdated = Date.now();\n data.totals = totals;\n });\n } catch (error) {\n if (signal.aborted) {\n log('Quote request aborted', { transactionId, reason: signal.reason });\n return false;\n }\n throw error;\n } finally {\n if (!signal.aborted) {\n updateTransactionData(transactionId, (data) => {\n data.isLoading = false;\n });\n }\n clearControllerIfCurrent(transactionId, controller);\n }\n\n return true;\n}\n\n/**\n * Sync batch transactions to the transaction meta.\n *\n * @param request - Request object.\n * @param request.batchTransactions - Batch transactions to sync.\n * @param request.hasQuotes - Whether MM Pay produced any quotes for this transaction.\n * @param request.isPostQuote - Whether this is a post-quote flow.\n * @param request.messenger - Messenger instance.\n * @param request.paymentToken - Payment token (source for standard flows, destination for post-quote).\n * @param request.selectedFiatPayment - Selected fiat payment method ID.\n * @param request.totals - Calculated totals.\n * @param request.transactionId - ID of the transaction to sync.\n */\nfunction syncTransaction({\n batchTransactions,\n hasQuotes,\n isPostQuote,\n messenger,\n paymentToken,\n selectedFiatPayment,\n totals,\n transactionId,\n}: {\n batchTransactions: BatchTransaction[];\n selectedFiatPayment?: string;\n hasQuotes: boolean;\n isPostQuote?: boolean;\n messenger: TransactionPayControllerMessenger;\n paymentToken: TransactionPaymentToken | undefined;\n totals: TransactionPayTotals;\n transactionId: string;\n}): void {\n if (!paymentToken && !selectedFiatPayment) {\n return;\n }\n\n updateTransaction(\n {\n transactionId,\n messenger: messenger as never,\n note: 'Update transaction pay data',\n },\n (tx: TransactionMeta) => {\n tx.batchTransactions = batchTransactions;\n tx.batchTransactionsOptions = {};\n\n // When MM Pay has produced quotes, it owns submission of this transaction\n // via its strategy publish hook, so the parent must be marked externally\n // signed to skip the local `KeyringController:signTransaction` call.\n // When there are no quotes (e.g. user selected the target token as the\n // payment token in a Predict flow), the transaction falls back to normal\n // local signing, so the flag is cleared to allow that.\n // If gas is sponsored, TC owns this field — it is set based on the\n // Sentinel simulation result and must not be cleared here. Same-token\n // flows (e.g. Monad mUSD withdrawal via a Money Account) produce no\n // quotes but still need external sign because the account cannot sign\n // locally.\n if (!tx.isGasFeeSponsored) {\n tx.isExternalSign = hasQuotes;\n }\n\n tx.metamaskPay = {\n bridgeFeeFiat: totals.fees.provider.usd,\n chainId: paymentToken?.chainId,\n isPostQuote,\n networkFeeFiat: totals.fees.sourceNetwork.estimate.usd,\n targetFiat: totals.targetAmount.usd,\n tokenAddress: paymentToken?.address,\n totalFiat: totals.total.usd,\n };\n },\n );\n}\n\n/**\n * Refresh quotes for all transactions if expired.\n *\n * @param messenger - Messenger instance.\n * @param updateTransactionData - Callback to update transaction data.\n * @param getStrategies - Callback to get ordered strategy names for a transaction.\n */\nexport async function refreshQuotes(\n messenger: TransactionPayControllerMessenger,\n updateTransactionData: UpdateTransactionDataCallback,\n getStrategies: (transaction: TransactionMeta) => TransactionPayStrategy[],\n): Promise<void> {\n const state = messenger.call('TransactionPayController:getState');\n const transactionIds = Object.keys(state.transactionData);\n\n for (const transactionId of transactionIds) {\n const transactionData = state.transactionData[transactionId];\n const { isLoading, quotes, quotesLastUpdated } = transactionData;\n\n if (isLoading || !quotes?.length) {\n continue;\n }\n\n const strategyName = quotes[0].strategy;\n const strategy = getStrategyByName(strategyName);\n\n const refreshInterval =\n (await strategy.getRefreshInterval?.({\n chainId: quotes[0].request.sourceChainId,\n messenger,\n })) ?? DEFAULT_REFRESH_INTERVAL;\n\n const isExpired = Date.now() - (quotesLastUpdated ?? 0) > refreshInterval;\n\n if (!isExpired) {\n continue;\n }\n\n const isUpdated = await updateQuotes({\n getStrategies,\n messenger,\n transactionData,\n transactionId,\n updateTransactionData,\n });\n\n if (isUpdated) {\n log('Refreshed quotes', { transactionId, strategy: strategyName });\n }\n }\n}\n\nfunction abortPreviousAndCreateController(\n transactionId: string,\n): AbortController {\n const previous = inFlightQuoteRequests.get(transactionId);\n\n if (previous && !previous.signal.aborted) {\n log('Aborting previous quote request', { transactionId });\n previous.abort(new Error('Superseded by newer quote request'));\n }\n\n const controller = new AbortController();\n inFlightQuoteRequests.set(transactionId, controller);\n return controller;\n}\n\nfunction clearControllerIfCurrent(\n transactionId: string,\n controller: AbortController,\n): void {\n if (inFlightQuoteRequests.get(transactionId) === controller) {\n inFlightQuoteRequests.delete(transactionId);\n }\n}\n\n/**\n * Build quote requests required to retrieve quotes.\n *\n * @param request - Request parameters.\n * @param request.from - Address from which the transaction is sent.\n * @param request.isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param request.isHyperliquidSource - Whether the source of funds is HyperLiquid.\n * @param request.isPolymarketDepositWallet - Whether the source of funds is a Polymarket deposit wallet.\n * @param request.isPostQuote - Whether this is a post-quote flow.\n * @param request.paymentOverride - Optional payment override type for the transaction.\n * @param request.paymentToken - Payment token (source for standard flows, destination for post-quote).\n * @param request.refundTo - Optional address to receive refunds if the Relay transaction fails.\n * @param request.sourceAmounts - Source amounts for the transaction.\n * @param request.tokens - Required tokens for the transaction.\n * @param request.transactionId - ID of the transaction.\n * @returns Array of quote requests.\n */\nfunction buildQuoteRequests({\n from,\n isMaxAmount,\n isPostQuote,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n paymentToken,\n refundTo,\n sourceAmounts,\n tokens,\n transactionId,\n}: {\n from: Hex;\n isMaxAmount: boolean;\n isPostQuote?: boolean;\n isHyperliquidSource?: boolean;\n isPolymarketDepositWallet?: boolean;\n paymentOverride?: PaymentOverride;\n paymentToken: TransactionPaymentToken | undefined;\n refundTo?: Hex;\n sourceAmounts: TransactionPaySourceAmount[] | undefined;\n tokens: TransactionPayRequiredToken[];\n transactionId: string;\n}): QuoteRequest[] {\n if (!paymentToken) {\n return [];\n }\n\n if (isPostQuote) {\n return buildPostQuoteRequests({\n from,\n isMaxAmount,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n destinationToken: paymentToken,\n refundTo,\n sourceAmounts,\n transactionId,\n });\n }\n\n // Standard flow: source = paymentToken, target = required tokens\n const requests = (sourceAmounts ?? []).map((sourceAmount) => {\n const token = tokens.find(\n (singleToken) => singleToken.address === sourceAmount.targetTokenAddress,\n ) as TransactionPayRequiredToken;\n\n return {\n from,\n isMaxAmount,\n paymentOverride,\n sourceBalanceRaw: paymentToken.balanceRaw,\n sourceTokenAmount: sourceAmount.sourceAmountRaw,\n sourceChainId: paymentToken.chainId,\n sourceTokenAddress: paymentToken.address,\n targetAmountMinimum: token.allowUnderMinimum ? '0' : token.amountRaw,\n targetChainId: token.chainId,\n targetTokenAddress: token.address,\n };\n });\n\n if (!requests.length) {\n log('No quote requests', { transactionId });\n }\n\n return requests;\n}\n\n/**\n * Build quote requests for post-quote flows.\n * In this flow, the source is the transaction's required token,\n * and the target is the user's selected destination token (paymentToken).\n *\n * @param request - Request parameters.\n * @param request.from - Address from which the transaction is sent.\n * @param request.isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param request.isHyperliquidSource - Whether the source of funds is HyperLiquid.\n * @param request.isPolymarketDepositWallet - Whether the source of funds is a Polymarket deposit wallet.\n * @param request.paymentOverride - Optional payment override type for the transaction.\n * @param request.destinationToken - Destination token (paymentToken in post-quote mode).\n * @param request.refundTo - Optional address to receive refunds if the Relay transaction fails.\n * @param request.sourceAmounts - Source amounts for the transaction (includes source token info).\n * @param request.transactionId - ID of the transaction.\n * @returns Array of quote requests for post-quote flow.\n */\nfunction buildPostQuoteRequests({\n from,\n isMaxAmount,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n destinationToken,\n refundTo,\n sourceAmounts,\n transactionId,\n}: {\n from: Hex;\n isMaxAmount: boolean;\n isHyperliquidSource?: boolean;\n isPolymarketDepositWallet?: boolean;\n paymentOverride?: PaymentOverride;\n destinationToken: TransactionPaymentToken;\n refundTo?: Hex;\n sourceAmounts: TransactionPaySourceAmount[] | undefined;\n transactionId: string;\n}): QuoteRequest[] {\n // Find the source amount where targetTokenAddress matches the destination token\n const sourceAmount = sourceAmounts?.find(\n (amount) =>\n amount.targetTokenAddress.toLowerCase() ===\n destinationToken.address.toLowerCase(),\n );\n\n // Same-token-same-chain cases are already filtered in source-amounts.ts\n if (\n !sourceAmount?.sourceBalanceRaw ||\n !sourceAmount.sourceChainId ||\n !sourceAmount.sourceTokenAddress\n ) {\n log('No valid source amount found for post-quote request', {\n transactionId,\n });\n return [];\n }\n\n const request: QuoteRequest = {\n from,\n isMaxAmount,\n isPostQuote: true,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n refundTo,\n sourceBalanceRaw: sourceAmount.sourceBalanceRaw,\n sourceTokenAmount: sourceAmount.sourceAmountRaw,\n sourceChainId: sourceAmount.sourceChainId,\n sourceTokenAddress: sourceAmount.sourceTokenAddress,\n targetAmountMinimum: '0',\n targetChainId: destinationToken.chainId,\n targetTokenAddress: destinationToken.address,\n };\n\n log('Post-quote request built', { transactionId, request });\n\n // Currently only single token post-quote flows are supported.\n // Multiple token support would require multiple quotes for each required token.\n return [request];\n}\n\nasync function refreshPaymentTokenBalance({\n from,\n messenger,\n paymentToken,\n signal,\n transactionId,\n updateTransactionData,\n}: {\n from: Hex;\n messenger: TransactionPayControllerMessenger;\n paymentToken: TransactionPaymentToken | undefined;\n signal: AbortSignal;\n transactionId: string;\n updateTransactionData: UpdateTransactionDataCallback;\n}): Promise<TransactionPaymentToken | undefined> {\n if (!paymentToken) {\n return undefined;\n }\n\n try {\n const fiatRates = getTokenFiatRate(\n messenger,\n paymentToken.address,\n paymentToken.chainId,\n );\n\n if (!fiatRates) {\n return paymentToken;\n }\n\n const liveBalance = await getLiveTokenBalance(\n messenger,\n from,\n paymentToken.chainId,\n paymentToken.address,\n );\n\n if (signal.aborted) {\n log('Payment token balance refresh aborted', { transactionId });\n return paymentToken;\n }\n\n const {\n raw: balanceRaw,\n human: balanceHuman,\n usd: balanceUsd,\n fiat: balanceFiat,\n } = computeTokenAmounts(liveBalance, paymentToken.decimals, fiatRates);\n\n const updatedToken = {\n ...paymentToken,\n balanceFiat,\n balanceHuman,\n balanceRaw,\n balanceUsd,\n };\n\n updateTransactionData(transactionId, (data) => {\n data.paymentToken = updatedToken;\n });\n\n log('Refreshed payment token balance', { transactionId, balanceRaw });\n\n return updatedToken;\n } catch (error) {\n log('Failed to refresh payment token balance', { transactionId, error });\n return paymentToken;\n }\n}\n\n/**\n * Retrieve quotes for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param from - Resolved wallet address (`accountOverride ?? txParams.from`).\n * @param requests - Quote requests.\n * @param isAccountEIP7702Compatible - Whether the account supports EIP-7702.\n * @param getStrategies - Callback to get ordered strategy names for a transaction.\n * @param messenger - Controller messenger.\n * @param fiatPaymentMethod - Selected fiat payment method ID, if applicable.\n * @param signal - Signal that aborts when the quote request is superseded.\n * @returns An object containing batch transactions and quotes.\n */\nasync function getQuotes(\n transaction: TransactionMeta,\n from: Hex,\n requests: QuoteRequest[],\n isAccountEIP7702Compatible: boolean,\n getStrategies: (transaction: TransactionMeta) => TransactionPayStrategy[],\n messenger: TransactionPayControllerMessenger,\n fiatPaymentMethod?: string,\n signal?: AbortSignal,\n): Promise<{\n batchTransactions: BatchTransaction[];\n quotes: TransactionPayQuote<Json>[];\n}> {\n const { id: transactionId } = transaction;\n const strategies = getStrategiesByName(\n getStrategies(transaction),\n (strategyName) => {\n log('Skipping unknown strategy', {\n strategy: strategyName,\n transactionId,\n });\n },\n );\n\n if (!requests?.length && !fiatPaymentMethod) {\n return {\n batchTransactions: [],\n quotes: [],\n };\n }\n\n const request = {\n accountSupports7702: isAccountEIP7702Compatible,\n fiatPaymentMethod,\n from,\n messenger,\n requests,\n signal,\n transaction,\n };\n\n for (const { name, strategy } of strategies) {\n try {\n const support = await checkStrategySupport(strategy, request);\n\n if (!support) {\n log('Strategy does not support request', {\n strategy: name,\n transactionId,\n });\n continue;\n }\n\n const quotes = (await strategy.getQuotes(\n request,\n )) as TransactionPayQuote<Json>[];\n\n if (!quotes.length) {\n log('Strategy returned no quotes', { strategy: name, transactionId });\n continue;\n }\n\n const quoteSupport = await checkStrategyQuoteSupport(strategy, {\n messenger,\n quotes,\n signal,\n transaction,\n });\n\n if (!quoteSupport) {\n log('Strategy does not support quotes', {\n strategy: name,\n transactionId,\n });\n continue;\n }\n\n log('Updated', { transactionId, quotes });\n\n const batchTransactions = strategy.getBatchTransactions\n ? await strategy.getBatchTransactions({\n messenger,\n quotes,\n signal,\n })\n : [];\n\n log('Batch transactions', { transactionId, batchTransactions });\n\n return {\n batchTransactions,\n quotes,\n };\n } catch (error) {\n if (signal?.aborted) {\n throw error;\n }\n\n log('Strategy failed, trying next', {\n error,\n strategy: name,\n transactionId,\n });\n continue;\n }\n }\n\n log('No quotes available', { transactionId });\n\n return {\n batchTransactions: [],\n quotes: [],\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"quotes.cjs","sourceRoot":"","sources":["../../src/utils/quotes.ts"],"names":[],"mappings":"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","sourcesContent":["import { TransactionStatus } from '@metamask/transaction-controller';\nimport type { BatchTransaction } from '@metamask/transaction-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex, Json } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { PaymentOverride, TransactionPayStrategy } from '../constants';\nimport { projectLogger } from '../logger';\nimport type {\n QuoteRequest,\n TransactionData,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n TransactionPayRequiredToken,\n TransactionPaySourceAmount,\n TransactionPayTotals,\n TransactionPaymentToken,\n UpdateTransactionDataCallback,\n} from '../types';\nimport { accountSupports7702 } from './7702';\nimport { buildNoOpQuote } from './no-op-quote';\nimport {\n checkStrategyQuoteSupport,\n checkStrategySupport,\n getStrategiesByName,\n getStrategyByName,\n} from './strategy';\nimport {\n computeTokenAmounts,\n getLiveTokenBalance,\n getTokenFiatRate,\n} from './token';\nimport { calculateTotals } from './totals';\nimport { getTransaction, updateTransaction } from './transaction';\n\nconst DEFAULT_REFRESH_INTERVAL = 30 * 1000; // 30 Seconds\n\nconst log = createModuleLogger(projectLogger, 'quotes');\n\nconst inFlightQuoteRequests = new Map<string, AbortController>();\n\nexport type UpdateQuotesRequest = {\n getStrategies: (transaction: TransactionMeta) => TransactionPayStrategy[];\n messenger: TransactionPayControllerMessenger;\n transactionData: TransactionData | undefined;\n transactionId: string;\n updateTransactionData: UpdateTransactionDataCallback;\n};\n\n/**\n * Update the quotes for a specific transaction.\n *\n * Calls for the same `transactionId` are serialised: a fresh call aborts any\n * previous in-flight call so a slower stale response cannot overwrite a newer\n * one in state.\n *\n * @param request - Request parameters.\n * @returns Boolean indicating if the quotes were updated. Returns `false` when\n * the call was aborted by a subsequent call for the same transaction.\n */\nexport async function updateQuotes(\n request: UpdateQuotesRequest,\n): Promise<boolean> {\n const {\n getStrategies,\n messenger,\n transactionData,\n transactionId,\n updateTransactionData,\n } = request;\n\n const transaction = getTransaction(transactionId, messenger);\n\n if (!transaction || !transactionData) {\n throw new Error('Transaction not found');\n }\n\n if (transaction?.status !== TransactionStatus.unapproved) {\n return false;\n }\n\n log('Updating quotes', { transactionId });\n\n const {\n accountOverride,\n isMaxAmount,\n isPostQuote,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n isQuoteRequired,\n paymentOverride,\n paymentToken: originalPaymentToken,\n fiatPayment,\n refundTo,\n sourceAmounts,\n tokens,\n } = transactionData;\n\n const from = accountOverride ?? (transaction.txParams.from as Hex);\n\n const controller = abortPreviousAndCreateController(transactionId);\n const { signal } = controller;\n\n updateTransactionData(transactionId, (data) => {\n data.isLoading = true;\n });\n\n try {\n const paymentToken = await refreshPaymentTokenBalance({\n from,\n messenger,\n paymentToken: originalPaymentToken,\n signal,\n transactionId,\n updateTransactionData,\n });\n\n if (signal.aborted) {\n log('Quote request aborted before building requests', { transactionId });\n return false;\n }\n\n const requests = buildQuoteRequests({\n from,\n isMaxAmount: isMaxAmount ?? false,\n isPostQuote,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n paymentToken,\n refundTo,\n sourceAmounts,\n tokens,\n transactionId,\n });\n\n const supports7702 = accountSupports7702(messenger, from);\n\n const { batchTransactions, quotes } = await getQuotes(\n transaction,\n from,\n requests,\n paymentToken,\n isQuoteRequired ?? false,\n supports7702,\n getStrategies,\n messenger,\n fiatPayment?.selectedPaymentMethodId,\n signal,\n );\n\n if (signal.aborted) {\n log('Quote request aborted before persisting results', { transactionId });\n return false;\n }\n\n // No-op quotes mark direct routes. They have no fees or amounts and the\n // transaction is signed and submitted locally, so totals and transaction\n // sync must treat them as \"no quotes\".\n const executableQuotes = quotes.filter(\n (quote) => quote.strategy !== TransactionPayStrategy.None,\n );\n\n const totals = calculateTotals({\n fiatPaymentAmount: fiatPayment?.amountFiat,\n isMaxAmount,\n messenger,\n quotes: executableQuotes as TransactionPayQuote<unknown>[],\n tokens,\n transaction,\n });\n\n log('Calculated totals', { transactionId, totals });\n\n syncTransaction({\n batchTransactions,\n selectedFiatPayment: fiatPayment?.selectedPaymentMethodId,\n hasQuotes: executableQuotes.length > 0,\n isPostQuote,\n messenger: messenger as never,\n paymentToken,\n totals,\n transactionId,\n });\n\n updateTransactionData(transactionId, (data) => {\n data.quotes = quotes as never;\n data.quotesLastUpdated = Date.now();\n data.totals = totals;\n });\n } catch (error) {\n if (signal.aborted) {\n log('Quote request aborted', { transactionId, reason: signal.reason });\n return false;\n }\n throw error;\n } finally {\n if (!signal.aborted) {\n updateTransactionData(transactionId, (data) => {\n data.isLoading = false;\n });\n }\n clearControllerIfCurrent(transactionId, controller);\n }\n\n return true;\n}\n\n/**\n * Sync batch transactions to the transaction meta.\n *\n * @param request - Request object.\n * @param request.batchTransactions - Batch transactions to sync.\n * @param request.hasQuotes - Whether MM Pay produced any quotes for this transaction.\n * @param request.isPostQuote - Whether this is a post-quote flow.\n * @param request.messenger - Messenger instance.\n * @param request.paymentToken - Payment token (source for standard flows, destination for post-quote).\n * @param request.selectedFiatPayment - Selected fiat payment method ID.\n * @param request.totals - Calculated totals.\n * @param request.transactionId - ID of the transaction to sync.\n */\nfunction syncTransaction({\n batchTransactions,\n hasQuotes,\n isPostQuote,\n messenger,\n paymentToken,\n selectedFiatPayment,\n totals,\n transactionId,\n}: {\n batchTransactions: BatchTransaction[];\n selectedFiatPayment?: string;\n hasQuotes: boolean;\n isPostQuote?: boolean;\n messenger: TransactionPayControllerMessenger;\n paymentToken: TransactionPaymentToken | undefined;\n totals: TransactionPayTotals;\n transactionId: string;\n}): void {\n if (!paymentToken && !selectedFiatPayment) {\n return;\n }\n\n updateTransaction(\n {\n transactionId,\n messenger: messenger as never,\n note: 'Update transaction pay data',\n },\n (tx: TransactionMeta) => {\n tx.batchTransactions = batchTransactions;\n tx.batchTransactionsOptions = {};\n\n // When MM Pay has produced quotes, it owns submission of this transaction\n // via its strategy publish hook, so the parent must be marked externally\n // signed to skip the local `KeyringController:signTransaction` call.\n // When there are no quotes (e.g. user selected the target token as the\n // payment token in a Predict flow), the transaction falls back to normal\n // local signing, so the flag is cleared to allow that.\n // If gas is sponsored, TC owns this field — it is set based on the\n // Sentinel simulation result and must not be cleared here. Same-token\n // flows (e.g. Monad mUSD withdrawal via a Money Account) produce no\n // quotes but still need external sign because the account cannot sign\n // locally.\n if (!tx.isGasFeeSponsored) {\n tx.isExternalSign = hasQuotes;\n }\n\n tx.metamaskPay = {\n bridgeFeeFiat: totals.fees.provider.usd,\n chainId: paymentToken?.chainId,\n isPostQuote,\n networkFeeFiat: totals.fees.sourceNetwork.estimate.usd,\n targetFiat: totals.targetAmount.usd,\n tokenAddress: paymentToken?.address,\n totalFiat: totals.total.usd,\n };\n },\n );\n}\n\n/**\n * Refresh quotes for all transactions if expired.\n *\n * @param messenger - Messenger instance.\n * @param updateTransactionData - Callback to update transaction data.\n * @param getStrategies - Callback to get ordered strategy names for a transaction.\n */\nexport async function refreshQuotes(\n messenger: TransactionPayControllerMessenger,\n updateTransactionData: UpdateTransactionDataCallback,\n getStrategies: (transaction: TransactionMeta) => TransactionPayStrategy[],\n): Promise<void> {\n const state = messenger.call('TransactionPayController:getState');\n const transactionIds = Object.keys(state.transactionData);\n\n for (const transactionId of transactionIds) {\n const transactionData = state.transactionData[transactionId];\n const { isLoading, quotes, quotesLastUpdated } = transactionData;\n\n if (isLoading || !quotes?.length) {\n continue;\n }\n\n // No-op quotes mark direct routes and have nothing to refresh. They are\n // regenerated whenever the transaction data changes.\n if (\n quotes.every((quote) => quote.strategy === TransactionPayStrategy.None)\n ) {\n continue;\n }\n\n const strategyName = quotes[0].strategy;\n const strategy = getStrategyByName(strategyName);\n\n const refreshInterval =\n (await strategy.getRefreshInterval?.({\n chainId: quotes[0].request.sourceChainId,\n messenger,\n })) ?? DEFAULT_REFRESH_INTERVAL;\n\n const isExpired = Date.now() - (quotesLastUpdated ?? 0) > refreshInterval;\n\n if (!isExpired) {\n continue;\n }\n\n const isUpdated = await updateQuotes({\n getStrategies,\n messenger,\n transactionData,\n transactionId,\n updateTransactionData,\n });\n\n if (isUpdated) {\n log('Refreshed quotes', { transactionId, strategy: strategyName });\n }\n }\n}\n\nfunction abortPreviousAndCreateController(\n transactionId: string,\n): AbortController {\n const previous = inFlightQuoteRequests.get(transactionId);\n\n if (previous && !previous.signal.aborted) {\n log('Aborting previous quote request', { transactionId });\n previous.abort(new Error('Superseded by newer quote request'));\n }\n\n const controller = new AbortController();\n inFlightQuoteRequests.set(transactionId, controller);\n return controller;\n}\n\nfunction clearControllerIfCurrent(\n transactionId: string,\n controller: AbortController,\n): void {\n if (inFlightQuoteRequests.get(transactionId) === controller) {\n inFlightQuoteRequests.delete(transactionId);\n }\n}\n\n/**\n * Build quote requests required to retrieve quotes.\n *\n * @param request - Request parameters.\n * @param request.from - Address from which the transaction is sent.\n * @param request.isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param request.isHyperliquidSource - Whether the source of funds is HyperLiquid.\n * @param request.isPolymarketDepositWallet - Whether the source of funds is a Polymarket deposit wallet.\n * @param request.isPostQuote - Whether this is a post-quote flow.\n * @param request.paymentOverride - Optional payment override type for the transaction.\n * @param request.paymentToken - Payment token (source for standard flows, destination for post-quote).\n * @param request.refundTo - Optional address to receive refunds if the Relay transaction fails.\n * @param request.sourceAmounts - Source amounts for the transaction.\n * @param request.tokens - Required tokens for the transaction.\n * @param request.transactionId - ID of the transaction.\n * @returns Array of quote requests.\n */\nfunction buildQuoteRequests({\n from,\n isMaxAmount,\n isPostQuote,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n paymentToken,\n refundTo,\n sourceAmounts,\n tokens,\n transactionId,\n}: {\n from: Hex;\n isMaxAmount: boolean;\n isPostQuote?: boolean;\n isHyperliquidSource?: boolean;\n isPolymarketDepositWallet?: boolean;\n paymentOverride?: PaymentOverride;\n paymentToken: TransactionPaymentToken | undefined;\n refundTo?: Hex;\n sourceAmounts: TransactionPaySourceAmount[] | undefined;\n tokens: TransactionPayRequiredToken[];\n transactionId: string;\n}): QuoteRequest[] {\n if (!paymentToken) {\n return [];\n }\n\n if (isPostQuote) {\n return buildPostQuoteRequests({\n from,\n isMaxAmount,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n destinationToken: paymentToken,\n refundTo,\n sourceAmounts,\n transactionId,\n });\n }\n\n // Standard flow: source = paymentToken, target = required tokens\n const requests = (sourceAmounts ?? []).map((sourceAmount) => {\n const token = tokens.find(\n (singleToken) => singleToken.address === sourceAmount.targetTokenAddress,\n ) as TransactionPayRequiredToken;\n\n return {\n from,\n isMaxAmount,\n paymentOverride,\n sourceBalanceRaw: paymentToken.balanceRaw,\n sourceTokenAmount: sourceAmount.sourceAmountRaw,\n sourceChainId: paymentToken.chainId,\n sourceTokenAddress: paymentToken.address,\n targetAmountMinimum: token.allowUnderMinimum ? '0' : token.amountRaw,\n targetChainId: token.chainId,\n targetTokenAddress: token.address,\n };\n });\n\n if (!requests.length) {\n log('No quote requests', { transactionId });\n }\n\n return requests;\n}\n\n/**\n * Build quote requests for post-quote flows.\n * In this flow, the source is the transaction's required token,\n * and the target is the user's selected destination token (paymentToken).\n *\n * @param request - Request parameters.\n * @param request.from - Address from which the transaction is sent.\n * @param request.isMaxAmount - Whether the transaction is a maximum amount transaction.\n * @param request.isHyperliquidSource - Whether the source of funds is HyperLiquid.\n * @param request.isPolymarketDepositWallet - Whether the source of funds is a Polymarket deposit wallet.\n * @param request.paymentOverride - Optional payment override type for the transaction.\n * @param request.destinationToken - Destination token (paymentToken in post-quote mode).\n * @param request.refundTo - Optional address to receive refunds if the Relay transaction fails.\n * @param request.sourceAmounts - Source amounts for the transaction (includes source token info).\n * @param request.transactionId - ID of the transaction.\n * @returns Array of quote requests for post-quote flow.\n */\nfunction buildPostQuoteRequests({\n from,\n isMaxAmount,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n destinationToken,\n refundTo,\n sourceAmounts,\n transactionId,\n}: {\n from: Hex;\n isMaxAmount: boolean;\n isHyperliquidSource?: boolean;\n isPolymarketDepositWallet?: boolean;\n paymentOverride?: PaymentOverride;\n destinationToken: TransactionPaymentToken;\n refundTo?: Hex;\n sourceAmounts: TransactionPaySourceAmount[] | undefined;\n transactionId: string;\n}): QuoteRequest[] {\n // Find the source amount where targetTokenAddress matches the destination token\n const sourceAmount = sourceAmounts?.find(\n (amount) =>\n amount.targetTokenAddress.toLowerCase() ===\n destinationToken.address.toLowerCase(),\n );\n\n // Same-token-same-chain cases are already filtered in source-amounts.ts\n if (\n !sourceAmount?.sourceBalanceRaw ||\n !sourceAmount.sourceChainId ||\n !sourceAmount.sourceTokenAddress\n ) {\n log('No valid source amount found for post-quote request', {\n transactionId,\n });\n return [];\n }\n\n const request: QuoteRequest = {\n from,\n isMaxAmount,\n isPostQuote: true,\n isHyperliquidSource,\n isPolymarketDepositWallet,\n paymentOverride,\n refundTo,\n sourceBalanceRaw: sourceAmount.sourceBalanceRaw,\n sourceTokenAmount: sourceAmount.sourceAmountRaw,\n sourceChainId: sourceAmount.sourceChainId,\n sourceTokenAddress: sourceAmount.sourceTokenAddress,\n targetAmountMinimum: '0',\n targetChainId: destinationToken.chainId,\n targetTokenAddress: destinationToken.address,\n };\n\n log('Post-quote request built', { transactionId, request });\n\n // Currently only single token post-quote flows are supported.\n // Multiple token support would require multiple quotes for each required token.\n return [request];\n}\n\nasync function refreshPaymentTokenBalance({\n from,\n messenger,\n paymentToken,\n signal,\n transactionId,\n updateTransactionData,\n}: {\n from: Hex;\n messenger: TransactionPayControllerMessenger;\n paymentToken: TransactionPaymentToken | undefined;\n signal: AbortSignal;\n transactionId: string;\n updateTransactionData: UpdateTransactionDataCallback;\n}): Promise<TransactionPaymentToken | undefined> {\n if (!paymentToken) {\n return undefined;\n }\n\n try {\n const fiatRates = getTokenFiatRate(\n messenger,\n paymentToken.address,\n paymentToken.chainId,\n );\n\n if (!fiatRates) {\n return paymentToken;\n }\n\n const liveBalance = await getLiveTokenBalance(\n messenger,\n from,\n paymentToken.chainId,\n paymentToken.address,\n );\n\n if (signal.aborted) {\n log('Payment token balance refresh aborted', { transactionId });\n return paymentToken;\n }\n\n const {\n raw: balanceRaw,\n human: balanceHuman,\n usd: balanceUsd,\n fiat: balanceFiat,\n } = computeTokenAmounts(liveBalance, paymentToken.decimals, fiatRates);\n\n const updatedToken = {\n ...paymentToken,\n balanceFiat,\n balanceHuman,\n balanceRaw,\n balanceUsd,\n };\n\n updateTransactionData(transactionId, (data) => {\n data.paymentToken = updatedToken;\n });\n\n log('Refreshed payment token balance', { transactionId, balanceRaw });\n\n return updatedToken;\n } catch (error) {\n log('Failed to refresh payment token balance', { transactionId, error });\n return paymentToken;\n }\n}\n\n/**\n * Retrieve quotes for a transaction.\n *\n * @param transaction - Transaction metadata.\n * @param from - Resolved wallet address (`accountOverride ?? txParams.from`).\n * @param requests - Quote requests.\n * @param paymentToken - Selected payment token, if any.\n * @param isQuoteRequired - Whether a quote is always required for the transaction.\n * @param isAccountEIP7702Compatible - Whether the account supports EIP-7702.\n * @param getStrategies - Callback to get ordered strategy names for a transaction.\n * @param messenger - Controller messenger.\n * @param fiatPaymentMethod - Selected fiat payment method ID, if applicable.\n * @param signal - Signal that aborts when the quote request is superseded.\n * @returns An object containing batch transactions and quotes.\n */\nasync function getQuotes(\n transaction: TransactionMeta,\n from: Hex,\n requests: QuoteRequest[],\n paymentToken: TransactionPaymentToken | undefined,\n isQuoteRequired: boolean,\n isAccountEIP7702Compatible: boolean,\n getStrategies: (transaction: TransactionMeta) => TransactionPayStrategy[],\n messenger: TransactionPayControllerMessenger,\n fiatPaymentMethod?: string,\n signal?: AbortSignal,\n): Promise<{\n batchTransactions: BatchTransaction[];\n quotes: TransactionPayQuote<Json>[];\n}> {\n const { id: transactionId } = transaction;\n const strategies = getStrategiesByName(\n getStrategies(transaction),\n (strategyName) => {\n log('Skipping unknown strategy', {\n strategy: strategyName,\n transactionId,\n });\n },\n );\n\n if (!requests?.length && !fiatPaymentMethod) {\n // A selected payment token with no conversion requests means the route is\n // direct. Return an explicit no-op quote so clients and the publish hook\n // can distinguish \"no conversion needed\" from \"quote needed but missing\".\n // Not applicable when a quote is always required, as an empty requests\n // list then means the source amounts could not be calculated.\n const noOpQuote =\n paymentToken && !isQuoteRequired\n ? buildNoOpQuote(from, paymentToken)\n : undefined;\n\n if (noOpQuote) {\n log('Built no-op quote for direct route', { transactionId });\n }\n\n return {\n batchTransactions: [],\n quotes: noOpQuote ? [noOpQuote] : [],\n };\n }\n\n const request = {\n accountSupports7702: isAccountEIP7702Compatible,\n fiatPaymentMethod,\n from,\n messenger,\n requests,\n signal,\n transaction,\n };\n\n for (const { name, strategy } of strategies) {\n try {\n const support = await checkStrategySupport(strategy, request);\n\n if (!support) {\n log('Strategy does not support request', {\n strategy: name,\n transactionId,\n });\n continue;\n }\n\n const quotes = (await strategy.getQuotes(\n request,\n )) as TransactionPayQuote<Json>[];\n\n if (!quotes.length) {\n log('Strategy returned no quotes', { strategy: name, transactionId });\n continue;\n }\n\n const quoteSupport = await checkStrategyQuoteSupport(strategy, {\n messenger,\n quotes,\n signal,\n transaction,\n });\n\n if (!quoteSupport) {\n log('Strategy does not support quotes', {\n strategy: name,\n transactionId,\n });\n continue;\n }\n\n log('Updated', { transactionId, quotes });\n\n const batchTransactions = strategy.getBatchTransactions\n ? await strategy.getBatchTransactions({\n messenger,\n quotes,\n signal,\n })\n : [];\n\n log('Batch transactions', { transactionId, batchTransactions });\n\n return {\n batchTransactions,\n quotes,\n };\n } catch (error) {\n if (signal?.aborted) {\n throw error;\n }\n\n log('Strategy failed, trying next', {\n error,\n strategy: name,\n transactionId,\n });\n continue;\n }\n }\n\n log('No quotes available', { transactionId });\n\n return {\n batchTransactions: [],\n quotes: [],\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes.d.cts","sourceRoot":"","sources":["../../src/utils/quotes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAIxE,OAAO,EAAmB,sBAAsB,EAAE,yBAAqB;AAEvE,OAAO,KAAK,EAEV,eAAe,EACf,iCAAiC,EAMjC,6BAA6B,EAC9B,qBAAiB;
|
|
1
|
+
{"version":3,"file":"quotes.d.cts","sourceRoot":"","sources":["../../src/utils/quotes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAIxE,OAAO,EAAmB,sBAAsB,EAAE,yBAAqB;AAEvE,OAAO,KAAK,EAEV,eAAe,EACf,iCAAiC,EAMjC,6BAA6B,EAC9B,qBAAiB;AAuBlB,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,sBAAsB,EAAE,CAAC;IAC1E,SAAS,EAAE,iCAAiC,CAAC;IAC7C,eAAe,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,6BAA6B,CAAC;CACtD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAgJlB;AA4ED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,iCAAiC,EAC5C,qBAAqB,EAAE,6BAA6B,EACpD,aAAa,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,sBAAsB,EAAE,GACxE,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes.d.mts","sourceRoot":"","sources":["../../src/utils/quotes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAIxE,OAAO,EAAmB,sBAAsB,EAAE,yBAAqB;AAEvE,OAAO,KAAK,EAEV,eAAe,EACf,iCAAiC,EAMjC,6BAA6B,EAC9B,qBAAiB;
|
|
1
|
+
{"version":3,"file":"quotes.d.mts","sourceRoot":"","sources":["../../src/utils/quotes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AAIxE,OAAO,EAAmB,sBAAsB,EAAE,yBAAqB;AAEvE,OAAO,KAAK,EAEV,eAAe,EACf,iCAAiC,EAMjC,6BAA6B,EAC9B,qBAAiB;AAuBlB,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,sBAAsB,EAAE,CAAC;IAC1E,SAAS,EAAE,iCAAiC,CAAC;IAC7C,eAAe,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,EAAE,6BAA6B,CAAC;CACtD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAgJlB;AA4ED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,iCAAiC,EAC5C,qBAAqB,EAAE,6BAA6B,EACpD,aAAa,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,sBAAsB,EAAE,GACxE,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
|
package/dist/utils/quotes.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { createModuleLogger } from "@metamask/utils";
|
|
|
3
3
|
import { PaymentOverride, TransactionPayStrategy } from "../constants.mjs";
|
|
4
4
|
import { projectLogger } from "../logger.mjs";
|
|
5
5
|
import { accountSupports7702 } from "./7702.mjs";
|
|
6
|
+
import { buildNoOpQuote } from "./no-op-quote.mjs";
|
|
6
7
|
import { checkStrategyQuoteSupport, checkStrategySupport, getStrategiesByName, getStrategyByName } from "./strategy.mjs";
|
|
7
8
|
import { computeTokenAmounts, getLiveTokenBalance, getTokenFiatRate } from "./token.mjs";
|
|
8
9
|
import { calculateTotals } from "./totals.mjs";
|
|
@@ -31,7 +32,7 @@ export async function updateQuotes(request) {
|
|
|
31
32
|
return false;
|
|
32
33
|
}
|
|
33
34
|
log('Updating quotes', { transactionId });
|
|
34
|
-
const { accountOverride, isMaxAmount, isPostQuote, isHyperliquidSource, isPolymarketDepositWallet, paymentOverride, paymentToken: originalPaymentToken, fiatPayment, refundTo, sourceAmounts, tokens, } = transactionData;
|
|
35
|
+
const { accountOverride, isMaxAmount, isPostQuote, isHyperliquidSource, isPolymarketDepositWallet, isQuoteRequired, paymentOverride, paymentToken: originalPaymentToken, fiatPayment, refundTo, sourceAmounts, tokens, } = transactionData;
|
|
35
36
|
const from = accountOverride ?? transaction.txParams.from;
|
|
36
37
|
const controller = abortPreviousAndCreateController(transactionId);
|
|
37
38
|
const { signal } = controller;
|
|
@@ -65,16 +66,20 @@ export async function updateQuotes(request) {
|
|
|
65
66
|
transactionId,
|
|
66
67
|
});
|
|
67
68
|
const supports7702 = accountSupports7702(messenger, from);
|
|
68
|
-
const { batchTransactions, quotes } = await getQuotes(transaction, from, requests, supports7702, getStrategies, messenger, fiatPayment?.selectedPaymentMethodId, signal);
|
|
69
|
+
const { batchTransactions, quotes } = await getQuotes(transaction, from, requests, paymentToken, isQuoteRequired ?? false, supports7702, getStrategies, messenger, fiatPayment?.selectedPaymentMethodId, signal);
|
|
69
70
|
if (signal.aborted) {
|
|
70
71
|
log('Quote request aborted before persisting results', { transactionId });
|
|
71
72
|
return false;
|
|
72
73
|
}
|
|
74
|
+
// No-op quotes mark direct routes. They have no fees or amounts and the
|
|
75
|
+
// transaction is signed and submitted locally, so totals and transaction
|
|
76
|
+
// sync must treat them as "no quotes".
|
|
77
|
+
const executableQuotes = quotes.filter((quote) => quote.strategy !== TransactionPayStrategy.None);
|
|
73
78
|
const totals = calculateTotals({
|
|
74
79
|
fiatPaymentAmount: fiatPayment?.amountFiat,
|
|
75
80
|
isMaxAmount,
|
|
76
81
|
messenger,
|
|
77
|
-
quotes:
|
|
82
|
+
quotes: executableQuotes,
|
|
78
83
|
tokens,
|
|
79
84
|
transaction,
|
|
80
85
|
});
|
|
@@ -82,7 +87,7 @@ export async function updateQuotes(request) {
|
|
|
82
87
|
syncTransaction({
|
|
83
88
|
batchTransactions,
|
|
84
89
|
selectedFiatPayment: fiatPayment?.selectedPaymentMethodId,
|
|
85
|
-
hasQuotes:
|
|
90
|
+
hasQuotes: executableQuotes.length > 0,
|
|
86
91
|
isPostQuote,
|
|
87
92
|
messenger: messenger,
|
|
88
93
|
paymentToken,
|
|
@@ -177,6 +182,11 @@ export async function refreshQuotes(messenger, updateTransactionData, getStrateg
|
|
|
177
182
|
if (isLoading || !quotes?.length) {
|
|
178
183
|
continue;
|
|
179
184
|
}
|
|
185
|
+
// No-op quotes mark direct routes and have nothing to refresh. They are
|
|
186
|
+
// regenerated whenever the transaction data changes.
|
|
187
|
+
if (quotes.every((quote) => quote.strategy === TransactionPayStrategy.None)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
180
190
|
const strategyName = quotes[0].strategy;
|
|
181
191
|
const strategy = getStrategyByName(strategyName);
|
|
182
192
|
const refreshInterval = (await strategy.getRefreshInterval?.({
|
|
@@ -359,6 +369,8 @@ async function refreshPaymentTokenBalance({ from, messenger, paymentToken, signa
|
|
|
359
369
|
* @param transaction - Transaction metadata.
|
|
360
370
|
* @param from - Resolved wallet address (`accountOverride ?? txParams.from`).
|
|
361
371
|
* @param requests - Quote requests.
|
|
372
|
+
* @param paymentToken - Selected payment token, if any.
|
|
373
|
+
* @param isQuoteRequired - Whether a quote is always required for the transaction.
|
|
362
374
|
* @param isAccountEIP7702Compatible - Whether the account supports EIP-7702.
|
|
363
375
|
* @param getStrategies - Callback to get ordered strategy names for a transaction.
|
|
364
376
|
* @param messenger - Controller messenger.
|
|
@@ -366,7 +378,7 @@ async function refreshPaymentTokenBalance({ from, messenger, paymentToken, signa
|
|
|
366
378
|
* @param signal - Signal that aborts when the quote request is superseded.
|
|
367
379
|
* @returns An object containing batch transactions and quotes.
|
|
368
380
|
*/
|
|
369
|
-
async function getQuotes(transaction, from, requests, isAccountEIP7702Compatible, getStrategies, messenger, fiatPaymentMethod, signal) {
|
|
381
|
+
async function getQuotes(transaction, from, requests, paymentToken, isQuoteRequired, isAccountEIP7702Compatible, getStrategies, messenger, fiatPaymentMethod, signal) {
|
|
370
382
|
const { id: transactionId } = transaction;
|
|
371
383
|
const strategies = getStrategiesByName(getStrategies(transaction), (strategyName) => {
|
|
372
384
|
log('Skipping unknown strategy', {
|
|
@@ -375,9 +387,20 @@ async function getQuotes(transaction, from, requests, isAccountEIP7702Compatible
|
|
|
375
387
|
});
|
|
376
388
|
});
|
|
377
389
|
if (!requests?.length && !fiatPaymentMethod) {
|
|
390
|
+
// A selected payment token with no conversion requests means the route is
|
|
391
|
+
// direct. Return an explicit no-op quote so clients and the publish hook
|
|
392
|
+
// can distinguish "no conversion needed" from "quote needed but missing".
|
|
393
|
+
// Not applicable when a quote is always required, as an empty requests
|
|
394
|
+
// list then means the source amounts could not be calculated.
|
|
395
|
+
const noOpQuote = paymentToken && !isQuoteRequired
|
|
396
|
+
? buildNoOpQuote(from, paymentToken)
|
|
397
|
+
: undefined;
|
|
398
|
+
if (noOpQuote) {
|
|
399
|
+
log('Built no-op quote for direct route', { transactionId });
|
|
400
|
+
}
|
|
378
401
|
return {
|
|
379
402
|
batchTransactions: [],
|
|
380
|
-
quotes: [],
|
|
403
|
+
quotes: noOpQuote ? [noOpQuote] : [],
|
|
381
404
|
};
|
|
382
405
|
}
|
|
383
406
|
const request = {
|