@metamask/transaction-controller 62.6.0 → 62.8.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 (60) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/dist/TransactionController.cjs +34 -75
  3. package/dist/TransactionController.cjs.map +1 -1
  4. package/dist/TransactionController.d.cts +12 -13
  5. package/dist/TransactionController.d.cts.map +1 -1
  6. package/dist/TransactionController.d.mts +12 -13
  7. package/dist/TransactionController.d.mts.map +1 -1
  8. package/dist/TransactionController.mjs +34 -75
  9. package/dist/TransactionController.mjs.map +1 -1
  10. package/dist/helpers/PendingTransactionTracker.cjs +39 -26
  11. package/dist/helpers/PendingTransactionTracker.cjs.map +1 -1
  12. package/dist/helpers/PendingTransactionTracker.d.cts.map +1 -1
  13. package/dist/helpers/PendingTransactionTracker.d.mts.map +1 -1
  14. package/dist/helpers/PendingTransactionTracker.mjs +40 -27
  15. package/dist/helpers/PendingTransactionTracker.mjs.map +1 -1
  16. package/dist/index.cjs +1 -4
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +0 -1
  19. package/dist/index.d.cts.map +1 -1
  20. package/dist/index.d.mts +0 -1
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +0 -1
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/types.cjs.map +1 -1
  25. package/dist/types.d.cts +32 -5
  26. package/dist/types.d.cts.map +1 -1
  27. package/dist/types.d.mts +32 -5
  28. package/dist/types.d.mts.map +1 -1
  29. package/dist/types.mjs.map +1 -1
  30. package/dist/utils/batch.cjs +2 -1
  31. package/dist/utils/batch.cjs.map +1 -1
  32. package/dist/utils/batch.d.cts +1 -0
  33. package/dist/utils/batch.d.cts.map +1 -1
  34. package/dist/utils/batch.d.mts +1 -0
  35. package/dist/utils/batch.d.mts.map +1 -1
  36. package/dist/utils/batch.mjs +2 -1
  37. package/dist/utils/batch.mjs.map +1 -1
  38. package/dist/utils/feature-flags.cjs +4 -1
  39. package/dist/utils/feature-flags.cjs.map +1 -1
  40. package/dist/utils/feature-flags.d.cts +5 -0
  41. package/dist/utils/feature-flags.d.cts.map +1 -1
  42. package/dist/utils/feature-flags.d.mts +5 -0
  43. package/dist/utils/feature-flags.d.mts.map +1 -1
  44. package/dist/utils/feature-flags.mjs +4 -1
  45. package/dist/utils/feature-flags.mjs.map +1 -1
  46. package/dist/utils/nonce.cjs +10 -6
  47. package/dist/utils/nonce.cjs.map +1 -1
  48. package/dist/utils/nonce.d.cts.map +1 -1
  49. package/dist/utils/nonce.d.mts.map +1 -1
  50. package/dist/utils/nonce.mjs +10 -6
  51. package/dist/utils/nonce.mjs.map +1 -1
  52. package/package.json +5 -5
  53. package/dist/utils/history.cjs +0 -164
  54. package/dist/utils/history.cjs.map +0 -1
  55. package/dist/utils/history.d.cts +0 -29
  56. package/dist/utils/history.d.cts.map +0 -1
  57. package/dist/utils/history.d.mts +0 -29
  58. package/dist/utils/history.d.mts.map +0 -1
  59. package/dist/utils/history.mjs +0 -164
  60. package/dist/utils/history.mjs.map +0 -1
