@metamask/bridge-status-controller 68.1.0 → 70.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/dist/bridge-status-controller.cjs +123 -221
  3. package/dist/bridge-status-controller.cjs.map +1 -1
  4. package/dist/bridge-status-controller.d.cts +1 -4
  5. package/dist/bridge-status-controller.d.cts.map +1 -1
  6. package/dist/bridge-status-controller.d.mts +1 -4
  7. package/dist/bridge-status-controller.d.mts.map +1 -1
  8. package/dist/bridge-status-controller.intent.cjs +9 -13
  9. package/dist/bridge-status-controller.intent.cjs.map +1 -1
  10. package/dist/bridge-status-controller.intent.d.cts +6 -8
  11. package/dist/bridge-status-controller.intent.d.cts.map +1 -1
  12. package/dist/bridge-status-controller.intent.d.mts +6 -8
  13. package/dist/bridge-status-controller.intent.d.mts.map +1 -1
  14. package/dist/bridge-status-controller.intent.mjs +10 -14
  15. package/dist/bridge-status-controller.intent.mjs.map +1 -1
  16. package/dist/bridge-status-controller.mjs +125 -223
  17. package/dist/bridge-status-controller.mjs.map +1 -1
  18. package/dist/index.cjs +1 -3
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +0 -1
  21. package/dist/index.d.cts.map +1 -1
  22. package/dist/index.d.mts +0 -1
  23. package/dist/index.d.mts.map +1 -1
  24. package/dist/index.mjs +0 -1
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/types.cjs.map +1 -1
  27. package/dist/types.d.cts +2 -2
  28. package/dist/types.d.cts.map +1 -1
  29. package/dist/types.d.mts +2 -2
  30. package/dist/types.d.mts.map +1 -1
  31. package/dist/types.mjs.map +1 -1
  32. package/dist/utils/accounts.cjs +8 -0
  33. package/dist/utils/accounts.cjs.map +1 -0
  34. package/dist/utils/accounts.d.cts +36 -0
  35. package/dist/utils/accounts.d.cts.map +1 -0
  36. package/dist/utils/accounts.d.mts +36 -0
  37. package/dist/utils/accounts.d.mts.map +1 -0
  38. package/dist/utils/accounts.mjs +4 -0
  39. package/dist/utils/accounts.mjs.map +1 -0
  40. package/dist/utils/authentication.cjs +15 -0
  41. package/dist/utils/authentication.cjs.map +1 -0
  42. package/dist/utils/authentication.d.cts +3 -0
  43. package/dist/utils/authentication.d.cts.map +1 -0
  44. package/dist/utils/authentication.d.mts +3 -0
  45. package/dist/utils/authentication.d.mts.map +1 -0
  46. package/dist/utils/authentication.mjs +11 -0
  47. package/dist/utils/authentication.mjs.map +1 -0
  48. package/dist/utils/bridge-status.cjs +2 -4
  49. package/dist/utils/bridge-status.cjs.map +1 -1
  50. package/dist/utils/bridge-status.d.cts.map +1 -1
  51. package/dist/utils/bridge-status.d.mts.map +1 -1
  52. package/dist/utils/bridge-status.mjs +2 -4
  53. package/dist/utils/bridge-status.mjs.map +1 -1
  54. package/dist/utils/bridge.cjs +16 -0
  55. package/dist/utils/bridge.cjs.map +1 -0
  56. package/dist/utils/bridge.d.cts +10 -0
  57. package/dist/utils/bridge.d.cts.map +1 -0
  58. package/dist/utils/bridge.d.mts +10 -0
  59. package/dist/utils/bridge.d.mts.map +1 -0
  60. package/dist/utils/bridge.mjs +11 -0
  61. package/dist/utils/bridge.mjs.map +1 -0
  62. package/dist/utils/gas.cjs +4 -7
  63. package/dist/utils/gas.cjs.map +1 -1
  64. package/dist/utils/gas.d.cts +1 -1
  65. package/dist/utils/gas.d.cts.map +1 -1
  66. package/dist/utils/gas.d.mts +1 -1
  67. package/dist/utils/gas.d.mts.map +1 -1
  68. package/dist/utils/gas.mjs +4 -7
  69. package/dist/utils/gas.mjs.map +1 -1
  70. package/dist/utils/history.cjs +97 -0
  71. package/dist/utils/history.cjs.map +1 -0
  72. package/dist/utils/history.d.cts +21 -0
  73. package/dist/utils/history.d.cts.map +1 -0
  74. package/dist/utils/history.d.mts +21 -0
  75. package/dist/utils/history.d.mts.map +1 -0
  76. package/dist/utils/history.mjs +90 -0
  77. package/dist/utils/history.mjs.map +1 -0
  78. package/dist/utils/intent-api.cjs +18 -3
  79. package/dist/utils/intent-api.cjs.map +1 -1
  80. package/dist/utils/intent-api.d.cts +16 -7
  81. package/dist/utils/intent-api.d.cts.map +1 -1
  82. package/dist/utils/intent-api.d.mts +16 -7
  83. package/dist/utils/intent-api.d.mts.map +1 -1
  84. package/dist/utils/intent-api.mjs +18 -4
  85. package/dist/utils/intent-api.mjs.map +1 -1
  86. package/dist/utils/keyring.cjs +12 -0
  87. package/dist/utils/keyring.cjs.map +1 -0
  88. package/dist/utils/keyring.d.cts +8 -0
  89. package/dist/utils/keyring.d.cts.map +1 -0
  90. package/dist/utils/keyring.d.mts +8 -0
  91. package/dist/utils/keyring.d.mts.map +1 -0
  92. package/dist/utils/keyring.mjs +8 -0
  93. package/dist/utils/keyring.mjs.map +1 -0
  94. package/dist/utils/network.cjs +17 -0
  95. package/dist/utils/network.cjs.map +1 -0
  96. package/dist/utils/network.d.cts +5 -0
  97. package/dist/utils/network.d.cts.map +1 -0
  98. package/dist/utils/network.d.mts +5 -0
  99. package/dist/utils/network.d.mts.map +1 -0
  100. package/dist/utils/network.mjs +12 -0
  101. package/dist/utils/network.mjs.map +1 -0
  102. package/dist/utils/snaps.cjs +146 -1
  103. package/dist/utils/snaps.cjs.map +1 -1
  104. package/dist/utils/snaps.d.cts +62 -0
  105. package/dist/utils/snaps.d.cts.map +1 -1
  106. package/dist/utils/snaps.d.mts +62 -0
  107. package/dist/utils/snaps.d.mts.map +1 -1
  108. package/dist/utils/snaps.mjs +141 -0
  109. package/dist/utils/snaps.mjs.map +1 -1
  110. package/dist/utils/trace.cjs +31 -0
  111. package/dist/utils/trace.cjs.map +1 -0
  112. package/dist/utils/trace.d.cts +17 -0
  113. package/dist/utils/trace.d.cts.map +1 -0
  114. package/dist/utils/trace.d.mts +17 -0
  115. package/dist/utils/trace.d.mts.map +1 -0
  116. package/dist/utils/trace.mjs +26 -0
  117. package/dist/utils/trace.mjs.map +1 -0
  118. package/dist/utils/transaction.cjs +31 -193
  119. package/dist/utils/transaction.cjs.map +1 -1
  120. package/dist/utils/transaction.d.cts +8 -79
  121. package/dist/utils/transaction.d.cts.map +1 -1
  122. package/dist/utils/transaction.d.mts +8 -79
  123. package/dist/utils/transaction.d.mts.map +1 -1
  124. package/dist/utils/transaction.mjs +31 -187
  125. package/dist/utils/transaction.mjs.map +1 -1
  126. package/dist/utils/validators.cjs +5 -5
  127. package/dist/utils/validators.cjs.map +1 -1
  128. package/dist/utils/validators.d.cts +6 -11
  129. package/dist/utils/validators.d.cts.map +1 -1
  130. package/dist/utils/validators.d.mts +6 -11
  131. package/dist/utils/validators.d.mts.map +1 -1
  132. package/dist/utils/validators.mjs +3 -3
  133. package/dist/utils/validators.mjs.map +1 -1
  134. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"snaps.d.mts","sourceRoot":"","sources":["../../src/utils/snaps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB;AAGnD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,WACjC,MAAM,eACD,MAAM,SACZ,WAAW,aACP,MAAM,YACP,OAAO,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;CAmBlC,CAAC"}
