@@ -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,15 @@ 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
+ */
36
+ const getSeenKey = evidence => {
37
+ const { txHash, chainId } = evidence ;
38
+ return /** @type {SeenTxKey } */ ( JSON . stringify ( [ txHash , chainId ] ) ) ;
39
+ } ;
40
+
32
41
/**
33
42
* The `StatusManager` keeps track of Pending and Seen Transactions
34
43
* via {@link TxStatus} states, aiding in coordination between the `Advancer`
@@ -45,6 +54,25 @@ export const prepareStatusManager = zone => {
45
54
valueShape : M . arrayOf ( PendingTxShape ) ,
46
55
} ) ;
47
56
57
+ /** @type {SetStore<SeenTxKey> } */
58
+ const seenTxs = zone . setStore ( 'SeenTxs' , {
59
+ keyShape : M . string ( ) ,
60
+ } ) ;
61
+
62
+ /**
63
+ * Ensures that `txHash+chainId` has not been processed
64
+ * and adds `txHash+chainId` to `seenTxs` set.
65
+ *
66
+ * @param {CctpTxEvidence } evidence
67
+ */
68
+ const assertNotSeen = evidence => {
69
+ const seenKey = getSeenKey ( evidence ) ;
70
+ if ( seenTxs . has ( seenKey ) ) {
71
+ throw makeError ( `Transaction already seen: ${ q ( seenKey ) } ` ) ;
72
+ }
73
+ seenTxs . add ( seenKey ) ;
74
+ } ;
75
+
48
76
return zone . exo (
49
77
'Fast USDC Status Manager' ,
50
78
M . interface ( 'StatusManagerI' , {
@@ -60,6 +88,7 @@ export const prepareStatusManager = zone => {
60
88
* @param {CctpTxEvidence } evidence
61
89
*/
62
90
advance ( evidence ) {
91
+ assertNotSeen ( evidence ) ;
63
92
const key = getPendingTxKey ( evidence ) ;
64
93
const entry = { ...evidence , status : TxStatus . Advanced } ;
65
94
@@ -76,6 +105,7 @@ export const prepareStatusManager = zone => {
76
105
* @param {CctpTxEvidence } evidence
77
106
*/
78
107
observe ( evidence ) {
108
+ assertNotSeen ( evidence ) ;
79
109
const key = getPendingTxKey ( evidence ) ;
80
110
const entry = { ...evidence , status : TxStatus . Observed } ;
81
111
0 commit comments