@@ -6,9 +6,9 @@ import { CctpTxEvidenceShape, PendingTxShape } from '../typeGuards.js';
6
6
import { TxStatus } from '../constants.js' ;
7
7
8
8
/**
9
- * @import {MapStore} from '@agoric/store';
9
+ * @import {MapStore, SetStore } from '@agoric/store';
10
10
* @import {Zone} from '@agoric/zone';
11
- * @import {CctpTxEvidence, NobleAddress, PendingTxKey, PendingTx} from '../types.js';
11
+ * @import {CctpTxEvidence, NobleAddress, SeenTxKey, PendingTxKey, PendingTx} from '../types.js';
12
12
*/
13
13
14
14
/**
@@ -29,6 +29,16 @@ const getPendingTxKey = evidence => {
29
29
return toPendingTxKey ( forwardingAddress , amount ) ;
30
30
} ;
31
31
32
+ /**
33
+ * Get the key for the seenTxs SetStore
34
+ * @param {CctpTxEvidence } evidence
35
+ * @returns {SeenTxKey }
36
+ */
37
+ const getSeenKey = evidence => {
38
+ const { txHash, chainId } = evidence ;
39
+ return `${ txHash } +${ chainId } ` ;
40
+ } ;
41
+
32
42
/**
33
43
* The `StatusManager` keeps track of Pending and Seen Transactions
34
44
* via {@link TxStatus} states, aiding in coordination between the `Advancer`
@@ -45,6 +55,25 @@ export const prepareStatusManager = zone => {
45
55
valueShape : M . arrayOf ( PendingTxShape ) ,
46
56
} ) ;
47
57
58
+ /** @type {SetStore<SeenTxKey> } */
59
+ const seenTxs = zone . setStore ( 'SeenTxs' , {
60
+ keyShape : M . string ( ) ,
61
+ } ) ;
62
+
63
+ /**
64
+ * Ensures that `txHash+chainId` has not been processed
65
+ * and adds `txHash+chainId` to `seenTxs` set.
66
+ *
67
+ * @param {CctpTxEvidence } evidence
68
+ */
69
+ const assertNotSeen = evidence => {
70
+ const seenKey = getSeenKey ( evidence ) ;
71
+ if ( seenTxs . has ( seenKey ) ) {
72
+ throw makeError ( `Transaction already seen: ${ q ( seenKey ) } ` ) ;
73
+ }
74
+ seenTxs . add ( seenKey ) ;
75
+ } ;
76
+
48
77
return zone . exo (
49
78
'Fast USDC Status Manager' ,
50
79
M . interface ( 'StatusManagerI' , {
@@ -60,6 +89,7 @@ export const prepareStatusManager = zone => {
60
89
* @param {CctpTxEvidence } evidence
61
90
*/
62
91
advance ( evidence ) {
92
+ assertNotSeen ( evidence ) ;
63
93
const key = getPendingTxKey ( evidence ) ;
64
94
const entry = { ...evidence , status : TxStatus . Advanced } ;
65
95
@@ -76,6 +106,7 @@ export const prepareStatusManager = zone => {
76
106
* @param {CctpTxEvidence } evidence
77
107
*/
78
108
observe ( evidence ) {
109
+ assertNotSeen ( evidence ) ;
79
110
const key = getPendingTxKey ( evidence ) ;
80
111
const entry = { ...evidence , status : TxStatus . Observed } ;
81
112
0 commit comments