1
+ {"version":3,"file":"snaps.d.mts","sourceRoot":"","sources":["../../src/utils/snaps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,sCAAsC;AAC7E,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,KAAK,EACN,oCAAoC;AAYrC,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAO,wBAAwB;AAGxD,OAAO,KAAK,EACV,+BAA+B,EAC/B,qBAAqB,EACtB,qBAAiB;AAElB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,WACjC,MAAM,eACD,MAAM,SACZ,WAAW,aACP,MAAM,YACP,OAAO,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;CAmBlC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,UACpB,KAAK,cACA,MAAM,aACP,MAAM,UACT,MAAM;;;;;;;;;;;;;;;CAsBf,CAAC;AAEF,eAAO,MAAM,eAAe,kBACX,KAAK,cAAc,KAAK,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,GACpE,aAAa,iBACA,MAAM,KACpB,KACD,eAAe,EACf,iBAAiB,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,CA4BtE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,iBAE7B,MAAM,GACN;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAClC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,SAClB,KAAK,iBACG,KAAK,cAAc,KAAK,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,GAC7D,aAAa,mBACE,uBAAuB,CAAC,kBAAkB,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAC/E,eAAe,GAAG,qBA6DpB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,sDAElB,KAAK,iBACG,cAAc,KAAK,EAAE,KAAK,CAAC,GAAG,aAAa,mBACzC,uBAAuB,CAAC,kBAAkB,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAC/E,QAAQ,eAAe,CAgCzB,CAAC"}
@@ -1,3 +1,5 @@
1
+ import { extractTradeData, formatChainIdToCaip, formatChainIdToHex, isCrossChain, isTronTrade } from "@metamask/bridge-controller";
2
+ import { TransactionStatus, TransactionType } from "@metamask/transaction-controller";
1
3
  import { v4 as uuid } from "uuid";
2
4
  /**
3
5
  * Creates a client request object for signing and sending a transaction
@@ -29,4 +31,143 @@ export const createClientTransactionRequest = (snapId, transaction, scope, accou
29
31
  },
30
32
  };
31
33
  };
34
+ /**
35
+ * Creates a request to sign and send a transaction for non-EVM chains
36
+ * Uses the new unified ClientRequest:signAndSendTransaction interface
37
+ *
38
+ * @param trade - The trade data
39
+ * @param srcChainId - The source chain ID
40
+ * @param accountId - The selected account ID
41
+ * @param snapId - The snap ID
42
+ * @returns The snap request object for signing and sending transaction
43
+ */
44
+ export const getClientRequest = (trade, srcChainId, accountId, snapId) => {
45
+ const scope = formatChainIdToCaip(srcChainId);
46
+ const transactionData = extractTradeData(trade);
47
+ // Tron trades need the visible flag and contract type to be included in the request options
48
+ const options = isTronTrade(trade)
49
+ ? {
50
+ visible: trade.visible,
51
+ type: trade.raw_data?.contract?.[0]?.type,
52
+ }
53
+ : undefined;
54
+ // Use the new unified interface
55
+ return createClientTransactionRequest(snapId, transactionData, scope, accountId, options);
56
+ };
57
+ export const getTxMetaFields = (quoteResponse, approvalTxId) => {
58
+ // Handle destination chain ID - should always be convertible for EVM destinations
59
+ let destinationChainId;
60
+ try {
61
+ destinationChainId = formatChainIdToHex(quoteResponse.quote.destChainId);
62
+ }
63
+ catch {
64
+ // Fallback for non-EVM destination (shouldn't happen for BTC->EVM)
65
+ destinationChainId = '0x1'; // Default to mainnet
66
+ }
67
+ return {
68
+ destinationChainId,
69
+ sourceTokenAmount: quoteResponse.quote.srcTokenAmount,
70
+ sourceTokenSymbol: quoteResponse.quote.srcAsset.symbol,
71
+ sourceTokenDecimals: quoteResponse.quote.srcAsset.decimals,
72
+ sourceTokenAddress: quoteResponse.quote.srcAsset.address,
73
+ destinationTokenAmount: quoteResponse.quote.destTokenAmount,
74
+ destinationTokenSymbol: quoteResponse.quote.destAsset.symbol,
75
+ destinationTokenDecimals: quoteResponse.quote.destAsset.decimals,
76
+ destinationTokenAddress: quoteResponse.quote.destAsset.address,
77
+ // chainId is now excluded from this function and handled by the caller
78
+ approvalTxId,
79
+ // this is the decimal (non atomic) amount (not USD value) of source token to swap
80
+ swapTokenValue: quoteResponse.sentAmount.amount,
81
+ };
82
+ };
83
+ /**
84
+ * Handles the response from non-EVM transaction submission
85
+ * Works with the new unified ClientRequest:signAndSendTransaction interface
86
+ * Supports Solana, Bitcoin, and other non-EVM chains
87
+ *
88
+ * @param snapResponse - The response from the snap after transaction submission
89
+ * @param trade - The non-evm trade or approval data
90
+ * @param quoteResponse - The quote response containing trade details and metadata
91
+ * @param selectedAccount - The selected account information
92
+ * @returns The transaction metadata including non-EVM specific fields
93
+ */
94
+ export const handleNonEvmTxResponse = (snapResponse, trade, quoteResponse, selectedAccount) => {
95
+ const selectedAccountAddress = selectedAccount.address;
96
+ const snapId = selectedAccount.metadata.snap?.id;
97
+ let hash;
98
+ // Handle different response formats
99
+ if (typeof snapResponse === 'string') {
100
+ hash = snapResponse;
101
+ }
102
+ else if (snapResponse && typeof snapResponse === 'object') {
103
+ // Check for new unified interface response format first
104
+ if ('transactionId' in snapResponse && snapResponse.transactionId) {
105
+ hash = snapResponse.transactionId;
106
+ }
107
+ else if ('result' in snapResponse &&
108
+ snapResponse.result &&
109
+ typeof snapResponse.result === 'object') {
110
+ // Try to extract signature from common locations in response object
111
+ hash =
112
+ snapResponse.result.signature ||
113
+ snapResponse.result.txid ||
114
+ snapResponse.result.hash ||
115
+ snapResponse.result.txHash;
116
+ }
117
+ else if ('signature' in snapResponse &&
118
+ snapResponse.signature &&
119
+ typeof snapResponse.signature === 'string') {
120
+ hash = snapResponse.signature;
121
+ }
122
+ }
123
+ const isBridgeTx = isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
124
+ let hexChainId;
125
+ try {
126
+ hexChainId = formatChainIdToHex(quoteResponse.quote.srcChainId);
127
+ }
128
+ catch {
129
+ hexChainId = '0x1';
130
+ }
131
+ // Extract the transaction data for storage
132
+ const tradeData = extractTradeData(trade);
133
+ // Create a transaction meta object with bridge-specific fields
134
+ return {
135
+ ...getTxMetaFields(quoteResponse),
136
+ time: Date.now(),
137
+ id: hash ?? uuid(),
138
+ chainId: hexChainId,
139
+ networkClientId: snapId ?? 'mainnet',
140
+ txParams: { from: selectedAccountAddress, data: tradeData },
141
+ type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,
142
+ status: TransactionStatus.submitted,
143
+ hash, // Add the transaction signature as hash
144
+ origin: snapId,
145
+ // Add an explicit flag to mark this as a non-EVM transaction
146
+ isSolana: true, // TODO deprecate this and use chainId to detect non-EVM chains
147
+ isBridgeTx,
148
+ };
149
+ };
150
+ /**
151
+ * Submits the transaction to the snap using the new unified ClientRequest interface
152
+ * Works for all non-EVM chains (Solana, BTC, Tron)
153
+ * This adds an approval tx to the ApprovalsController in the background
154
+ * The client needs to handle the approval tx by redirecting to the confirmation page with the approvalTxId in the URL
155
+ *
156
+ * @param messenger - The BridgeStatusControllerMessenger instance
157
+ * @param trade - The trade data (can be approval or main trade)
158
+ * @param quoteResponse - The quote response containing metadata
159
+ * @param selectedAccount - The account to submit the transaction for
160
+ * @returns The transaction meta
161
+ */
162
+ export const handleNonEvmTx = async (messenger, trade, quoteResponse, selectedAccount) => {
163
+ if (!selectedAccount.metadata?.snap?.id) {
164
+ throw new Error('Failed to submit cross-chain swap transaction: undefined snap id');
165
+ }
166
+ const request = getClientRequest(trade, quoteResponse.quote.srcChainId, selectedAccount.id, selectedAccount.metadata?.snap?.id);
167
+ const requestResponse = (await messenger.call('SnapController:handleRequest', request));
168
+ const txMeta = handleNonEvmTxResponse(requestResponse, trade, quoteResponse, selectedAccount);
169
+ // TODO remove this eventually, just returning it now to match extension behavior
170
+ // OR if the snap can propagate the snapRequestId or keyringReqId to the ApprovalsController, this can return the approvalTxId instead and clients won't need to subscribe to the ApprovalsController state to redirect
171
+ return txMeta;
172
+ };
32
173
  //# sourceMappingURL=snaps.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"snaps.mjs","sourceRoot":"","sources":["../../src/utils/snaps.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,aAAa;AAElC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,MAAc,EACd,WAAmB,EACnB,KAAkB,EAClB,SAAiB,EACjB,OAAiC,EACjC,EAAE;IACF,OAAO;QACL,kCAAkC;QAClC,MAAM,EAAE,MAAe;QACvB,MAAM,EAAE,UAAU;QAClB,OAAO,EAAE,iBAA0B;QACnC,OAAO,EAAE;YACP,EAAE,EAAE,IAAI,EAAE;YACV,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,wBAAwB;YAChC,MAAM,EAAE;gBACN,WAAW;gBACX,KAAK;gBACL,SAAS;gBACT,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;aAC5B;SACF;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { CaipChainId } from '@metamask/utils';\nimport { v4 as uuid } from 'uuid';\n\n/**\n * Creates a client request object for signing and sending a transaction\n * Works for Solana, BTC, Tron, and other non-EVM networks\n *\n * @param snapId - The snap ID to send the request to\n * @param transaction - The base64 encoded transaction string\n * @param scope - The CAIP-2 chain scope\n * @param accountId - The account ID\n * @param options - Optional network-specific options\n * @returns The snap request object\n */\nexport const createClientTransactionRequest = (\n snapId: string,\n transaction: string,\n scope: CaipChainId,\n accountId: string,\n options?: Record<string, unknown>,\n) => {\n return {\n // TODO: remove 'as never' typing.\n snapId: snapId as never,\n origin: 'metamask',\n handler: 'onClientRequest' as never,\n request: {\n id: uuid(),\n jsonrpc: '2.0',\n method: 'signAndSendTransaction',\n params: {\n transaction,\n scope,\n accountId,\n ...(options && { options }),\n },\n },\n };\n};\n"]}
1
+ {"version":3,"file":"snaps.mjs","sourceRoot":"","sources":["../../src/utils/snaps.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport type { AccountsControllerState } from '@metamask/accounts-controller';\nimport type {\n QuoteMetadata,\n QuoteResponse,\n Trade,\n} from '@metamask/bridge-controller';\nimport {\n extractTradeData,\n formatChainIdToCaip,\n formatChainIdToHex,\n isCrossChain,\n isTronTrade,\n} from '@metamask/bridge-controller';\nimport {\n TransactionStatus,\n TransactionType,\n} from '@metamask/transaction-controller';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport { v4 as uuid } from 'uuid';\n\nimport type {\n BridgeStatusControllerMessenger,\n SolanaTransactionMeta,\n} from '../types';\n\n/**\n * Creates a client request object for signing and sending a transaction\n * Works for Solana, BTC, Tron, and other non-EVM networks\n *\n * @param snapId - The snap ID to send the request to\n * @param transaction - The base64 encoded transaction string\n * @param scope - The CAIP-2 chain scope\n * @param accountId - The account ID\n * @param options - Optional network-specific options\n * @returns The snap request object\n */\nexport const createClientTransactionRequest = (\n snapId: string,\n transaction: string,\n scope: CaipChainId,\n accountId: string,\n options?: Record<string, unknown>,\n) => {\n return {\n // TODO: remove 'as never' typing.\n snapId: snapId as never,\n origin: 'metamask',\n handler: 'onClientRequest' as never,\n request: {\n id: uuid(),\n jsonrpc: '2.0',\n method: 'signAndSendTransaction',\n params: {\n transaction,\n scope,\n accountId,\n ...(options && { options }),\n },\n },\n };\n};\n\n/**\n * Creates a request to sign and send a transaction for non-EVM chains\n * Uses the new unified ClientRequest:signAndSendTransaction interface\n *\n * @param trade - The trade data\n * @param srcChainId - The source chain ID\n * @param accountId - The selected account ID\n * @param snapId - The snap ID\n * @returns The snap request object for signing and sending transaction\n */\nexport const getClientRequest = (\n trade: Trade,\n srcChainId: number,\n accountId: string,\n snapId: string,\n) => {\n const scope = formatChainIdToCaip(srcChainId);\n\n const transactionData = extractTradeData(trade);\n\n // Tron trades need the visible flag and contract type to be included in the request options\n const options = isTronTrade(trade)\n ? {\n visible: trade.visible,\n type: trade.raw_data?.contract?.[0]?.type,\n }\n : undefined;\n\n // Use the new unified interface\n return createClientTransactionRequest(\n snapId,\n transactionData,\n scope,\n accountId,\n options,\n );\n};\n\nexport const getTxMetaFields = (\n quoteResponse: Omit<QuoteResponse<Trade, Trade>, 'approval' | 'trade'> &\n QuoteMetadata,\n approvalTxId?: string,\n): Omit<\n TransactionMeta,\n 'networkClientId' | 'status' | 'time' | 'txParams' | 'id' | 'chainId'\n> => {\n // Handle destination chain ID - should always be convertible for EVM destinations\n let destinationChainId;\n try {\n destinationChainId = formatChainIdToHex(quoteResponse.quote.destChainId);\n } catch {\n // Fallback for non-EVM destination (shouldn't happen for BTC->EVM)\n destinationChainId = '0x1' as `0x${string}`; // Default to mainnet\n }\n\n return {\n destinationChainId,\n sourceTokenAmount: quoteResponse.quote.srcTokenAmount,\n sourceTokenSymbol: quoteResponse.quote.srcAsset.symbol,\n sourceTokenDecimals: quoteResponse.quote.srcAsset.decimals,\n sourceTokenAddress: quoteResponse.quote.srcAsset.address,\n\n destinationTokenAmount: quoteResponse.quote.destTokenAmount,\n destinationTokenSymbol: quoteResponse.quote.destAsset.symbol,\n destinationTokenDecimals: quoteResponse.quote.destAsset.decimals,\n destinationTokenAddress: quoteResponse.quote.destAsset.address,\n\n // chainId is now excluded from this function and handled by the caller\n approvalTxId,\n // this is the decimal (non atomic) amount (not USD value) of source token to swap\n swapTokenValue: quoteResponse.sentAmount.amount,\n };\n};\n\n/**\n * Handles the response from non-EVM transaction submission\n * Works with the new unified ClientRequest:signAndSendTransaction interface\n * Supports Solana, Bitcoin, and other non-EVM chains\n *\n * @param snapResponse - The response from the snap after transaction submission\n * @param trade - The non-evm trade or approval data\n * @param quoteResponse - The quote response containing trade details and metadata\n * @param selectedAccount - The selected account information\n * @returns The transaction metadata including non-EVM specific fields\n */\nexport const handleNonEvmTxResponse = (\n snapResponse:\n | string\n | { transactionId: string } // New unified interface response\n | { result: Record<string, string> }\n | { signature: string },\n trade: Trade,\n quoteResponse: Omit<QuoteResponse<Trade>, 'trade' | 'approval'> &\n QuoteMetadata,\n selectedAccount: AccountsControllerState['internalAccounts']['accounts'][string],\n): TransactionMeta & SolanaTransactionMeta => {\n const selectedAccountAddress = selectedAccount.address;\n const snapId = selectedAccount.metadata.snap?.id;\n let hash;\n // Handle different response formats\n if (typeof snapResponse === 'string') {\n hash = snapResponse;\n } else if (snapResponse && typeof snapResponse === 'object') {\n // Check for new unified interface response format first\n if ('transactionId' in snapResponse && snapResponse.transactionId) {\n hash = snapResponse.transactionId;\n } else if (\n 'result' in snapResponse &&\n snapResponse.result &&\n typeof snapResponse.result === 'object'\n ) {\n // Try to extract signature from common locations in response object\n hash =\n snapResponse.result.signature ||\n snapResponse.result.txid ||\n snapResponse.result.hash ||\n snapResponse.result.txHash;\n } else if (\n 'signature' in snapResponse &&\n snapResponse.signature &&\n typeof snapResponse.signature === 'string'\n ) {\n hash = snapResponse.signature;\n }\n }\n\n const isBridgeTx = isCrossChain(\n quoteResponse.quote.srcChainId,\n quoteResponse.quote.destChainId,\n );\n\n let hexChainId: Hex;\n try {\n hexChainId = formatChainIdToHex(quoteResponse.quote.srcChainId);\n } catch {\n hexChainId = '0x1';\n }\n // Extract the transaction data for storage\n const tradeData = extractTradeData(trade);\n\n // Create a transaction meta object with bridge-specific fields\n return {\n ...getTxMetaFields(quoteResponse),\n time: Date.now(),\n id: hash ?? uuid(),\n chainId: hexChainId,\n networkClientId: snapId ?? 'mainnet',\n txParams: { from: selectedAccountAddress, data: tradeData },\n type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,\n status: TransactionStatus.submitted,\n hash, // Add the transaction signature as hash\n origin: snapId,\n // Add an explicit flag to mark this as a non-EVM transaction\n isSolana: true, // TODO deprecate this and use chainId to detect non-EVM chains\n isBridgeTx,\n };\n};\n\n/**\n * Submits the transaction to the snap using the new unified ClientRequest interface\n * Works for all non-EVM chains (Solana, BTC, Tron)\n * This adds an approval tx to the ApprovalsController in the background\n * The client needs to handle the approval tx by redirecting to the confirmation page with the approvalTxId in the URL\n *\n * @param messenger - The BridgeStatusControllerMessenger instance\n * @param trade - The trade data (can be approval or main trade)\n * @param quoteResponse - The quote response containing metadata\n * @param selectedAccount - The account to submit the transaction for\n * @returns The transaction meta\n */\nexport const handleNonEvmTx = async (\n messenger: BridgeStatusControllerMessenger,\n trade: Trade,\n quoteResponse: QuoteResponse<Trade, Trade> & QuoteMetadata,\n selectedAccount: AccountsControllerState['internalAccounts']['accounts'][string],\n): Promise<TransactionMeta> => {\n if (!selectedAccount.metadata?.snap?.id) {\n throw new Error(\n 'Failed to submit cross-chain swap transaction: undefined snap id',\n );\n }\n\n const request = getClientRequest(\n trade,\n quoteResponse.quote.srcChainId,\n selectedAccount.id,\n selectedAccount.metadata?.snap?.id,\n );\n const requestResponse = (await messenger.call(\n 'SnapController:handleRequest',\n request,\n )) as\n | string\n | { transactionId: string }\n | { result: Record<string, string> }\n | { signature: string };\n\n const txMeta = handleNonEvmTxResponse(\n requestResponse,\n trade,\n quoteResponse,\n selectedAccount,\n );\n\n // TODO remove this eventually, just returning it now to match extension behavior\n // OR if the snap can propagate the snapRequestId or keyringReqId to the ApprovalsController, this can return the approvalTxId instead and clients won't need to subscribe to the ApprovalsController state to redirect\n return txMeta;\n};\n"]}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getApprovalTraceParams = exports.getTraceParams = void 0;
4
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
5
+ const bridge_controller_1 = require("@metamask/bridge-controller");
6
+ const constants_1 = require("../constants.cjs");
7
+ const getTraceParams = (quoteResponse, isStxEnabledOnClient) => {
8
+ return {
9
+ name: (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId)
10
+ ? constants_1.TraceName.BridgeTransactionCompleted
11
+ : constants_1.TraceName.SwapTransactionCompleted,
12
+ data: {
13
+ srcChainId: (0, bridge_controller_1.formatChainIdToCaip)(quoteResponse.quote.srcChainId),
14
+ stxEnabled: isStxEnabledOnClient,
15
+ },
16
+ };
17
+ };
18
+ exports.getTraceParams = getTraceParams;
19
+ const getApprovalTraceParams = (quoteResponse, isStxEnabledOnClient) => {
20
+ return {
21
+ name: (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId)
22
+ ? constants_1.TraceName.BridgeTransactionApprovalCompleted
23
+ : constants_1.TraceName.SwapTransactionApprovalCompleted,
24
+ data: {
25
+ srcChainId: (0, bridge_controller_1.formatChainIdToCaip)(quoteResponse.quote.srcChainId),
26
+ stxEnabled: isStxEnabledOnClient,
27
+ },
28
+ };
29
+ };
30
+ exports.getApprovalTraceParams = getApprovalTraceParams;
31
+ //# sourceMappingURL=trace.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.cjs","sourceRoot":"","sources":["../../src/utils/trace.ts"],"names":[],"mappings":";;;AAAA,qEAAqE;AACrE,mEAIqC;AAErC,gDAAyC;AAElC,MAAM,cAAc,GAAG,CAC5B,aAA4B,EAC5B,oBAA6B,EAC7B,EAAE;IACF,OAAO;QACL,IAAI,EAAE,IAAA,gCAAY,EAChB,aAAa,CAAC,KAAK,CAAC,UAAU,EAC9B,aAAa,CAAC,KAAK,CAAC,WAAW,CAChC;YACC,CAAC,CAAC,qBAAS,CAAC,0BAA0B;YACtC,CAAC,CAAC,qBAAS,CAAC,wBAAwB;QACtC,IAAI,EAAE;YACJ,UAAU,EAAE,IAAA,uCAAmB,EAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/D,UAAU,EAAE,oBAAoB;SACjC;KACF,CAAC;AACJ,CAAC,CAAC;AAhBW,QAAA,cAAc,kBAgBzB;AAEK,MAAM,sBAAsB,GAAG,CACpC,aAA4B,EAC5B,oBAA6B,EAC7B,EAAE;IACF,OAAO;QACL,IAAI,EAAE,IAAA,gCAAY,EAChB,aAAa,CAAC,KAAK,CAAC,UAAU,EAC9B,aAAa,CAAC,KAAK,CAAC,WAAW,CAChC;YACC,CAAC,CAAC,qBAAS,CAAC,kCAAkC;YAC9C,CAAC,CAAC,qBAAS,CAAC,gCAAgC;QAC9C,IAAI,EAAE;YACJ,UAAU,EAAE,IAAA,uCAAmB,EAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/D,UAAU,EAAE,oBAAoB;SACjC;KACF,CAAC;AACJ,CAAC,CAAC;AAhBW,QAAA,sBAAsB,0BAgBjC","sourcesContent":["/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport {\n formatChainIdToCaip,\n isCrossChain,\n QuoteResponse,\n} from '@metamask/bridge-controller';\n\nimport { TraceName } from '../constants';\n\nexport const getTraceParams = (\n quoteResponse: QuoteResponse,\n isStxEnabledOnClient: boolean,\n) => {\n return {\n name: isCrossChain(\n quoteResponse.quote.srcChainId,\n quoteResponse.quote.destChainId,\n )\n ? TraceName.BridgeTransactionCompleted\n : TraceName.SwapTransactionCompleted,\n data: {\n srcChainId: formatChainIdToCaip(quoteResponse.quote.srcChainId),\n stxEnabled: isStxEnabledOnClient,\n },\n };\n};\n\nexport const getApprovalTraceParams = (\n quoteResponse: QuoteResponse,\n isStxEnabledOnClient: boolean,\n) => {\n return {\n name: isCrossChain(\n quoteResponse.quote.srcChainId,\n quoteResponse.quote.destChainId,\n )\n ? TraceName.BridgeTransactionApprovalCompleted\n : TraceName.SwapTransactionApprovalCompleted,\n data: {\n srcChainId: formatChainIdToCaip(quoteResponse.quote.srcChainId),\n stxEnabled: isStxEnabledOnClient,\n },\n };\n};\n"]}
@@ -0,0 +1,17 @@
1
+ import { QuoteResponse } from "@metamask/bridge-controller";
2
+ import { TraceName } from "../constants.cjs";
3
+ export declare const getTraceParams: (quoteResponse: QuoteResponse, isStxEnabledOnClient: boolean) => {
4
+ name: TraceName;
5
+ data: {
6
+ srcChainId: `${string}:${string}`;
7
+ stxEnabled: boolean;
8
+ };
9
+ };
10
+ export declare const getApprovalTraceParams: (quoteResponse: QuoteResponse, isStxEnabledOnClient: boolean) => {
11
+ name: TraceName;
12
+ data: {
13
+ srcChainId: `${string}:${string}`;
14
+ stxEnabled: boolean;
15
+ };
16
+ };
17
+ //# sourceMappingURL=trace.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.d.cts","sourceRoot":"","sources":["../../src/utils/trace.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,aAAa,EACd,oCAAoC;AAErC,OAAO,EAAE,SAAS,EAAE,yBAAqB;AAEzC,eAAO,MAAM,cAAc,kBACV,aAAa,wBACN,OAAO;;;;;;CAc9B,CAAC;AAEF,eAAO,MAAM,sBAAsB,kBAClB,aAAa,wBACN,OAAO;;;;;;CAc9B,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { QuoteResponse } from "@metamask/bridge-controller";
2
+ import { TraceName } from "../constants.mjs";
3
+ export declare const getTraceParams: (quoteResponse: QuoteResponse, isStxEnabledOnClient: boolean) => {
4
+ name: TraceName;
5
+ data: {
6
+ srcChainId: `${string}:${string}`;
7
+ stxEnabled: boolean;
8
+ };
9
+ };
10
+ export declare const getApprovalTraceParams: (quoteResponse: QuoteResponse, isStxEnabledOnClient: boolean) => {
11
+ name: TraceName;
12
+ data: {
13
+ srcChainId: `${string}:${string}`;
14
+ stxEnabled: boolean;
15
+ };
16
+ };
17
+ //# sourceMappingURL=trace.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.d.mts","sourceRoot":"","sources":["../../src/utils/trace.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,aAAa,EACd,oCAAoC;AAErC,OAAO,EAAE,SAAS,EAAE,yBAAqB;AAEzC,eAAO,MAAM,cAAc,kBACV,aAAa,wBACN,OAAO;;;;;;CAc9B,CAAC;AAEF,eAAO,MAAM,sBAAsB,kBAClB,aAAa,wBACN,OAAO;;;;;;CAc9B,CAAC"}
@@ -0,0 +1,26 @@
1
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
2
+ import { formatChainIdToCaip, isCrossChain } from "@metamask/bridge-controller";
3
+ import { TraceName } from "../constants.mjs";
4
+ export const getTraceParams = (quoteResponse, isStxEnabledOnClient) => {
5
+ return {
6
+ name: isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId)
7
+ ? TraceName.BridgeTransactionCompleted
8
+ : TraceName.SwapTransactionCompleted,
9
+ data: {
10
+ srcChainId: formatChainIdToCaip(quoteResponse.quote.srcChainId),
11
+ stxEnabled: isStxEnabledOnClient,
12
+ },
13
+ };
14
+ };
15
+ export const getApprovalTraceParams = (quoteResponse, isStxEnabledOnClient) => {
16
+ return {
17
+ name: isCrossChain(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId)
18
+ ? TraceName.BridgeTransactionApprovalCompleted
19
+ : TraceName.SwapTransactionApprovalCompleted,
20
+ data: {
21
+ srcChainId: formatChainIdToCaip(quoteResponse.quote.srcChainId),
22
+ stxEnabled: isStxEnabledOnClient,
23
+ },
24
+ };
25
+ };
26
+ //# sourceMappingURL=trace.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.mjs","sourceRoot":"","sources":["../../src/utils/trace.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EACL,mBAAmB,EACnB,YAAY,EAEb,oCAAoC;AAErC,OAAO,EAAE,SAAS,EAAE,yBAAqB;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,aAA4B,EAC5B,oBAA6B,EAC7B,EAAE;IACF,OAAO;QACL,IAAI,EAAE,YAAY,CAChB,aAAa,CAAC,KAAK,CAAC,UAAU,EAC9B,aAAa,CAAC,KAAK,CAAC,WAAW,CAChC;YACC,CAAC,CAAC,SAAS,CAAC,0BAA0B;YACtC,CAAC,CAAC,SAAS,CAAC,wBAAwB;QACtC,IAAI,EAAE;YACJ,UAAU,EAAE,mBAAmB,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/D,UAAU,EAAE,oBAAoB;SACjC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,aAA4B,EAC5B,oBAA6B,EAC7B,EAAE;IACF,OAAO;QACL,IAAI,EAAE,YAAY,CAChB,aAAa,CAAC,KAAK,CAAC,UAAU,EAC9B,aAAa,CAAC,KAAK,CAAC,WAAW,CAChC;YACC,CAAC,CAAC,SAAS,CAAC,kCAAkC;YAC9C,CAAC,CAAC,SAAS,CAAC,gCAAgC;QAC9C,IAAI,EAAE;YACJ,UAAU,EAAE,mBAAmB,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/D,UAAU,EAAE,oBAAoB;SACjC;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport {\n formatChainIdToCaip,\n isCrossChain,\n QuoteResponse,\n} from '@metamask/bridge-controller';\n\nimport { TraceName } from '../constants';\n\nexport const getTraceParams = (\n quoteResponse: QuoteResponse,\n isStxEnabledOnClient: boolean,\n) => {\n return {\n name: isCrossChain(\n quoteResponse.quote.srcChainId,\n quoteResponse.quote.destChainId,\n )\n ? TraceName.BridgeTransactionCompleted\n : TraceName.SwapTransactionCompleted,\n data: {\n srcChainId: formatChainIdToCaip(quoteResponse.quote.srcChainId),\n stxEnabled: isStxEnabledOnClient,\n },\n };\n};\n\nexport const getApprovalTraceParams = (\n quoteResponse: QuoteResponse,\n isStxEnabledOnClient: boolean,\n) => {\n return {\n name: isCrossChain(\n quoteResponse.quote.srcChainId,\n quoteResponse.quote.destChainId,\n )\n ? TraceName.BridgeTransactionApprovalCompleted\n : TraceName.SwapTransactionApprovalCompleted,\n data: {\n srcChainId: formatChainIdToCaip(quoteResponse.quote.srcChainId),\n stxEnabled: isStxEnabledOnClient,\n },\n };\n};\n"]}
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getIntentFromQuote = exports.getHistoryKey = exports.findAndUpdateTransactionsInBatch = exports.getAddTransactionBatchParams = exports.toBatchTxParams = exports.rekeyHistoryItemInState = exports.waitForTxConfirmation = exports.getClientRequest = exports.handleMobileHardwareWalletDelay = exports.handleApprovalDelay = exports.handleNonEvmTxResponse = exports.getTxMetaFields = exports.getStatusRequestParams = exports.generateActionId = void 0;
3
+ exports.findAndUpdateTransactionsInBatch = exports.getAddTransactionBatchParams = exports.toBatchTxParams = exports.waitForTxConfirmation = exports.handleMobileHardwareWalletDelay = exports.handleApprovalDelay = exports.getStatusRequestParams = exports.generateActionId = void 0;
4
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
4
5
  const bridge_controller_1 = require("@metamask/bridge-controller");