@@ -1,164 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.updateTransactionHistory = exports.addInitialHistorySnapshot = exports.DISPLAYED_TRANSACTION_HISTORY_PATHS = exports.MAX_TRANSACTION_HISTORY_LENGTH = void 0;
7
- const fast_json_patch_1 = __importDefault(require("fast-json-patch"));
8
- const lodash_1 = require("lodash");
9
- /**
10
- * The maximum allowed length of the `transaction.history` property.
11
- */
12
- exports.MAX_TRANSACTION_HISTORY_LENGTH = 100;
13
- /**
14
- * A list of trarnsaction history paths that may be used for display. These entries will not be
15
- * compressed.
16
- */
17
- exports.DISPLAYED_TRANSACTION_HISTORY_PATHS = [
18
- '/status',
19
- '/txParams/gasPrice',
20
- '/txParams/gas',
21
- '/estimatedBaseFee',
22
- '/blockTimestamp',
23
- ];
24
- /**
25
- * Build a new version of the provided transaction with an initial history
26
- * entry, which is just a snapshot of the transaction.
27
- *
28
- * @param transactionMeta - TransactionMeta to add initial history snapshot to.
29
- * @returns A copy of `transactionMeta` with a new `history` property.
30
- */
31
- function addInitialHistorySnapshot(transactionMeta) {
32
- const snapshot = snapshotFromTransactionMeta(transactionMeta);
33
- return (0, lodash_1.merge)({}, transactionMeta, { history: [snapshot] });
34
- }
35
- exports.addInitialHistorySnapshot = addInitialHistorySnapshot;
36
- /**
37
- * Builds a new version of the transaction with a new history entry if
38
- * it has a `history` property, or just returns the transaction.
39
- *
40
- * @param transactionMeta - TransactionMeta to add history entry to.
41
- * @param note - Note to add to history entry.
42
- * @returns A copy of `transactionMeta` with a new `history` entry if it has an
43
- * existing non-empty `history` array.
44
- */
45
- function updateTransactionHistory(transactionMeta, note) {
46
- if (!transactionMeta.history) {
47
- return transactionMeta;
48
- }
49
- const currentState = snapshotFromTransactionMeta(transactionMeta);
50
- const previousState = replayHistory(transactionMeta.history);
51
- const newHistoryEntry = generateHistoryEntry(previousState, currentState, note);
52
- if (newHistoryEntry.length === 0) {
53
- return transactionMeta;
54
- }
55
- // Casts required here because this list has two separate types of entries:
56
- // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first
57
- // entry, but TypeScript loses that type information when `slice` is called for some reason.
58
- let updatedHistory = [
59
- ...transactionMeta.history,
60
- newHistoryEntry,
61
- ];
62
- if (updatedHistory.length > exports.MAX_TRANSACTION_HISTORY_LENGTH) {
63
- updatedHistory = compressTransactionHistory(updatedHistory);
64
- }
65
- return (0, lodash_1.merge)({}, transactionMeta, {
66
- history: updatedHistory,
67
- });
68
- }
69
- exports.updateTransactionHistory = updateTransactionHistory;
70
- /**
71
- * Compress the transaction history, if it is possible to do so without compressing entries used
72
- * for display. History entries are merged together to make room for a single new entry.
73
- *
74
- * @param transactionHistory - The transaction history to compress.
75
- * @returns A compressed transaction history.
76
- */
77
- function compressTransactionHistory(transactionHistory) {
78
- const initialEntry = transactionHistory[0];
79
- // Casts required here because this list has two separate types of entries:
80
- // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first
81
- // entry, but TypeScript loses that type information when `slice` is called for some reason.
82
- const historyEntries = transactionHistory.slice(1);
83
- const firstNonDisplayedEntryIndex = historyEntries.findIndex((historyEntry) => {
84
- return !historyEntry.some(({ path }) => exports.DISPLAYED_TRANSACTION_HISTORY_PATHS.includes(path));
85
- });
86
- // If no non-displayed entry is found, let history exceed max size.
87
- // TODO: Move data used for display to another property, so that we can more reliably limit
88
- // history size or remove it altogether.
89
- if (firstNonDisplayedEntryIndex === -1) {
90
- return transactionHistory;
91
- }
92
- // If a non-displayed entry is found that we can remove, merge it with another entry.
93
- // The entry we're merging with might be a "displayed" entry, but that's OK, merging more changes
94
- // in does not break our display logic.
95
- const mergeTargetEntryIndex =
96
- // Merge with previous entry if there is no next entry.
97
- // We default to merging with next because the next entry might also be non-displayed, so it
98
- // might be removed in a future trim, saving more space.
99
- firstNonDisplayedEntryIndex === historyEntries.length - 1
100
- ? firstNonDisplayedEntryIndex - 1
101
- : firstNonDisplayedEntryIndex + 1;
102
- const firstIndexToMerge = Math.min(firstNonDisplayedEntryIndex, mergeTargetEntryIndex);
103
- const firstEntryToMerge = historyEntries[firstIndexToMerge];
104
- const secondEntryToMerge = historyEntries[firstIndexToMerge + 1];
105
- const beforeMergeState = replayHistory([
106
- initialEntry,
107
- ...historyEntries.slice(0, firstIndexToMerge),
108
- ]);
109
- const afterMergeState = replayHistory([
110
- beforeMergeState,
111
- firstEntryToMerge,
112
- secondEntryToMerge,
113
- ]);
114
- const mergedHistoryEntry = generateHistoryEntry(beforeMergeState, afterMergeState, `${String(firstEntryToMerge[0].note)}, ${String(secondEntryToMerge[0].note)}`);
115
- historyEntries.splice(firstIndexToMerge, 2, mergedHistoryEntry);
116
- return [initialEntry, ...historyEntries];
117
- }
118
- /**
119
- * Generates a history entry from the previous and new transaction metadata.
120
- *
121
- * @param previousState - The previous transaction metadata.
122
- * @param currentState - The new transaction metadata.
123
- * @param note - A note for the transaction metada update.
124
- * @returns An array of history operation.
125
- */
126
- function generateHistoryEntry(
127
- // TODO: Replace `any` with type
128
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
- previousState, currentState, note) {
130
- const historyOperationsEntry = fast_json_patch_1.default.compare(previousState, currentState);
131
- // Add a note to the first operation, since it breaks if we append it to the entry
132
- if (historyOperationsEntry[0]) {
133
- if (note) {
134
- historyOperationsEntry[0].note = note;
135
- }
136
- historyOperationsEntry[0].timestamp = Date.now();
137
- }
138
- return historyOperationsEntry;
139
- }
140
- /**
141
- * Recovers previous transactionMeta from passed history array.
142
- *
143
- * @param transactionHistory - The transaction metadata to replay.
144
- * @returns The transaction metadata.
145
- */
146
- function replayHistory(transactionHistory) {
147
- const shortHistory = (0, lodash_1.cloneDeep)(transactionHistory);
148
- return shortHistory.reduce(
149
- // TODO: Replace `any` with type
150
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
151
- (val, entry) => fast_json_patch_1.default.applyPatch(val, entry).newDocument);
152
- }
153
- /**
154
- * Clone the transaction meta data without the history property.
155
- *
156
- * @param transactionMeta - The transaction metadata to snapshot.
157
- * @returns A deep clone of transaction metadata without history property.
158
- */
159
- function snapshotFromTransactionMeta(transactionMeta) {
160
- const snapshot = { ...transactionMeta };
161
- delete snapshot.history;
162
- return (0, lodash_1.cloneDeep)(snapshot);
163
- }
164
- //# sourceMappingURL=history.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"history.cjs","sourceRoot":"","sources":["../../src/utils/history.ts"],"names":[],"mappings":"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","sourcesContent":["import jsonDiffer from 'fast-json-patch';\nimport { cloneDeep, merge } from 'lodash';\n\nimport type {\n TransactionHistory,\n TransactionHistoryEntry,\n TransactionMeta,\n} from '../types';\n\n/**\n * The maximum allowed length of the `transaction.history` property.\n */\nexport const MAX_TRANSACTION_HISTORY_LENGTH = 100;\n\n/**\n * A list of trarnsaction history paths that may be used for display. These entries will not be\n * compressed.\n */\nexport const DISPLAYED_TRANSACTION_HISTORY_PATHS = [\n '/status',\n '/txParams/gasPrice',\n '/txParams/gas',\n '/estimatedBaseFee',\n '/blockTimestamp',\n];\n\n/**\n * Build a new version of the provided transaction with an initial history\n * entry, which is just a snapshot of the transaction.\n *\n * @param transactionMeta - TransactionMeta to add initial history snapshot to.\n * @returns A copy of `transactionMeta` with a new `history` property.\n */\nexport function addInitialHistorySnapshot(\n transactionMeta: TransactionMeta,\n): TransactionMeta {\n const snapshot = snapshotFromTransactionMeta(transactionMeta);\n return merge({}, transactionMeta, { history: [snapshot] });\n}\n\n/**\n * Builds a new version of the transaction with a new history entry if\n * it has a `history` property, or just returns the transaction.\n *\n * @param transactionMeta - TransactionMeta to add history entry to.\n * @param note - Note to add to history entry.\n * @returns A copy of `transactionMeta` with a new `history` entry if it has an\n * existing non-empty `history` array.\n */\nexport function updateTransactionHistory(\n transactionMeta: TransactionMeta,\n note: string,\n): TransactionMeta {\n if (!transactionMeta.history) {\n return transactionMeta;\n }\n\n const currentState = snapshotFromTransactionMeta(transactionMeta);\n const previousState = replayHistory(transactionMeta.history);\n const newHistoryEntry = generateHistoryEntry(\n previousState,\n currentState,\n note,\n );\n\n if (newHistoryEntry.length === 0) {\n return transactionMeta;\n }\n\n // Casts required here because this list has two separate types of entries:\n // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first\n // entry, but TypeScript loses that type information when `slice` is called for some reason.\n let updatedHistory = [\n ...transactionMeta.history,\n newHistoryEntry,\n ] as TransactionHistory;\n\n if (updatedHistory.length > MAX_TRANSACTION_HISTORY_LENGTH) {\n updatedHistory = compressTransactionHistory(updatedHistory);\n }\n\n return merge({}, transactionMeta, {\n history: updatedHistory,\n });\n}\n\n/**\n * Compress the transaction history, if it is possible to do so without compressing entries used\n * for display. History entries are merged together to make room for a single new entry.\n *\n * @param transactionHistory - The transaction history to compress.\n * @returns A compressed transaction history.\n */\nfunction compressTransactionHistory(\n transactionHistory: TransactionHistory,\n): TransactionHistory {\n const initialEntry = transactionHistory[0];\n // Casts required here because this list has two separate types of entries:\n // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first\n // entry, but TypeScript loses that type information when `slice` is called for some reason.\n const historyEntries = transactionHistory.slice(\n 1,\n ) as TransactionHistoryEntry[];\n\n const firstNonDisplayedEntryIndex = historyEntries.findIndex(\n (historyEntry) => {\n return !historyEntry.some(({ path }) =>\n DISPLAYED_TRANSACTION_HISTORY_PATHS.includes(path),\n );\n },\n );\n\n // If no non-displayed entry is found, let history exceed max size.\n // TODO: Move data used for display to another property, so that we can more reliably limit\n // history size or remove it altogether.\n if (firstNonDisplayedEntryIndex === -1) {\n return transactionHistory;\n }\n\n // If a non-displayed entry is found that we can remove, merge it with another entry.\n // The entry we're merging with might be a \"displayed\" entry, but that's OK, merging more changes\n // in does not break our display logic.\n const mergeTargetEntryIndex =\n // Merge with previous entry if there is no next entry.\n // We default to merging with next because the next entry might also be non-displayed, so it\n // might be removed in a future trim, saving more space.\n firstNonDisplayedEntryIndex === historyEntries.length - 1\n ? firstNonDisplayedEntryIndex - 1\n : firstNonDisplayedEntryIndex + 1;\n const firstIndexToMerge = Math.min(\n firstNonDisplayedEntryIndex,\n mergeTargetEntryIndex,\n );\n const firstEntryToMerge = historyEntries[firstIndexToMerge];\n const secondEntryToMerge = historyEntries[firstIndexToMerge + 1];\n\n const beforeMergeState = replayHistory([\n initialEntry,\n ...historyEntries.slice(0, firstIndexToMerge),\n ]);\n const afterMergeState = replayHistory([\n beforeMergeState,\n firstEntryToMerge,\n secondEntryToMerge,\n ]);\n const mergedHistoryEntry = generateHistoryEntry(\n beforeMergeState,\n afterMergeState,\n `${String(firstEntryToMerge[0].note)}, ${String(\n secondEntryToMerge[0].note,\n )}`,\n );\n\n historyEntries.splice(firstIndexToMerge, 2, mergedHistoryEntry);\n return [initialEntry, ...historyEntries];\n}\n\n/**\n * Generates a history entry from the previous and new transaction metadata.\n *\n * @param previousState - The previous transaction metadata.\n * @param currentState - The new transaction metadata.\n * @param note - A note for the transaction metada update.\n * @returns An array of history operation.\n */\nfunction generateHistoryEntry(\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n previousState: any,\n currentState: TransactionMeta,\n note: string,\n): TransactionHistoryEntry {\n const historyOperationsEntry = jsonDiffer.compare(\n previousState,\n currentState,\n ) as TransactionHistoryEntry;\n // Add a note to the first operation, since it breaks if we append it to the entry\n if (historyOperationsEntry[0]) {\n if (note) {\n historyOperationsEntry[0].note = note;\n }\n historyOperationsEntry[0].timestamp = Date.now();\n }\n return historyOperationsEntry;\n}\n\n/**\n * Recovers previous transactionMeta from passed history array.\n *\n * @param transactionHistory - The transaction metadata to replay.\n * @returns The transaction metadata.\n */\nfunction replayHistory(\n transactionHistory: TransactionHistory,\n): TransactionMeta {\n const shortHistory = cloneDeep(transactionHistory);\n return shortHistory.reduce(\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (val, entry: any) => jsonDiffer.applyPatch(val, entry).newDocument,\n ) as TransactionMeta;\n}\n\n/**\n * Clone the transaction meta data without the history property.\n *\n * @param transactionMeta - The transaction metadata to snapshot.\n * @returns A deep clone of transaction metadata without history property.\n */\nfunction snapshotFromTransactionMeta(\n transactionMeta: TransactionMeta,\n): TransactionMeta {\n const snapshot = { ...transactionMeta };\n delete snapshot.history;\n return cloneDeep(snapshot);\n}\n"]}
@@ -1,29 +0,0 @@
1
- import type { TransactionMeta } from "../types.cjs";
2
- /**
3
- * The maximum allowed length of the `transaction.history` property.
4
- */
5
- export declare const MAX_TRANSACTION_HISTORY_LENGTH = 100;
6
- /**
7
- * A list of trarnsaction history paths that may be used for display. These entries will not be
8
- * compressed.
9
- */
10
- export declare const DISPLAYED_TRANSACTION_HISTORY_PATHS: string[];
11
- /**
12
- * Build a new version of the provided transaction with an initial history
13
- * entry, which is just a snapshot of the transaction.
14
- *
15
- * @param transactionMeta - TransactionMeta to add initial history snapshot to.
16
- * @returns A copy of `transactionMeta` with a new `history` property.
17
- */
18
- export declare function addInitialHistorySnapshot(transactionMeta: TransactionMeta): TransactionMeta;
19
- /**
20
- * Builds a new version of the transaction with a new history entry if
21
- * it has a `history` property, or just returns the transaction.
22
- *
23
- * @param transactionMeta - TransactionMeta to add history entry to.
24
- * @param note - Note to add to history entry.
25
- * @returns A copy of `transactionMeta` with a new `history` entry if it has an
26
- * existing non-empty `history` array.
27
- */
28
- export declare function updateTransactionHistory(transactionMeta: TransactionMeta, note: string): TransactionMeta;
29
- //# sourceMappingURL=history.d.cts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"history.d.cts","sourceRoot":"","sources":["../../src/utils/history.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,eAAe,EAChB,qBAAiB;AAElB;;GAEG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,mCAAmC,UAM/C,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,eAAe,GAC/B,eAAe,CAGjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,MAAM,GACX,eAAe,CAgCjB"}
@@ -1,29 +0,0 @@
1
- import type { TransactionMeta } from "../types.mjs";
2
- /**
3
- * The maximum allowed length of the `transaction.history` property.
4
- */
5
- export declare const MAX_TRANSACTION_HISTORY_LENGTH = 100;
6
- /**
7
- * A list of trarnsaction history paths that may be used for display. These entries will not be
8
- * compressed.
9
- */
10
- export declare const DISPLAYED_TRANSACTION_HISTORY_PATHS: string[];
11
- /**
12
- * Build a new version of the provided transaction with an initial history
13
- * entry, which is just a snapshot of the transaction.
14
- *
15
- * @param transactionMeta - TransactionMeta to add initial history snapshot to.
16
- * @returns A copy of `transactionMeta` with a new `history` property.
17
- */
18
- export declare function addInitialHistorySnapshot(transactionMeta: TransactionMeta): TransactionMeta;
19
- /**
20
- * Builds a new version of the transaction with a new history entry if
21
- * it has a `history` property, or just returns the transaction.
22
- *
23
- * @param transactionMeta - TransactionMeta to add history entry to.
24
- * @param note - Note to add to history entry.
25
- * @returns A copy of `transactionMeta` with a new `history` entry if it has an
26
- * existing non-empty `history` array.
27
- */
28
- export declare function updateTransactionHistory(transactionMeta: TransactionMeta, note: string): TransactionMeta;
29
- //# sourceMappingURL=history.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"history.d.mts","sourceRoot":"","sources":["../../src/utils/history.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,eAAe,EAChB,qBAAiB;AAElB;;GAEG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,mCAAmC,UAM/C,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,eAAe,GAC/B,eAAe,CAGjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,MAAM,GACX,eAAe,CAgCjB"}
@@ -1,164 +0,0 @@
1
- function $importDefault(module) {
2
- if (module?.__esModule) {
3
- return module.default;
4
- }
5
- return module;
6
- }
7
- import $jsonDiffer from "fast-json-patch";
8
- const jsonDiffer = $importDefault($jsonDiffer);
9
- import $lodash from "lodash";
10
- const { cloneDeep, merge } = $lodash;
11
- /**
12
- * The maximum allowed length of the `transaction.history` property.
13
- */
14
- export const MAX_TRANSACTION_HISTORY_LENGTH = 100;
15
- /**
16
- * A list of trarnsaction history paths that may be used for display. These entries will not be
17
- * compressed.
18
- */
19
- export const DISPLAYED_TRANSACTION_HISTORY_PATHS = [
20
- '/status',
21
- '/txParams/gasPrice',
22
- '/txParams/gas',
23
- '/estimatedBaseFee',
24
- '/blockTimestamp',
25
- ];
26
- /**
27
- * Build a new version of the provided transaction with an initial history
28
- * entry, which is just a snapshot of the transaction.
29
- *
30
- * @param transactionMeta - TransactionMeta to add initial history snapshot to.
31
- * @returns A copy of `transactionMeta` with a new `history` property.
32
- */
33
- export function addInitialHistorySnapshot(transactionMeta) {
34
- const snapshot = snapshotFromTransactionMeta(transactionMeta);
35
- return merge({}, transactionMeta, { history: [snapshot] });
36
- }
37
- /**
38
- * Builds a new version of the transaction with a new history entry if
39
- * it has a `history` property, or just returns the transaction.
40
- *
41
- * @param transactionMeta - TransactionMeta to add history entry to.
42
- * @param note - Note to add to history entry.
43
- * @returns A copy of `transactionMeta` with a new `history` entry if it has an
44
- * existing non-empty `history` array.
45
- */
46
- export function updateTransactionHistory(transactionMeta, note) {
47
- if (!transactionMeta.history) {
48
- return transactionMeta;
49
- }
50
- const currentState = snapshotFromTransactionMeta(transactionMeta);
51
- const previousState = replayHistory(transactionMeta.history);
52
- const newHistoryEntry = generateHistoryEntry(previousState, currentState, note);
53
- if (newHistoryEntry.length === 0) {
54
- return transactionMeta;
55
- }
56
- // Casts required here because this list has two separate types of entries:
57
- // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first
58
- // entry, but TypeScript loses that type information when `slice` is called for some reason.
59
- let updatedHistory = [
60
- ...transactionMeta.history,
61
- newHistoryEntry,
62
- ];
63
- if (updatedHistory.length > MAX_TRANSACTION_HISTORY_LENGTH) {
64
- updatedHistory = compressTransactionHistory(updatedHistory);
65
- }
66
- return merge({}, transactionMeta, {
67
- history: updatedHistory,
68
- });
69
- }
70
- /**
71
- * Compress the transaction history, if it is possible to do so without compressing entries used
72
- * for display. History entries are merged together to make room for a single new entry.
73
- *
74
- * @param transactionHistory - The transaction history to compress.
75
- * @returns A compressed transaction history.
76
- */
77
- function compressTransactionHistory(transactionHistory) {
78
- const initialEntry = transactionHistory[0];
79
- // Casts required here because this list has two separate types of entries:
80
- // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first
81
- // entry, but TypeScript loses that type information when `slice` is called for some reason.
82
- const historyEntries = transactionHistory.slice(1);
83
- const firstNonDisplayedEntryIndex = historyEntries.findIndex((historyEntry) => {
84
- return !historyEntry.some(({ path }) => DISPLAYED_TRANSACTION_HISTORY_PATHS.includes(path));
85
- });
86
- // If no non-displayed entry is found, let history exceed max size.
87
- // TODO: Move data used for display to another property, so that we can more reliably limit
88
- // history size or remove it altogether.
89
- if (firstNonDisplayedEntryIndex === -1) {
90
- return transactionHistory;
91
- }
92
- // If a non-displayed entry is found that we can remove, merge it with another entry.
93
- // The entry we're merging with might be a "displayed" entry, but that's OK, merging more changes
94
- // in does not break our display logic.
95
- const mergeTargetEntryIndex =
96
- // Merge with previous entry if there is no next entry.
97
- // We default to merging with next because the next entry might also be non-displayed, so it
98
- // might be removed in a future trim, saving more space.
99
- firstNonDisplayedEntryIndex === historyEntries.length - 1
100
- ? firstNonDisplayedEntryIndex - 1
101
- : firstNonDisplayedEntryIndex + 1;
102
- const firstIndexToMerge = Math.min(firstNonDisplayedEntryIndex, mergeTargetEntryIndex);
103
- const firstEntryToMerge = historyEntries[firstIndexToMerge];
104
- const secondEntryToMerge = historyEntries[firstIndexToMerge + 1];
105
- const beforeMergeState = replayHistory([
106
- initialEntry,
107
- ...historyEntries.slice(0, firstIndexToMerge),
108
- ]);
109
- const afterMergeState = replayHistory([
110
- beforeMergeState,
111
- firstEntryToMerge,
112
- secondEntryToMerge,
113
- ]);
114
- const mergedHistoryEntry = generateHistoryEntry(beforeMergeState, afterMergeState, `${String(firstEntryToMerge[0].note)}, ${String(secondEntryToMerge[0].note)}`);
115
- historyEntries.splice(firstIndexToMerge, 2, mergedHistoryEntry);
116
- return [initialEntry, ...historyEntries];
117
- }
118
- /**
119
- * Generates a history entry from the previous and new transaction metadata.
120
- *
121
- * @param previousState - The previous transaction metadata.
122
- * @param currentState - The new transaction metadata.
123
- * @param note - A note for the transaction metada update.
124
- * @returns An array of history operation.
125
- */
126
- function generateHistoryEntry(
127
- // TODO: Replace `any` with type
128
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
- previousState, currentState, note) {
130
- const historyOperationsEntry = jsonDiffer.compare(previousState, currentState);
131
- // Add a note to the first operation, since it breaks if we append it to the entry
132
- if (historyOperationsEntry[0]) {
133
- if (note) {
134
- historyOperationsEntry[0].note = note;
135
- }
136
- historyOperationsEntry[0].timestamp = Date.now();
137
- }
138
- return historyOperationsEntry;
139
- }
140
- /**
141
- * Recovers previous transactionMeta from passed history array.
142
- *
143
- * @param transactionHistory - The transaction metadata to replay.
144
- * @returns The transaction metadata.
145
- */
146
- function replayHistory(transactionHistory) {
147
- const shortHistory = cloneDeep(transactionHistory);
148
- return shortHistory.reduce(
149
- // TODO: Replace `any` with type
150
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
151
- (val, entry) => jsonDiffer.applyPatch(val, entry).newDocument);
152
- }
153
- /**
154
- * Clone the transaction meta data without the history property.
155
- *
156
- * @param transactionMeta - The transaction metadata to snapshot.
157
- * @returns A deep clone of transaction metadata without history property.
158
- */
159
- function snapshotFromTransactionMeta(transactionMeta) {
160
- const snapshot = { ...transactionMeta };
161
- delete snapshot.history;
162
- return cloneDeep(snapshot);
163
- }
164
- //# sourceMappingURL=history.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"history.mjs","sourceRoot":"","sources":["../../src/utils/history.ts"],"names":[],"mappings":"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","sourcesContent":["import jsonDiffer from 'fast-json-patch';\nimport { cloneDeep, merge } from 'lodash';\n\nimport type {\n TransactionHistory,\n TransactionHistoryEntry,\n TransactionMeta,\n} from '../types';\n\n/**\n * The maximum allowed length of the `transaction.history` property.\n */\nexport const MAX_TRANSACTION_HISTORY_LENGTH = 100;\n\n/**\n * A list of trarnsaction history paths that may be used for display. These entries will not be\n * compressed.\n */\nexport const DISPLAYED_TRANSACTION_HISTORY_PATHS = [\n '/status',\n '/txParams/gasPrice',\n '/txParams/gas',\n '/estimatedBaseFee',\n '/blockTimestamp',\n];\n\n/**\n * Build a new version of the provided transaction with an initial history\n * entry, which is just a snapshot of the transaction.\n *\n * @param transactionMeta - TransactionMeta to add initial history snapshot to.\n * @returns A copy of `transactionMeta` with a new `history` property.\n */\nexport function addInitialHistorySnapshot(\n transactionMeta: TransactionMeta,\n): TransactionMeta {\n const snapshot = snapshotFromTransactionMeta(transactionMeta);\n return merge({}, transactionMeta, { history: [snapshot] });\n}\n\n/**\n * Builds a new version of the transaction with a new history entry if\n * it has a `history` property, or just returns the transaction.\n *\n * @param transactionMeta - TransactionMeta to add history entry to.\n * @param note - Note to add to history entry.\n * @returns A copy of `transactionMeta` with a new `history` entry if it has an\n * existing non-empty `history` array.\n */\nexport function updateTransactionHistory(\n transactionMeta: TransactionMeta,\n note: string,\n): TransactionMeta {\n if (!transactionMeta.history) {\n return transactionMeta;\n }\n\n const currentState = snapshotFromTransactionMeta(transactionMeta);\n const previousState = replayHistory(transactionMeta.history);\n const newHistoryEntry = generateHistoryEntry(\n previousState,\n currentState,\n note,\n );\n\n if (newHistoryEntry.length === 0) {\n return transactionMeta;\n }\n\n // Casts required here because this list has two separate types of entries:\n // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first\n // entry, but TypeScript loses that type information when `slice` is called for some reason.\n let updatedHistory = [\n ...transactionMeta.history,\n newHistoryEntry,\n ] as TransactionHistory;\n\n if (updatedHistory.length > MAX_TRANSACTION_HISTORY_LENGTH) {\n updatedHistory = compressTransactionHistory(updatedHistory);\n }\n\n return merge({}, transactionMeta, {\n history: updatedHistory,\n });\n}\n\n/**\n * Compress the transaction history, if it is possible to do so without compressing entries used\n * for display. History entries are merged together to make room for a single new entry.\n *\n * @param transactionHistory - The transaction history to compress.\n * @returns A compressed transaction history.\n */\nfunction compressTransactionHistory(\n transactionHistory: TransactionHistory,\n): TransactionHistory {\n const initialEntry = transactionHistory[0];\n // Casts required here because this list has two separate types of entries:\n // TransactionMeta and TransactionHistoryEntry. The only TransactionMeta is the first\n // entry, but TypeScript loses that type information when `slice` is called for some reason.\n const historyEntries = transactionHistory.slice(\n 1,\n ) as TransactionHistoryEntry[];\n\n const firstNonDisplayedEntryIndex = historyEntries.findIndex(\n (historyEntry) => {\n return !historyEntry.some(({ path }) =>\n DISPLAYED_TRANSACTION_HISTORY_PATHS.includes(path),\n );\n },\n );\n\n // If no non-displayed entry is found, let history exceed max size.\n // TODO: Move data used for display to another property, so that we can more reliably limit\n // history size or remove it altogether.\n if (firstNonDisplayedEntryIndex === -1) {\n return transactionHistory;\n }\n\n // If a non-displayed entry is found that we can remove, merge it with another entry.\n // The entry we're merging with might be a \"displayed\" entry, but that's OK, merging more changes\n // in does not break our display logic.\n const mergeTargetEntryIndex =\n // Merge with previous entry if there is no next entry.\n // We default to merging with next because the next entry might also be non-displayed, so it\n // might be removed in a future trim, saving more space.\n firstNonDisplayedEntryIndex === historyEntries.length - 1\n ? firstNonDisplayedEntryIndex - 1\n : firstNonDisplayedEntryIndex + 1;\n const firstIndexToMerge = Math.min(\n firstNonDisplayedEntryIndex,\n mergeTargetEntryIndex,\n );\n const firstEntryToMerge = historyEntries[firstIndexToMerge];\n const secondEntryToMerge = historyEntries[firstIndexToMerge + 1];\n\n const beforeMergeState = replayHistory([\n initialEntry,\n ...historyEntries.slice(0, firstIndexToMerge),\n ]);\n const afterMergeState = replayHistory([\n beforeMergeState,\n firstEntryToMerge,\n secondEntryToMerge,\n ]);\n const mergedHistoryEntry = generateHistoryEntry(\n beforeMergeState,\n afterMergeState,\n `${String(firstEntryToMerge[0].note)}, ${String(\n secondEntryToMerge[0].note,\n )}`,\n );\n\n historyEntries.splice(firstIndexToMerge, 2, mergedHistoryEntry);\n return [initialEntry, ...historyEntries];\n}\n\n/**\n * Generates a history entry from the previous and new transaction metadata.\n *\n * @param previousState - The previous transaction metadata.\n * @param currentState - The new transaction metadata.\n * @param note - A note for the transaction metada update.\n * @returns An array of history operation.\n */\nfunction generateHistoryEntry(\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n previousState: any,\n currentState: TransactionMeta,\n note: string,\n): TransactionHistoryEntry {\n const historyOperationsEntry = jsonDiffer.compare(\n previousState,\n currentState,\n ) as TransactionHistoryEntry;\n // Add a note to the first operation, since it breaks if we append it to the entry\n if (historyOperationsEntry[0]) {\n if (note) {\n historyOperationsEntry[0].note = note;\n }\n historyOperationsEntry[0].timestamp = Date.now();\n }\n return historyOperationsEntry;\n}\n\n/**\n * Recovers previous transactionMeta from passed history array.\n *\n * @param transactionHistory - The transaction metadata to replay.\n * @returns The transaction metadata.\n */\nfunction replayHistory(\n transactionHistory: TransactionHistory,\n): TransactionMeta {\n const shortHistory = cloneDeep(transactionHistory);\n return shortHistory.reduce(\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (val, entry: any) => jsonDiffer.applyPatch(val, entry).newDocument,\n ) as TransactionMeta;\n}\n\n/**\n * Clone the transaction meta data without the history property.\n *\n * @param transactionMeta - The transaction metadata to snapshot.\n * @returns A deep clone of transaction metadata without history property.\n */\nfunction snapshotFromTransactionMeta(\n transactionMeta: TransactionMeta,\n): TransactionMeta {\n const snapshot = { ...transactionMeta };\n delete snapshot.history;\n return cloneDeep(snapshot);\n}\n"]}