@metamask-previews/bridge-status-controller 1.0.0-preview-dbdf1da
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 +17 -0
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/dist/bridge-status-controller.cjs +247 -0
- package/dist/bridge-status-controller.cjs.map +1 -0
- package/dist/bridge-status-controller.d.cts +44 -0
- package/dist/bridge-status-controller.d.cts.map +1 -0
- package/dist/bridge-status-controller.d.mts +44 -0
- package/dist/bridge-status-controller.d.mts.map +1 -0
- package/dist/bridge-status-controller.mjs +243 -0
- package/dist/bridge-status-controller.mjs.map +1 -0
- package/dist/constants.cjs +12 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +10 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.mts +10 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +9 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/index.cjs +17 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.cjs +42 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +240 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +240 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +39 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils/bridge-status.cjs +53 -0
- package/dist/utils/bridge-status.cjs.map +1 -0
- package/dist/utils/bridge-status.d.cts +10 -0
- package/dist/utils/bridge-status.d.cts.map +1 -0
- package/dist/utils/bridge-status.d.mts +10 -0
- package/dist/utils/bridge-status.d.mts.map +1 -0
- package/dist/utils/bridge-status.mjs +46 -0
- package/dist/utils/bridge-status.mjs.map +1 -0
- package/dist/utils/validators.cjs +161 -0
- package/dist/utils/validators.cjs.map +1 -0
- package/dist/utils/validators.d.cts +15 -0
- package/dist/utils/validators.d.cts.map +1 -0
- package/dist/utils/validators.d.mts +15 -0
- package/dist/utils/validators.d.mts.map +1 -0
- package/dist/utils/validators.mjs +155 -0
- package/dist/utils/validators.mjs.map +1 -0
- package/package.json +85 -0
package/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [1.0.0]
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Initial release ([#5317](https://github.com/MetaMask/core/pull/5317))
|
15
|
+
|
16
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/bridge-status-controller@1.0.0...HEAD
|
17
|
+
[1.0.0]: https://github.com/MetaMask/core/releases/tag/@metamask/bridge-status-controller@1.0.0
|
package/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 MetaMask
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# `@metamask/bridge-status-controller`
|
2
|
+
|
3
|
+
Manages bridge-related status fetching functionality for MetaMask.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
`yarn add @metamask/bridge-status-controller`
|
8
|
+
|
9
|
+
or
|
10
|
+
|
11
|
+
`npm install @metamask/bridge-status-controller`
|
12
|
+
|
13
|
+
## Contributing
|
14
|
+
|
15
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
@@ -0,0 +1,247 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
7
|
+
};
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
12
|
+
};
|
13
|
+
var _BridgeStatusController_instances, _BridgeStatusController_pollingTokensByTxMetaId, _BridgeStatusController_clientId, _BridgeStatusController_fetchFn, _BridgeStatusController_restartPollingForIncompleteHistoryItems, _BridgeStatusController_getSelectedAccount, _BridgeStatusController_fetchBridgeTxStatus, _BridgeStatusController_getSrcTxHash, _BridgeStatusController_updateSrcTxHash, _BridgeStatusController_wipeBridgeStatusByChainId;
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
exports.BridgeStatusController = void 0;
|
16
|
+
const polling_controller_1 = require("@metamask/polling-controller");
|
17
|
+
const utils_1 = require("@metamask/utils");
|
18
|
+
const constants_1 = require("./constants.cjs");
|
19
|
+
const types_1 = require("./types.cjs");
|
20
|
+
const bridge_status_1 = require("./utils/bridge-status.cjs");
|
21
|
+
const metadata = {
|
22
|
+
// We want to persist the bridge status state so that we can show the proper data for the Activity list
|
23
|
+
// basically match the behavior of TransactionController
|
24
|
+
bridgeStatusState: {
|
25
|
+
persist: true,
|
26
|
+
anonymous: false,
|
27
|
+
},
|
28
|
+
};
|
29
|
+
class BridgeStatusController extends (0, polling_controller_1.StaticIntervalPollingController)() {
|
30
|
+
constructor({ messenger, state, clientId, fetchFn, }) {
|
31
|
+
super({
|
32
|
+
name: constants_1.BRIDGE_STATUS_CONTROLLER_NAME,
|
33
|
+
metadata,
|
34
|
+
messenger,
|
35
|
+
// Restore the persisted state
|
36
|
+
state: {
|
37
|
+
...state,
|
38
|
+
bridgeStatusState: {
|
39
|
+
...constants_1.DEFAULT_BRIDGE_STATUS_STATE,
|
40
|
+
...state?.bridgeStatusState,
|
41
|
+
},
|
42
|
+
},
|
43
|
+
});
|
44
|
+
_BridgeStatusController_instances.add(this);
|
45
|
+
_BridgeStatusController_pollingTokensByTxMetaId.set(this, {});
|
46
|
+
_BridgeStatusController_clientId.set(this, void 0);
|
47
|
+
_BridgeStatusController_fetchFn.set(this, void 0);
|
48
|
+
this.resetState = () => {
|
49
|
+
this.update((state) => {
|
50
|
+
state.bridgeStatusState = {
|
51
|
+
...constants_1.DEFAULT_BRIDGE_STATUS_STATE,
|
52
|
+
};
|
53
|
+
});
|
54
|
+
};
|
55
|
+
this.wipeBridgeStatus = ({ address, ignoreNetwork, }) => {
|
56
|
+
// Wipe all networks for this address
|
57
|
+
if (ignoreNetwork) {
|
58
|
+
this.update((state) => {
|
59
|
+
state.bridgeStatusState = {
|
60
|
+
...constants_1.DEFAULT_BRIDGE_STATUS_STATE,
|
61
|
+
};
|
62
|
+
});
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
|
66
|
+
const selectedNetworkClient = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
67
|
+
const selectedChainId = selectedNetworkClient.configuration.chainId;
|
68
|
+
__classPrivateFieldGet(this, _BridgeStatusController_wipeBridgeStatusByChainId, "f").call(this, address, selectedChainId);
|
69
|
+
}
|
70
|
+
};
|
71
|
+
_BridgeStatusController_restartPollingForIncompleteHistoryItems.set(this, () => {
|
72
|
+
// Check for historyItems that do not have a status of complete and restart polling
|
73
|
+
const { bridgeStatusState } = this.state;
|
74
|
+
const historyItems = Object.values(bridgeStatusState.txHistory);
|
75
|
+
const incompleteHistoryItems = historyItems
|
76
|
+
.filter((historyItem) => historyItem.status.status === types_1.StatusTypes.PENDING ||
|
77
|
+
historyItem.status.status === types_1.StatusTypes.UNKNOWN)
|
78
|
+
.filter((historyItem) => {
|
79
|
+
// Check if we are already polling this tx, if so, skip restarting polling for that
|
80
|
+
const srcTxMetaId = historyItem.txMetaId;
|
81
|
+
const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[srcTxMetaId];
|
82
|
+
return !pollingToken;
|
83
|
+
});
|
84
|
+
incompleteHistoryItems.forEach((historyItem) => {
|
85
|
+
const bridgeTxMetaId = historyItem.txMetaId;
|
86
|
+
// We manually call startPolling() here rather than go through startPollingForBridgeTxStatus()
|
87
|
+
// because we don't want to overwrite the existing historyItem in state
|
88
|
+
__classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId] = this.startPolling({
|
89
|
+
bridgeTxMetaId,
|
90
|
+
});
|
91
|
+
});
|
92
|
+
});
|
93
|
+
this.startPollingForBridgeTxStatus = (startPollingForBridgeTxStatusArgs) => {
|
94
|
+
const { bridgeTxMeta, statusRequest, quoteResponse, startTime, slippagePercentage, initialDestAssetBalance, targetContractAddress, } = startPollingForBridgeTxStatusArgs;
|
95
|
+
const { address: account } = __classPrivateFieldGet(this, _BridgeStatusController_instances, "m", _BridgeStatusController_getSelectedAccount).call(this);
|
96
|
+
// Write all non-status fields to state so we can reference the quote in Activity list without the Bridge API
|
97
|
+
// We know it's in progress but not the exact status yet
|
98
|
+
const txHistoryItem = {
|
99
|
+
txMetaId: bridgeTxMeta.id,
|
100
|
+
quote: quoteResponse.quote,
|
101
|
+
startTime,
|
102
|
+
estimatedProcessingTimeInSeconds: quoteResponse.estimatedProcessingTimeInSeconds,
|
103
|
+
slippagePercentage,
|
104
|
+
pricingData: {
|
105
|
+
amountSent: quoteResponse.sentAmount.amount,
|
106
|
+
amountSentInUsd: quoteResponse.sentAmount.usd ?? undefined,
|
107
|
+
quotedGasInUsd: quoteResponse.gasFee.usd ?? undefined,
|
108
|
+
quotedReturnInUsd: quoteResponse.toTokenAmount.usd ?? undefined,
|
109
|
+
},
|
110
|
+
initialDestAssetBalance,
|
111
|
+
targetContractAddress,
|
112
|
+
account,
|
113
|
+
status: {
|
114
|
+
// We always have a PENDING status when we start polling for a tx, don't need the Bridge API for that
|
115
|
+
// Also we know the bare minimum fields for status at this point in time
|
116
|
+
status: types_1.StatusTypes.PENDING,
|
117
|
+
srcChain: {
|
118
|
+
chainId: statusRequest.srcChainId,
|
119
|
+
txHash: statusRequest.srcTxHash,
|
120
|
+
},
|
121
|
+
},
|
122
|
+
hasApprovalTx: Boolean(quoteResponse.approval),
|
123
|
+
};
|
124
|
+
this.update((state) => {
|
125
|
+
// Use the txMeta.id as the key so we can reference the txMeta in TransactionController
|
126
|
+
state.bridgeStatusState.txHistory[bridgeTxMeta.id] = txHistoryItem;
|
127
|
+
});
|
128
|
+
__classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMeta.id] = this.startPolling({
|
129
|
+
bridgeTxMetaId: bridgeTxMeta.id,
|
130
|
+
});
|
131
|
+
};
|
132
|
+
// This will be called after you call this.startPolling()
|
133
|
+
// The args passed in are the args you passed in to startPolling()
|
134
|
+
this._executePoll = async (pollingInput) => {
|
135
|
+
await __classPrivateFieldGet(this, _BridgeStatusController_fetchBridgeTxStatus, "f").call(this, pollingInput);
|
136
|
+
};
|
137
|
+
_BridgeStatusController_fetchBridgeTxStatus.set(this, async ({ bridgeTxMetaId, }) => {
|
138
|
+
const { bridgeStatusState } = this.state;
|
139
|
+
try {
|
140
|
+
// We try here because we receive 500 errors from Bridge API if we try to fetch immediately after submitting the source tx
|
141
|
+
// Oddly mostly happens on Optimism, never on Arbitrum. By the 2nd fetch, the Bridge API responds properly.
|
142
|
+
// Also srcTxHash may not be available immediately for STX, so we don't want to fetch in those cases
|
143
|
+
const historyItem = bridgeStatusState.txHistory[bridgeTxMetaId];
|
144
|
+
const srcTxHash = __classPrivateFieldGet(this, _BridgeStatusController_getSrcTxHash, "f").call(this, bridgeTxMetaId);
|
145
|
+
if (!srcTxHash) {
|
146
|
+
return;
|
147
|
+
}
|
148
|
+
__classPrivateFieldGet(this, _BridgeStatusController_updateSrcTxHash, "f").call(this, bridgeTxMetaId, srcTxHash);
|
149
|
+
const statusRequest = (0, bridge_status_1.getStatusRequestWithSrcTxHash)(historyItem.quote, srcTxHash);
|
150
|
+
const status = await (0, bridge_status_1.fetchBridgeTxStatus)(statusRequest, __classPrivateFieldGet(this, _BridgeStatusController_clientId, "f"), __classPrivateFieldGet(this, _BridgeStatusController_fetchFn, "f"));
|
151
|
+
const newBridgeHistoryItem = {
|
152
|
+
...historyItem,
|
153
|
+
status,
|
154
|
+
completionTime: status.status === types_1.StatusTypes.COMPLETE ||
|
155
|
+
status.status === types_1.StatusTypes.FAILED
|
156
|
+
? Date.now()
|
157
|
+
: undefined, // TODO make this more accurate by looking up dest txHash block time
|
158
|
+
};
|
159
|
+
// No need to purge these on network change or account change, TransactionController does not purge either.
|
160
|
+
// TODO In theory we can skip checking status if it's not the current account/network
|
161
|
+
// we need to keep track of the account that this is associated with as well so that we don't show it in Activity list for other accounts
|
162
|
+
// First stab at this will not stop polling when you are on a different account
|
163
|
+
this.update((state) => {
|
164
|
+
state.bridgeStatusState.txHistory[bridgeTxMetaId] =
|
165
|
+
newBridgeHistoryItem;
|
166
|
+
});
|
167
|
+
const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[bridgeTxMetaId];
|
168
|
+
if ((status.status === types_1.StatusTypes.COMPLETE ||
|
169
|
+
status.status === types_1.StatusTypes.FAILED) &&
|
170
|
+
pollingToken) {
|
171
|
+
this.stopPollingByPollingToken(pollingToken);
|
172
|
+
if (status.status === types_1.StatusTypes.COMPLETE) {
|
173
|
+
this.messagingSystem.publish(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionComplete`, { bridgeHistoryItem: newBridgeHistoryItem });
|
174
|
+
}
|
175
|
+
if (status.status === types_1.StatusTypes.FAILED) {
|
176
|
+
this.messagingSystem.publish(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionFailed`, { bridgeHistoryItem: newBridgeHistoryItem });
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
catch (e) {
|
181
|
+
console.log('Failed to fetch bridge tx status', e);
|
182
|
+
}
|
183
|
+
});
|
184
|
+
_BridgeStatusController_getSrcTxHash.set(this, (bridgeTxMetaId) => {
|
185
|
+
const { bridgeStatusState } = this.state;
|
186
|
+
// Prefer the srcTxHash from bridgeStatusState so we don't have to l ook up in TransactionController
|
187
|
+
// But it is possible to have bridgeHistoryItem in state without the srcTxHash yet when it is an STX
|
188
|
+
const srcTxHash = bridgeStatusState.txHistory[bridgeTxMetaId].status.srcChain.txHash;
|
189
|
+
if (srcTxHash) {
|
190
|
+
return srcTxHash;
|
191
|
+
}
|
192
|
+
// Look up in TransactionController if txMeta has been updated with the srcTxHash
|
193
|
+
const txControllerState = this.messagingSystem.call('TransactionController:getState');
|
194
|
+
const txMeta = txControllerState.transactions.find((tx) => tx.id === bridgeTxMetaId);
|
195
|
+
return txMeta?.hash;
|
196
|
+
});
|
197
|
+
_BridgeStatusController_updateSrcTxHash.set(this, (bridgeTxMetaId, srcTxHash) => {
|
198
|
+
const { bridgeStatusState } = this.state;
|
199
|
+
if (bridgeStatusState.txHistory[bridgeTxMetaId].status.srcChain.txHash) {
|
200
|
+
return;
|
201
|
+
}
|
202
|
+
this.update((state) => {
|
203
|
+
state.bridgeStatusState.txHistory[bridgeTxMetaId].status.srcChain.txHash =
|
204
|
+
srcTxHash;
|
205
|
+
});
|
206
|
+
});
|
207
|
+
// Wipes the bridge status for the given address and chainId
|
208
|
+
// Will match only source chainId to the selectedChainId
|
209
|
+
_BridgeStatusController_wipeBridgeStatusByChainId.set(this, (address, selectedChainId) => {
|
210
|
+
const sourceTxMetaIdsToDelete = Object.keys(this.state.bridgeStatusState.txHistory).filter((txMetaId) => {
|
211
|
+
const bridgeHistoryItem = this.state.bridgeStatusState.txHistory[txMetaId];
|
212
|
+
const hexSourceChainId = (0, utils_1.numberToHex)(bridgeHistoryItem.quote.srcChainId);
|
213
|
+
return (bridgeHistoryItem.account === address &&
|
214
|
+
hexSourceChainId === selectedChainId);
|
215
|
+
});
|
216
|
+
sourceTxMetaIdsToDelete.forEach((sourceTxMetaId) => {
|
217
|
+
const pollingToken = __classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[sourceTxMetaId];
|
218
|
+
if (pollingToken) {
|
219
|
+
this.stopPollingByPollingToken(__classPrivateFieldGet(this, _BridgeStatusController_pollingTokensByTxMetaId, "f")[sourceTxMetaId]);
|
220
|
+
}
|
221
|
+
});
|
222
|
+
this.update((state) => {
|
223
|
+
state.bridgeStatusState.txHistory = sourceTxMetaIdsToDelete.reduce((acc, sourceTxMetaId) => {
|
224
|
+
delete acc[sourceTxMetaId];
|
225
|
+
return acc;
|
226
|
+
}, state.bridgeStatusState.txHistory);
|
227
|
+
});
|
228
|
+
});
|
229
|
+
__classPrivateFieldSet(this, _BridgeStatusController_clientId, clientId, "f");
|
230
|
+
__classPrivateFieldSet(this, _BridgeStatusController_fetchFn, fetchFn, "f");
|
231
|
+
// Register action handlers
|
232
|
+
this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`, this.startPollingForBridgeTxStatus.bind(this));
|
233
|
+
this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`, this.wipeBridgeStatus.bind(this));
|
234
|
+
this.messagingSystem.registerActionHandler(`${constants_1.BRIDGE_STATUS_CONTROLLER_NAME}:resetState`, this.resetState.bind(this));
|
235
|
+
// Set interval
|
236
|
+
this.setIntervalLength(constants_1.REFRESH_INTERVAL_MS);
|
237
|
+
// If you close the extension, but keep the browser open, the polling continues
|
238
|
+
// If you close the browser, the polling stops
|
239
|
+
// Check for historyItems that do not have a status of complete and restart polling
|
240
|
+
__classPrivateFieldGet(this, _BridgeStatusController_restartPollingForIncompleteHistoryItems, "f").call(this);
|
241
|
+
}
|
242
|
+
}
|
243
|
+
exports.BridgeStatusController = BridgeStatusController;
|
244
|
+
_BridgeStatusController_pollingTokensByTxMetaId = new WeakMap(), _BridgeStatusController_clientId = new WeakMap(), _BridgeStatusController_fetchFn = new WeakMap(), _BridgeStatusController_restartPollingForIncompleteHistoryItems = new WeakMap(), _BridgeStatusController_fetchBridgeTxStatus = new WeakMap(), _BridgeStatusController_getSrcTxHash = new WeakMap(), _BridgeStatusController_updateSrcTxHash = new WeakMap(), _BridgeStatusController_wipeBridgeStatusByChainId = new WeakMap(), _BridgeStatusController_instances = new WeakSet(), _BridgeStatusController_getSelectedAccount = function _BridgeStatusController_getSelectedAccount() {
|
245
|
+
return this.messagingSystem.call('AccountsController:getSelectedAccount');
|
246
|
+
};
|
247
|
+
//# sourceMappingURL=bridge-status-controller.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"bridge-status-controller.cjs","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StateMetadata } from '@metamask/base-controller';\nimport type { BridgeClientId } from '@metamask/bridge-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport { numberToHex, type Hex } from '@metamask/utils';\n\nimport {\n BRIDGE_STATUS_CONTROLLER_NAME,\n DEFAULT_BRIDGE_STATUS_STATE,\n REFRESH_INTERVAL_MS,\n} from './constants';\nimport { StatusTypes, type BridgeStatusControllerMessenger } from './types';\nimport type {\n BridgeStatusControllerState,\n StartPollingForBridgeTxStatusArgsSerialized,\n BridgeStatusState,\n FetchFunction,\n} from './types';\nimport {\n fetchBridgeTxStatus,\n getStatusRequestWithSrcTxHash,\n} from './utils/bridge-status';\n\nconst metadata: StateMetadata<BridgeStatusControllerState> = {\n // We want to persist the bridge status state so that we can show the proper data for the Activity list\n // basically match the behavior of TransactionController\n bridgeStatusState: {\n persist: true,\n anonymous: false,\n },\n};\n\n/** The input to start polling for the {@link BridgeStatusController} */\ntype BridgeStatusPollingInput = FetchBridgeTxStatusArgs;\n\ntype SrcTxMetaId = string;\nexport type FetchBridgeTxStatusArgs = {\n bridgeTxMetaId: string;\n};\nexport class BridgeStatusController extends StaticIntervalPollingController<BridgeStatusPollingInput>()<\n typeof BRIDGE_STATUS_CONTROLLER_NAME,\n BridgeStatusControllerState,\n BridgeStatusControllerMessenger\n> {\n #pollingTokensByTxMetaId: Record<SrcTxMetaId, string> = {};\n\n readonly #clientId: BridgeClientId;\n\n readonly #fetchFn: FetchFunction;\n\n constructor({\n messenger,\n state,\n clientId,\n fetchFn,\n }: {\n messenger: BridgeStatusControllerMessenger;\n state?: { bridgeStatusState?: Partial<BridgeStatusState> };\n clientId: BridgeClientId;\n fetchFn: FetchFunction;\n }) {\n super({\n name: BRIDGE_STATUS_CONTROLLER_NAME,\n metadata,\n messenger,\n // Restore the persisted state\n state: {\n ...state,\n bridgeStatusState: {\n ...DEFAULT_BRIDGE_STATUS_STATE,\n ...state?.bridgeStatusState,\n },\n },\n });\n\n this.#clientId = clientId;\n this.#fetchFn = fetchFn;\n\n // Register action handlers\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:startPollingForBridgeTxStatus`,\n this.startPollingForBridgeTxStatus.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:wipeBridgeStatus`,\n this.wipeBridgeStatus.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:resetState`,\n this.resetState.bind(this),\n );\n\n // Set interval\n this.setIntervalLength(REFRESH_INTERVAL_MS);\n\n // If you close the extension, but keep the browser open, the polling continues\n // If you close the browser, the polling stops\n // Check for historyItems that do not have a status of complete and restart polling\n this.#restartPollingForIncompleteHistoryItems();\n }\n\n resetState = () => {\n this.update((state) => {\n state.bridgeStatusState = {\n ...DEFAULT_BRIDGE_STATUS_STATE,\n };\n });\n };\n\n wipeBridgeStatus = ({\n address,\n ignoreNetwork,\n }: {\n address: string;\n ignoreNetwork: boolean;\n }) => {\n // Wipe all networks for this address\n if (ignoreNetwork) {\n this.update((state) => {\n state.bridgeStatusState = {\n ...DEFAULT_BRIDGE_STATUS_STATE,\n };\n });\n } else {\n const { selectedNetworkClientId } = this.messagingSystem.call(\n 'NetworkController:getState',\n );\n const selectedNetworkClient = this.messagingSystem.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n const selectedChainId = selectedNetworkClient.configuration.chainId;\n\n this.#wipeBridgeStatusByChainId(address, selectedChainId);\n }\n };\n\n readonly #restartPollingForIncompleteHistoryItems = () => {\n // Check for historyItems that do not have a status of complete and restart polling\n const { bridgeStatusState } = this.state;\n const historyItems = Object.values(bridgeStatusState.txHistory);\n const incompleteHistoryItems = historyItems\n .filter(\n (historyItem) =>\n historyItem.status.status === StatusTypes.PENDING ||\n historyItem.status.status === StatusTypes.UNKNOWN,\n )\n .filter((historyItem) => {\n // Check if we are already polling this tx, if so, skip restarting polling for that\n const srcTxMetaId = historyItem.txMetaId;\n const pollingToken = this.#pollingTokensByTxMetaId[srcTxMetaId];\n return !pollingToken;\n });\n\n incompleteHistoryItems.forEach((historyItem) => {\n const bridgeTxMetaId = historyItem.txMetaId;\n\n // We manually call startPolling() here rather than go through startPollingForBridgeTxStatus()\n // because we don't want to overwrite the existing historyItem in state\n this.#pollingTokensByTxMetaId[bridgeTxMetaId] = this.startPolling({\n bridgeTxMetaId,\n });\n });\n };\n\n startPollingForBridgeTxStatus = (\n startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized,\n ) => {\n const {\n bridgeTxMeta,\n statusRequest,\n quoteResponse,\n startTime,\n slippagePercentage,\n initialDestAssetBalance,\n targetContractAddress,\n } = startPollingForBridgeTxStatusArgs;\n const { address: account } = this.#getSelectedAccount();\n\n // Write all non-status fields to state so we can reference the quote in Activity list without the Bridge API\n // We know it's in progress but not the exact status yet\n const txHistoryItem = {\n txMetaId: bridgeTxMeta.id,\n quote: quoteResponse.quote,\n startTime,\n estimatedProcessingTimeInSeconds:\n quoteResponse.estimatedProcessingTimeInSeconds,\n slippagePercentage,\n pricingData: {\n amountSent: quoteResponse.sentAmount.amount,\n amountSentInUsd: quoteResponse.sentAmount.usd ?? undefined,\n quotedGasInUsd: quoteResponse.gasFee.usd ?? undefined,\n quotedReturnInUsd: quoteResponse.toTokenAmount.usd ?? undefined,\n },\n initialDestAssetBalance,\n targetContractAddress,\n account,\n status: {\n // We always have a PENDING status when we start polling for a tx, don't need the Bridge API for that\n // Also we know the bare minimum fields for status at this point in time\n status: StatusTypes.PENDING,\n srcChain: {\n chainId: statusRequest.srcChainId,\n txHash: statusRequest.srcTxHash,\n },\n },\n hasApprovalTx: Boolean(quoteResponse.approval),\n };\n this.update((state) => {\n // Use the txMeta.id as the key so we can reference the txMeta in TransactionController\n state.bridgeStatusState.txHistory[bridgeTxMeta.id] = txHistoryItem;\n });\n\n this.#pollingTokensByTxMetaId[bridgeTxMeta.id] = this.startPolling({\n bridgeTxMetaId: bridgeTxMeta.id,\n });\n };\n\n // This will be called after you call this.startPolling()\n // The args passed in are the args you passed in to startPolling()\n _executePoll = async (pollingInput: BridgeStatusPollingInput) => {\n await this.#fetchBridgeTxStatus(pollingInput);\n };\n\n #getSelectedAccount() {\n return this.messagingSystem.call('AccountsController:getSelectedAccount');\n }\n\n readonly #fetchBridgeTxStatus = async ({\n bridgeTxMetaId,\n }: FetchBridgeTxStatusArgs) => {\n const { bridgeStatusState } = this.state;\n\n try {\n // We try here because we receive 500 errors from Bridge API if we try to fetch immediately after submitting the source tx\n // Oddly mostly happens on Optimism, never on Arbitrum. By the 2nd fetch, the Bridge API responds properly.\n // Also srcTxHash may not be available immediately for STX, so we don't want to fetch in those cases\n const historyItem = bridgeStatusState.txHistory[bridgeTxMetaId];\n const srcTxHash = this.#getSrcTxHash(bridgeTxMetaId);\n if (!srcTxHash) {\n return;\n }\n\n this.#updateSrcTxHash(bridgeTxMetaId, srcTxHash);\n\n const statusRequest = getStatusRequestWithSrcTxHash(\n historyItem.quote,\n srcTxHash,\n );\n const status = await fetchBridgeTxStatus(\n statusRequest,\n this.#clientId,\n this.#fetchFn,\n );\n const newBridgeHistoryItem = {\n ...historyItem,\n status,\n completionTime:\n status.status === StatusTypes.COMPLETE ||\n status.status === StatusTypes.FAILED\n ? Date.now()\n : undefined, // TODO make this more accurate by looking up dest txHash block time\n };\n\n // No need to purge these on network change or account change, TransactionController does not purge either.\n // TODO In theory we can skip checking status if it's not the current account/network\n // we need to keep track of the account that this is associated with as well so that we don't show it in Activity list for other accounts\n // First stab at this will not stop polling when you are on a different account\n this.update((state) => {\n state.bridgeStatusState.txHistory[bridgeTxMetaId] =\n newBridgeHistoryItem;\n });\n\n const pollingToken = this.#pollingTokensByTxMetaId[bridgeTxMetaId];\n\n if (\n (status.status === StatusTypes.COMPLETE ||\n status.status === StatusTypes.FAILED) &&\n pollingToken\n ) {\n this.stopPollingByPollingToken(pollingToken);\n\n if (status.status === StatusTypes.COMPLETE) {\n this.messagingSystem.publish(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionComplete`,\n { bridgeHistoryItem: newBridgeHistoryItem },\n );\n }\n if (status.status === StatusTypes.FAILED) {\n this.messagingSystem.publish(\n `${BRIDGE_STATUS_CONTROLLER_NAME}:bridgeTransactionFailed`,\n { bridgeHistoryItem: newBridgeHistoryItem },\n );\n }\n }\n } catch (e) {\n console.log('Failed to fetch bridge tx status', e);\n }\n };\n\n readonly #getSrcTxHash = (bridgeTxMetaId: string): string | undefined => {\n const { bridgeStatusState } = this.state;\n // Prefer the srcTxHash from bridgeStatusState so we don't have to l ook up in TransactionController\n // But it is possible to have bridgeHistoryItem in state without the srcTxHash yet when it is an STX\n const srcTxHash =\n bridgeStatusState.txHistory[bridgeTxMetaId].status.srcChain.txHash;\n\n if (srcTxHash) {\n return srcTxHash;\n }\n\n // Look up in TransactionController if txMeta has been updated with the srcTxHash\n const txControllerState = this.messagingSystem.call(\n 'TransactionController:getState',\n );\n const txMeta = txControllerState.transactions.find(\n (tx) => tx.id === bridgeTxMetaId,\n );\n return txMeta?.hash;\n };\n\n readonly #updateSrcTxHash = (bridgeTxMetaId: string, srcTxHash: string) => {\n const { bridgeStatusState } = this.state;\n if (bridgeStatusState.txHistory[bridgeTxMetaId].status.srcChain.txHash) {\n return;\n }\n\n this.update((state) => {\n state.bridgeStatusState.txHistory[bridgeTxMetaId].status.srcChain.txHash =\n srcTxHash;\n });\n };\n\n // Wipes the bridge status for the given address and chainId\n // Will match only source chainId to the selectedChainId\n readonly #wipeBridgeStatusByChainId = (\n address: string,\n selectedChainId: Hex,\n ) => {\n const sourceTxMetaIdsToDelete = Object.keys(\n this.state.bridgeStatusState.txHistory,\n ).filter((txMetaId) => {\n const bridgeHistoryItem =\n this.state.bridgeStatusState.txHistory[txMetaId];\n\n const hexSourceChainId = numberToHex(bridgeHistoryItem.quote.srcChainId);\n\n return (\n bridgeHistoryItem.account === address &&\n hexSourceChainId === selectedChainId\n );\n });\n\n sourceTxMetaIdsToDelete.forEach((sourceTxMetaId) => {\n const pollingToken = this.#pollingTokensByTxMetaId[sourceTxMetaId];\n\n if (pollingToken) {\n this.stopPollingByPollingToken(\n this.#pollingTokensByTxMetaId[sourceTxMetaId],\n );\n }\n });\n\n this.update((state) => {\n state.bridgeStatusState.txHistory = sourceTxMetaIdsToDelete.reduce(\n (acc, sourceTxMetaId) => {\n delete acc[sourceTxMetaId];\n return acc;\n },\n state.bridgeStatusState.txHistory,\n );\n });\n };\n}\n"]}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import type { BridgeClientId } from "@metamask/bridge-controller";
|
2
|
+
import { BRIDGE_STATUS_CONTROLLER_NAME } from "./constants.cjs";
|
3
|
+
import { type BridgeStatusControllerMessenger } from "./types.cjs";
|
4
|
+
import type { BridgeStatusControllerState, StartPollingForBridgeTxStatusArgsSerialized, BridgeStatusState, FetchFunction } from "./types.cjs";
|
5
|
+
/** The input to start polling for the {@link BridgeStatusController} */
|
6
|
+
type BridgeStatusPollingInput = FetchBridgeTxStatusArgs;
|
7
|
+
export type FetchBridgeTxStatusArgs = {
|
8
|
+
bridgeTxMetaId: string;
|
9
|
+
};
|
10
|
+
declare const BridgeStatusController_base: (abstract new (...args: any[]) => {
|
11
|
+
readonly "__#13@#intervalIds": Record<string, NodeJS.Timeout>;
|
12
|
+
"__#13@#intervalLength": number | undefined;
|
13
|
+
setIntervalLength(intervalLength: number): void;
|
14
|
+
getIntervalLength(): number | undefined;
|
15
|
+
_startPolling(input: FetchBridgeTxStatusArgs): void;
|
16
|
+
_stopPollingByPollingTokenSetId(key: string): void;
|
17
|
+
readonly "__#3@#pollingTokenSets": Map<string, Set<string>>;
|
18
|
+
"__#3@#callbacks": Map<string, Set<(input: FetchBridgeTxStatusArgs) => void>>;
|
19
|
+
_executePoll(input: FetchBridgeTxStatusArgs): Promise<void>;
|
20
|
+
startPolling(input: FetchBridgeTxStatusArgs): string;
|
21
|
+
stopAllPolling(): void;
|
22
|
+
stopPollingByPollingToken(pollingToken: string): void;
|
23
|
+
onPollingComplete(input: FetchBridgeTxStatusArgs, callback: (input: FetchBridgeTxStatusArgs) => void): void;
|
24
|
+
}) & typeof import("@metamask/base-controller").BaseController;
|
25
|
+
export declare class BridgeStatusController extends BridgeStatusController_base<typeof BRIDGE_STATUS_CONTROLLER_NAME, BridgeStatusControllerState, BridgeStatusControllerMessenger> {
|
26
|
+
#private;
|
27
|
+
constructor({ messenger, state, clientId, fetchFn, }: {
|
28
|
+
messenger: BridgeStatusControllerMessenger;
|
29
|
+
state?: {
|
30
|
+
bridgeStatusState?: Partial<BridgeStatusState>;
|
31
|
+
};
|
32
|
+
clientId: BridgeClientId;
|
33
|
+
fetchFn: FetchFunction;
|
34
|
+
});
|
35
|
+
resetState: () => void;
|
36
|
+
wipeBridgeStatus: ({ address, ignoreNetwork, }: {
|
37
|
+
address: string;
|
38
|
+
ignoreNetwork: boolean;
|
39
|
+
}) => void;
|
40
|
+
startPollingForBridgeTxStatus: (startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized) => void;
|
41
|
+
_executePoll: (pollingInput: BridgeStatusPollingInput) => Promise<void>;
|
42
|
+
}
|
43
|
+
export {};
|
44
|
+
//# sourceMappingURL=bridge-status-controller.d.cts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"bridge-status-controller.d.cts","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,oCAAoC;AAIlE,OAAO,EACL,6BAA6B,EAG9B,wBAAoB;AACrB,OAAO,EAAe,KAAK,+BAA+B,EAAE,oBAAgB;AAC5E,OAAO,KAAK,EACV,2BAA2B,EAC3B,2CAA2C,EAC3C,iBAAiB,EACjB,aAAa,EACd,oBAAgB;AAejB,wEAAwE;AACxE,KAAK,wBAAwB,GAAG,uBAAuB,CAAC;AAGxD,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;;;;;;;;;;;;;AACF,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,6BAA6B,EACpC,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAOa,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,GACR,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE;YAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;SAAE,CAAC;QAC3D,QAAQ,EAAE,cAAc,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC;KACxB;IAyCD,UAAU,aAMR;IAEF,gBAAgB;iBAIL,MAAM;uBACA,OAAO;eAqBtB;IA8BF,6BAA6B,sCACQ,2CAA2C,UAkD9E;IAIF,YAAY,iBAAwB,wBAAwB,mBAE1D;CAuJH"}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import type { BridgeClientId } from "@metamask/bridge-controller";
|
2
|
+
import { BRIDGE_STATUS_CONTROLLER_NAME } from "./constants.mjs";
|
3
|
+
import { type BridgeStatusControllerMessenger } from "./types.mjs";
|
4
|
+
import type { BridgeStatusControllerState, StartPollingForBridgeTxStatusArgsSerialized, BridgeStatusState, FetchFunction } from "./types.mjs";
|
5
|
+
/** The input to start polling for the {@link BridgeStatusController} */
|
6
|
+
type BridgeStatusPollingInput = FetchBridgeTxStatusArgs;
|
7
|
+
export type FetchBridgeTxStatusArgs = {
|
8
|
+
bridgeTxMetaId: string;
|
9
|
+
};
|
10
|
+
declare const BridgeStatusController_base: (abstract new (...args: any[]) => {
|
11
|
+
readonly "__#13@#intervalIds": Record<string, NodeJS.Timeout>;
|
12
|
+
"__#13@#intervalLength": number | undefined;
|
13
|
+
setIntervalLength(intervalLength: number): void;
|
14
|
+
getIntervalLength(): number | undefined;
|
15
|
+
_startPolling(input: FetchBridgeTxStatusArgs): void;
|
16
|
+
_stopPollingByPollingTokenSetId(key: string): void;
|
17
|
+
readonly "__#3@#pollingTokenSets": Map<string, Set<string>>;
|
18
|
+
"__#3@#callbacks": Map<string, Set<(input: FetchBridgeTxStatusArgs) => void>>;
|
19
|
+
_executePoll(input: FetchBridgeTxStatusArgs): Promise<void>;
|
20
|
+
startPolling(input: FetchBridgeTxStatusArgs): string;
|
21
|
+
stopAllPolling(): void;
|
22
|
+
stopPollingByPollingToken(pollingToken: string): void;
|
23
|
+
onPollingComplete(input: FetchBridgeTxStatusArgs, callback: (input: FetchBridgeTxStatusArgs) => void): void;
|
24
|
+
}) & typeof import("@metamask/base-controller").BaseController;
|
25
|
+
export declare class BridgeStatusController extends BridgeStatusController_base<typeof BRIDGE_STATUS_CONTROLLER_NAME, BridgeStatusControllerState, BridgeStatusControllerMessenger> {
|
26
|
+
#private;
|
27
|
+
constructor({ messenger, state, clientId, fetchFn, }: {
|
28
|
+
messenger: BridgeStatusControllerMessenger;
|
29
|
+
state?: {
|
30
|
+
bridgeStatusState?: Partial<BridgeStatusState>;
|
31
|
+
};
|
32
|
+
clientId: BridgeClientId;
|
33
|
+
fetchFn: FetchFunction;
|
34
|
+
});
|
35
|
+
resetState: () => void;
|
36
|
+
wipeBridgeStatus: ({ address, ignoreNetwork, }: {
|
37
|
+
address: string;
|
38
|
+
ignoreNetwork: boolean;
|
39
|
+
}) => void;
|
40
|
+
startPollingForBridgeTxStatus: (startPollingForBridgeTxStatusArgs: StartPollingForBridgeTxStatusArgsSerialized) => void;
|
41
|
+
_executePoll: (pollingInput: BridgeStatusPollingInput) => Promise<void>;
|
42
|
+
}
|
43
|
+
export {};
|
44
|
+
//# sourceMappingURL=bridge-status-controller.d.mts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"bridge-status-controller.d.mts","sourceRoot":"","sources":["../src/bridge-status-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,oCAAoC;AAIlE,OAAO,EACL,6BAA6B,EAG9B,wBAAoB;AACrB,OAAO,EAAe,KAAK,+BAA+B,EAAE,oBAAgB;AAC5E,OAAO,KAAK,EACV,2BAA2B,EAC3B,2CAA2C,EAC3C,iBAAiB,EACjB,aAAa,EACd,oBAAgB;AAejB,wEAAwE;AACxE,KAAK,wBAAwB,GAAG,uBAAuB,CAAC;AAGxD,MAAM,MAAM,uBAAuB,GAAG;IACpC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;;;;;;;;;;;;;;;;AACF,qBAAa,sBAAuB,SAAQ,4BAC1C,OAAO,6BAA6B,EACpC,2BAA2B,EAC3B,+BAA+B,CAChC;;gBAOa,EACV,SAAS,EACT,KAAK,EACL,QAAQ,EACR,OAAO,GACR,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,KAAK,CAAC,EAAE;YAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;SAAE,CAAC;QAC3D,QAAQ,EAAE,cAAc,CAAC;QACzB,OAAO,EAAE,aAAa,CAAC;KACxB;IAyCD,UAAU,aAMR;IAEF,gBAAgB;iBAIL,MAAM;uBACA,OAAO;eAqBtB;IA8BF,6BAA6B,sCACQ,2CAA2C,UAkD9E;IAIF,YAAY,iBAAwB,wBAAwB,mBAE1D;CAuJH"}
|