5
6
  const controller_utils_1 = require("@metamask/controller-utils");
6
7
  const transaction_controller_1 = require("@metamask/transaction-controller");
7
8
  const utils_1 = require("@metamask/utils");
8
- const uuid_1 = require("uuid");
9
+ const accounts_1 = require("./accounts.cjs");
9
10
  const gas_1 = require("./gas.cjs");
10
- const snaps_1 = require("./snaps.cjs");
11
+ const network_1 = require("./network.cjs");
11
12
  const constants_1 = require("../constants.cjs");
12
13
  const generateActionId = () => (Date.now() + Math.random()).toString();
13
14
  exports.generateActionId = generateActionId;
@@ -22,102 +23,6 @@ const getStatusRequestParams = (quoteResponse) => {
22
23
  };
23
24
  };
24
25
  exports.getStatusRequestParams = getStatusRequestParams;
25
- const getTxMetaFields = (quoteResponse, approvalTxId) => {
26
- // Handle destination chain ID - should always be convertible for EVM destinations
27
- let destinationChainId;
28
- try {
29
- destinationChainId = (0, bridge_controller_1.formatChainIdToHex)(quoteResponse.quote.destChainId);
30
- }
31
- catch {
32
- // Fallback for non-EVM destination (shouldn't happen for BTC->EVM)
33
- destinationChainId = '0x1'; // Default to mainnet
34
- }
35
- return {
36
- destinationChainId,
37
- sourceTokenAmount: quoteResponse.quote.srcTokenAmount,
38
- sourceTokenSymbol: quoteResponse.quote.srcAsset.symbol,
39
- sourceTokenDecimals: quoteResponse.quote.srcAsset.decimals,
40
- sourceTokenAddress: quoteResponse.quote.srcAsset.address,
41
- destinationTokenAmount: quoteResponse.quote.destTokenAmount,
42
- destinationTokenSymbol: quoteResponse.quote.destAsset.symbol,
43
- destinationTokenDecimals: quoteResponse.quote.destAsset.decimals,
44
- destinationTokenAddress: quoteResponse.quote.destAsset.address,
45
- // chainId is now excluded from this function and handled by the caller
46
- approvalTxId,
47
- // this is the decimal (non atomic) amount (not USD value) of source token to swap
48
- swapTokenValue: quoteResponse.sentAmount.amount,
49
- };
50
- };
51
- exports.getTxMetaFields = getTxMetaFields;
52
- /**
53
- * Handles the response from non-EVM transaction submission
54
- * Works with the new unified ClientRequest:signAndSendTransaction interface
55
- * Supports Solana, Bitcoin, and other non-EVM chains
56
- *
57
- * @param snapResponse - The response from the snap after transaction submission
58
- * @param quoteResponse - The quote response containing trade details and metadata
59
- * @param selectedAccount - The selected account information
60
- * @returns The transaction metadata including non-EVM specific fields
61
- */
62
- const handleNonEvmTxResponse = (snapResponse, quoteResponse, selectedAccount) => {
63
- const selectedAccountAddress = selectedAccount.address;
64
- const snapId = selectedAccount.metadata.snap?.id;
65
- let hash;
66
- // Handle different response formats
67
- if (typeof snapResponse === 'string') {
68
- hash = snapResponse;
69
- }
70
- else if (snapResponse && typeof snapResponse === 'object') {
71
- // Check for new unified interface response format first
72
- if ('transactionId' in snapResponse && snapResponse.transactionId) {
73
- hash = snapResponse.transactionId;
74
- }
75
- else if ('result' in snapResponse &&
76
- snapResponse.result &&
77
- typeof snapResponse.result === 'object') {
78
- // Try to extract signature from common locations in response object
79
- hash =
80
- snapResponse.result.signature ||
81
- snapResponse.result.txid ||
82
- snapResponse.result.hash ||
83
- snapResponse.result.txHash;
84
- }
85
- else if ('signature' in snapResponse &&
86
- snapResponse.signature &&
87
- typeof snapResponse.signature === 'string') {
88
- hash = snapResponse.signature;
89
- }
90
- }
91
- const isBridgeTx = (0, bridge_controller_1.isCrossChain)(quoteResponse.quote.srcChainId, quoteResponse.quote.destChainId);
92
- let hexChainId;
93
- try {
94
- hexChainId = (0, bridge_controller_1.formatChainIdToHex)(quoteResponse.quote.srcChainId);
95
- }
96
- catch {
97
- // TODO: Fix chain ID activity list handling for Bitcoin
98
- // Fallback to Ethereum mainnet for now
99
- hexChainId = '0x1';
100
- }
101
- // Extract the transaction data for storage
102
- const tradeData = (0, bridge_controller_1.extractTradeData)(quoteResponse.trade);
103
- // Create a transaction meta object with bridge-specific fields
104
- return {
105
- ...(0, exports.getTxMetaFields)(quoteResponse),
106
- time: Date.now(),
107
- id: hash ?? (0, uuid_1.v4)(),
108
- chainId: hexChainId,
109
- networkClientId: snapId ?? hexChainId,
110
- txParams: { from: selectedAccountAddress, data: tradeData },
111
- type: isBridgeTx ? transaction_controller_1.TransactionType.bridge : transaction_controller_1.TransactionType.swap,
112
- status: transaction_controller_1.TransactionStatus.submitted,
113
- hash, // Add the transaction signature as hash
114
- origin: snapId,
115
- // Add an explicit flag to mark this as a non-EVM transaction
116
- isSolana: true, // TODO deprecate this and use chainId to detect non-EVM chains
117
- isBridgeTx,
118
- };
119
- };
120
- exports.handleNonEvmTxResponse = handleNonEvmTxResponse;
121
26
  const handleApprovalDelay = async (srcChainId) => {
122
27
  if ([bridge_controller_1.ChainId.LINEA, bridge_controller_1.ChainId.BASE].includes(srcChainId)) {
123
28
  const debugLog = (0, utils_1.createProjectLogger)('bridge');
@@ -141,29 +46,6 @@ const handleMobileHardwareWalletDelay = async (requireApproval) => {
141
46
  }
142
47
  };
143
48
  exports.handleMobileHardwareWalletDelay = handleMobileHardwareWalletDelay;
144
- /**
145
- * Creates a request to sign and send a transaction for non-EVM chains
146
- * Uses the new unified ClientRequest:signAndSendTransaction interface
147
- *
148
- * @param trade - The trade data
149
- * @param srcChainId - The source chain ID
150
- * @param selectedAccount - The selected account information
151
- * @returns The snap request object for signing and sending transaction
152
- */
153
- const getClientRequest = (trade, srcChainId, selectedAccount) => {
154
- const scope = (0, bridge_controller_1.formatChainIdToCaip)(srcChainId);
155
- const transactionData = (0, bridge_controller_1.extractTradeData)(trade);
156
- // Tron trades need the visible flag and contract type to be included in the request options
157
- const options = (0, bridge_controller_1.isTronTrade)(trade)
158
- ? {
159
- visible: trade.visible,
160
- type: trade.raw_data?.contract?.[0]?.type,
161
- }
162
- : undefined;
163
- // Use the new unified interface
164
- return (0, snaps_1.createClientTransactionRequest)(selectedAccount.metadata.snap?.id, transactionData, scope, selectedAccount.id, options);
165
- };
166
- exports.getClientRequest = getClientRequest;
167
49
  const waitForTxConfirmation = async (messenger, txId, { timeoutMs = 5 * 60000, pollMs = 3000, } = {}) => {
168
50
  const start = Date.now();
169
51
  while (true) {
@@ -186,35 +68,14 @@ const waitForTxConfirmation = async (messenger, txId, { timeoutMs = 5 * 60000, p
186
68
  }
187
69
  };
188
70
  exports.waitForTxConfirmation = waitForTxConfirmation;
189
- const rekeyHistoryItemInState = (state, actionId, txMeta) => {
190
- const historyItem = state.txHistory[actionId];
191
- if (!historyItem) {
192
- return false;
193
- }
194
- state.txHistory[txMeta.id] = {
195
- ...historyItem,
196
- txMetaId: txMeta.id,
197
- originalTransactionId: historyItem.originalTransactionId ?? txMeta.id,
198
- status: {
199
- ...historyItem.status,
200
- srcChain: {
201
- ...historyItem.status.srcChain,
202
- txHash: txMeta.hash ?? historyItem.status.srcChain?.txHash,
203
- },
204
- },
205
- };
206
- delete state.txHistory[actionId];
207
- return true;
208
- };
209
- exports.rekeyHistoryItemInState = rekeyHistoryItemInState;
210
- const toBatchTxParams = (disable7702, { chainId, gasLimit, ...trade }, { maxFeePerGas, maxPriorityFeePerGas, gas, }) => {
71
+ const toBatchTxParams = (skipGasFields, { chainId, gasLimit, ...trade }, { maxFeePerGas, maxPriorityFeePerGas, gas, }) => {
211
72
  const params = {
212
73
  ...trade,
213
74
  data: trade.data,
214
75
  to: trade.to,
215
76
  value: trade.value,
216
77
  };
217
- if (!disable7702) {
78
+ if (skipGasFields) {
218
79
  return params;
219
80
  }
220
81
  return {
@@ -225,40 +86,43 @@ const toBatchTxParams = (disable7702, { chainId, gasLimit, ...trade }, { maxFeeP
225
86
  };
226
87
  };
227
88
  exports.toBatchTxParams = toBatchTxParams;
228
- const getAddTransactionBatchParams = async ({ messenger, isBridgeTx, approval, resetApproval, trade, quoteResponse: { quote: { feeData: { txFee }, gasIncluded, gasIncluded7702, gasSponsored, }, sentAmount, toTokenAmount, }, requireApproval = false, estimateGasFeeFn, }) => {
89
+ const getAddTransactionBatchParams = async ({ messenger, isBridgeTx, approval, resetApproval, trade, quoteResponse: { quote: { feeData: { txFee }, gasIncluded, gasIncluded7702, gasSponsored, }, sentAmount, toTokenAmount, }, requireApproval = false, isDelegatedAccount = false, }) => {
229
90
  const isGasless = gasIncluded || gasIncluded7702;
230
- const selectedAccount = messenger.call('AccountsController:getAccountByAddress', trade.from);
91
+ const selectedAccount = (0, accounts_1.getAccountByAddress)(messenger, trade.from);
231
92
  if (!selectedAccount) {
232
93
  throw new Error('Failed to submit cross-chain swap batch transaction: unknown account in trade data');
233
94
  }
234
95
  const hexChainId = (0, bridge_controller_1.formatChainIdToHex)(trade.chainId);
235
- const networkClientId = messenger.call('NetworkController:findNetworkClientIdByChainId', hexChainId);
236
- // When an active quote has gasIncluded7702 set to true,
237
- // enable 7702 gasless txs for smart accounts
238
- const disable7702 = gasIncluded7702 !== true;
96
+ const networkClientId = (0, network_1.getNetworkClientIdByChainId)(messenger, hexChainId);
97
+ // Gas fields should be omitted only when gas is sponsored via 7702
98
+ const skipGasFields = gasIncluded7702 === true;
99
+ // Enable 7702 batching when the quote includes gasless 7702 support,
100
+ // or when the account is already delegated (to avoid the in-flight
101
+ // transaction limit for delegated accounts)
102
+ const disable7702 = !skipGasFields && !isDelegatedAccount;
239
103
  const transactions = [];
240
104
  if (resetApproval) {
241
- const gasFees = await (0, gas_1.calculateGasFees)(disable7702, messenger, estimateGasFeeFn, resetApproval, networkClientId, hexChainId, isGasless ? txFee : undefined);
105
+ const gasFees = await (0, gas_1.calculateGasFees)(skipGasFields, messenger, resetApproval, networkClientId, hexChainId, isGasless ? txFee : undefined);
242
106
  transactions.push({
243
107
  type: isBridgeTx
244
108
  ? transaction_controller_1.TransactionType.bridgeApproval
245
109
  : transaction_controller_1.TransactionType.swapApproval,
246
- params: (0, exports.toBatchTxParams)(disable7702, resetApproval, gasFees),
110
+ params: (0, exports.toBatchTxParams)(skipGasFields, resetApproval, gasFees),
247
111
  });
248
112
  }
249
113
  if (approval) {
250
- const gasFees = await (0, gas_1.calculateGasFees)(disable7702, messenger, estimateGasFeeFn, approval, networkClientId, hexChainId, isGasless ? txFee : undefined);
114
+ const gasFees = await (0, gas_1.calculateGasFees)(skipGasFields, messenger, approval, networkClientId, hexChainId, isGasless ? txFee : undefined);
251
115
  transactions.push({
252
116
  type: isBridgeTx
253
117
  ? transaction_controller_1.TransactionType.bridgeApproval
254
118
  : transaction_controller_1.TransactionType.swapApproval,
255
- params: (0, exports.toBatchTxParams)(disable7702, approval, gasFees),
119
+ params: (0, exports.toBatchTxParams)(skipGasFields, approval, gasFees),
256
120
  });
257
121
  }
258
- const gasFees = await (0, gas_1.calculateGasFees)(disable7702, messenger, estimateGasFeeFn, trade, networkClientId, hexChainId, isGasless ? txFee : undefined);
122
+ const gasFees = await (0, gas_1.calculateGasFees)(skipGasFields, messenger, trade, networkClientId, hexChainId, isGasless ? txFee : undefined);
259
123
  transactions.push({
260
124
  type: isBridgeTx ? transaction_controller_1.TransactionType.bridge : transaction_controller_1.TransactionType.swap,
261
- params: (0, exports.toBatchTxParams)(disable7702, trade, gasFees),
125
+ params: (0, exports.toBatchTxParams)(skipGasFields, trade, gasFees),
262
126
  assetsFiatValues: {
263
127
  sending: sentAmount?.valueInCurrency?.toString(),
264
128
  receiving: toTokenAmount?.valueInCurrency?.toString(),
@@ -277,7 +141,7 @@ const getAddTransactionBatchParams = async ({ messenger, isBridgeTx, approval, r
277
141
  return transactionParams;
278
142
  };
279
143
  exports.getAddTransactionBatchParams = getAddTransactionBatchParams;
280
- const findAndUpdateTransactionsInBatch = ({ messenger, updateTransactionFn, batchId, txDataByType, }) => {
144
+ const findAndUpdateTransactionsInBatch = ({ messenger, batchId, txDataByType, }) => {
281
145
  const txs = messenger.call('TransactionController:getState').transactions;
282
146
  const txBatch = {
283
147
  approvalMeta: undefined,
@@ -286,6 +150,10 @@ const findAndUpdateTransactionsInBatch = ({ messenger, updateTransactionFn, batc
286
150
  // This is a workaround to update the tx type after the tx is signed
287
151
  // TODO: remove this once the tx type for batch txs is preserved in the tx controller
288
152
  Object.entries(txDataByType).forEach(([txType, txData]) => {
153
+ // Skip types not present in the batch (e.g. swap entry is undefined for bridge txs)
154
+ if (txData === undefined) {
155
+ return;
156
+ }
289
157
  // Find transaction by batchId and either matching data or delegation characteristics
290
158
  const txMeta = txs.find((tx) => {
291
159
  if (tx.batchId !== batchId) {
@@ -299,12 +167,14 @@ const findAndUpdateTransactionsInBatch = ({ messenger, updateTransactionFn, batc
299
167
  if (is7702Transaction) {
300
168
  // For 7702 transactions, we need to match based on transaction type
301
169
  // since the data field might be different (batch execute call)
302
- if (txType === transaction_controller_1.TransactionType.swap &&
170
+ if ((txType === transaction_controller_1.TransactionType.swap ||
171
+ txType === transaction_controller_1.TransactionType.bridge) &&
303
172
  tx.type === transaction_controller_1.TransactionType.batch) {
304
173
  return true;
305
174
  }
306
175
  // Also check if it's an approval transaction for 7702
307
- if (txType === transaction_controller_1.TransactionType.swapApproval &&
176
+ if ((txType === transaction_controller_1.TransactionType.swapApproval ||
177
+ txType === transaction_controller_1.TransactionType.bridgeApproval) &&
308
178
  tx.txParams.data === txData) {
309
179
  return true;
310
180
  }
@@ -314,7 +184,7 @@ const findAndUpdateTransactionsInBatch = ({ messenger, updateTransactionFn, batc
314
184
  });
315
185
  if (txMeta) {
316
186
  const updatedTx = { ...txMeta, type: txType };
317
- updateTransactionFn(updatedTx, `Update tx type to ${txType}`);
187
+ messenger.call('TransactionController:updateTransaction', updatedTx, `Update tx type to ${txType}`);
318
188
  txBatch[[transaction_controller_1.TransactionType.bridgeApproval, transaction_controller_1.TransactionType.swapApproval].includes(txType)
319
189
  ? 'approvalMeta'
320
190
  : 'tradeMeta'] = updatedTx;
@@ -323,36 +193,4 @@ const findAndUpdateTransactionsInBatch = ({ messenger, updateTransactionFn, batc
323
193
  return txBatch;
324
194
  };
325
195
  exports.findAndUpdateTransactionsInBatch = findAndUpdateTransactionsInBatch;
326
- /**
327
- * Determines the key to use for storing a bridge history item.
328
- * Uses actionId for pre-submission tracking, or bridgeTxMetaId for post-submission.
329
- *
330
- * @param actionId - The action ID used for pre-submission tracking
331
- * @param bridgeTxMetaId - The transaction meta ID from bridgeTxMeta
332
- * @returns The key to use for the history item
333
- * @throws Error if neither actionId nor bridgeTxMetaId is provided
334
- */
335
- function getHistoryKey(actionId, bridgeTxMetaId) {
336
- const historyKey = actionId ?? bridgeTxMetaId;
337
- if (!historyKey) {
338
- throw new Error('Cannot add tx to history: either actionId or bridgeTxMeta.id must be provided');
339
- }
340
- return historyKey;
341
- }
342
- exports.getHistoryKey = getHistoryKey;
343
- /**
344
- * Extracts and validates the intent data from a quote response.
345
- *
346
- * @param quoteResponse - The quote response that may contain intent data
347
- * @returns The intent data from the quote
348
- * @throws Error if the quote does not contain intent data
349
- */
350
- function getIntentFromQuote(quoteResponse) {
351
- const { intent } = quoteResponse.quote;
352
- if (!intent) {
353
- throw new Error('submitIntent: missing intent data');
354
- }
355
- return intent;
356
- }
357
- exports.getIntentFromQuote = getIntentFromQuote;
358
196
  //# sourceMappingURL=transaction.cjs.map