@hyperlane-xyz/rebalancer 2.0.0 → 3.1.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.
- package/dist/bridges/LiFiBridge.d.ts +67 -0
- package/dist/bridges/LiFiBridge.d.ts.map +1 -0
- package/dist/bridges/LiFiBridge.js +386 -0
- package/dist/bridges/LiFiBridge.js.map +1 -0
- package/dist/config/RebalancerConfig.d.ts +8 -2
- package/dist/config/RebalancerConfig.d.ts.map +1 -1
- package/dist/config/RebalancerConfig.js +9 -4
- package/dist/config/RebalancerConfig.js.map +1 -1
- package/dist/config/RebalancerConfig.test.js +135 -1
- package/dist/config/RebalancerConfig.test.js.map +1 -1
- package/dist/config/types.d.ts +1023 -304
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +113 -10
- package/dist/config/types.js.map +1 -1
- package/dist/core/InventoryRebalancer.d.ts +190 -0
- package/dist/core/InventoryRebalancer.d.ts.map +1 -0
- package/dist/core/InventoryRebalancer.js +892 -0
- package/dist/core/InventoryRebalancer.js.map +1 -0
- package/dist/core/InventoryRebalancer.test.d.ts +2 -0
- package/dist/core/InventoryRebalancer.test.d.ts.map +1 -0
- package/dist/core/InventoryRebalancer.test.js +1382 -0
- package/dist/core/InventoryRebalancer.test.js.map +1 -0
- package/dist/core/Rebalancer.d.ts +11 -4
- package/dist/core/Rebalancer.d.ts.map +1 -1
- package/dist/core/Rebalancer.js +92 -9
- package/dist/core/Rebalancer.js.map +1 -1
- package/dist/core/Rebalancer.test.js +82 -49
- package/dist/core/Rebalancer.test.js.map +1 -1
- package/dist/core/RebalancerOrchestrator.d.ts +30 -9
- package/dist/core/RebalancerOrchestrator.d.ts.map +1 -1
- package/dist/core/RebalancerOrchestrator.js +79 -71
- package/dist/core/RebalancerOrchestrator.js.map +1 -1
- package/dist/core/RebalancerOrchestrator.test.d.ts +2 -0
- package/dist/core/RebalancerOrchestrator.test.d.ts.map +1 -0
- package/dist/core/RebalancerOrchestrator.test.js +719 -0
- package/dist/core/RebalancerOrchestrator.test.js.map +1 -0
- package/dist/core/RebalancerService.d.ts +7 -3
- package/dist/core/RebalancerService.d.ts.map +1 -1
- package/dist/core/RebalancerService.js +44 -24
- package/dist/core/RebalancerService.js.map +1 -1
- package/dist/core/RebalancerService.test.js +74 -110
- package/dist/core/RebalancerService.test.js.map +1 -1
- package/dist/e2e/collateral-deficit.e2e-test.js +1 -3
- package/dist/e2e/collateral-deficit.e2e-test.js.map +1 -1
- package/dist/e2e/composite.e2e-test.js.map +1 -1
- package/dist/e2e/harness/BridgeSetup.d.ts +6 -0
- package/dist/e2e/harness/BridgeSetup.d.ts.map +1 -1
- package/dist/e2e/harness/BridgeSetup.js +10 -1
- package/dist/e2e/harness/BridgeSetup.js.map +1 -1
- package/dist/e2e/harness/ForkIndexer.d.ts.map +1 -1
- package/dist/e2e/harness/ForkIndexer.js +1 -0
- package/dist/e2e/harness/ForkIndexer.js.map +1 -1
- package/dist/e2e/harness/TestHelpers.d.ts.map +1 -1
- package/dist/e2e/harness/TestHelpers.js +1 -4
- package/dist/e2e/harness/TestHelpers.js.map +1 -1
- package/dist/e2e/harness/TestRebalancer.d.ts +1 -1
- package/dist/e2e/harness/TestRebalancer.d.ts.map +1 -1
- package/dist/e2e/harness/TestRebalancer.js +9 -9
- package/dist/e2e/harness/TestRebalancer.js.map +1 -1
- package/dist/e2e/minAmount.e2e-test.js +0 -1
- package/dist/e2e/minAmount.e2e-test.js.map +1 -1
- package/dist/e2e/weighted.e2e-test.js +0 -1
- package/dist/e2e/weighted.e2e-test.js.map +1 -1
- package/dist/factories/RebalancerContextFactory.d.ts +48 -6
- package/dist/factories/RebalancerContextFactory.d.ts.map +1 -1
- package/dist/factories/RebalancerContextFactory.js +171 -17
- package/dist/factories/RebalancerContextFactory.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/IExternalBridge.d.ts +101 -0
- package/dist/interfaces/IExternalBridge.d.ts.map +1 -0
- package/dist/interfaces/IExternalBridge.js +2 -0
- package/dist/interfaces/IExternalBridge.js.map +1 -0
- package/dist/interfaces/IMonitor.d.ts +1 -0
- package/dist/interfaces/IMonitor.d.ts.map +1 -1
- package/dist/interfaces/IRebalancer.d.ts +25 -25
- package/dist/interfaces/IRebalancer.d.ts.map +1 -1
- package/dist/interfaces/IStrategy.d.ts +36 -3
- package/dist/interfaces/IStrategy.d.ts.map +1 -1
- package/dist/interfaces/IStrategy.js +12 -1
- package/dist/interfaces/IStrategy.js.map +1 -1
- package/dist/metrics/PriceGetter.js +1 -1
- package/dist/metrics/PriceGetter.js.map +1 -1
- package/dist/metrics/scripts/metrics.d.ts +3 -3
- package/dist/monitor/Monitor.d.ts +12 -2
- package/dist/monitor/Monitor.d.ts.map +1 -1
- package/dist/monitor/Monitor.js +46 -1
- package/dist/monitor/Monitor.js.map +1 -1
- package/dist/service.js +40 -17
- package/dist/service.js.map +1 -1
- package/dist/strategy/BaseStrategy.d.ts +12 -6
- package/dist/strategy/BaseStrategy.d.ts.map +1 -1
- package/dist/strategy/BaseStrategy.js +56 -21
- package/dist/strategy/BaseStrategy.js.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.d.ts +1 -1
- package/dist/strategy/CollateralDeficitStrategy.d.ts.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.js +19 -11
- package/dist/strategy/CollateralDeficitStrategy.js.map +1 -1
- package/dist/strategy/CollateralDeficitStrategy.test.js +135 -2
- package/dist/strategy/CollateralDeficitStrategy.test.js.map +1 -1
- package/dist/strategy/CompositeStrategy.test.js +13 -0
- package/dist/strategy/CompositeStrategy.test.js.map +1 -1
- package/dist/strategy/MinAmountStrategy.test.js +4 -0
- package/dist/strategy/MinAmountStrategy.test.js.map +1 -1
- package/dist/strategy/StrategyFactory.d.ts +2 -1
- package/dist/strategy/StrategyFactory.d.ts.map +1 -1
- package/dist/strategy/StrategyFactory.js +24 -8
- package/dist/strategy/StrategyFactory.js.map +1 -1
- package/dist/strategy/WeightedStrategy.test.js +6 -0
- package/dist/strategy/WeightedStrategy.test.js.map +1 -1
- package/dist/test/helpers.d.ts +8 -7
- package/dist/test/helpers.d.ts.map +1 -1
- package/dist/test/helpers.js +23 -5
- package/dist/test/helpers.js.map +1 -1
- package/dist/test/lifiMocks.d.ts +51 -0
- package/dist/test/lifiMocks.d.ts.map +1 -0
- package/dist/test/lifiMocks.js +130 -0
- package/dist/test/lifiMocks.js.map +1 -0
- package/dist/tracking/ActionTracker.d.ts +34 -1
- package/dist/tracking/ActionTracker.d.ts.map +1 -1
- package/dist/tracking/ActionTracker.js +233 -26
- package/dist/tracking/ActionTracker.js.map +1 -1
- package/dist/tracking/ActionTracker.test.js +380 -19
- package/dist/tracking/ActionTracker.test.js.map +1 -1
- package/dist/tracking/IActionTracker.d.ts +48 -3
- package/dist/tracking/IActionTracker.d.ts.map +1 -1
- package/dist/tracking/InflightContextAdapter.d.ts.map +1 -1
- package/dist/tracking/InflightContextAdapter.js +24 -7
- package/dist/tracking/InflightContextAdapter.js.map +1 -1
- package/dist/tracking/InflightContextAdapter.test.js +7 -4
- package/dist/tracking/InflightContextAdapter.test.js.map +1 -1
- package/dist/tracking/types.d.ts +33 -2
- package/dist/tracking/types.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.d.ts +3 -1
- package/dist/utils/ExplorerClient.d.ts.map +1 -1
- package/dist/utils/ExplorerClient.js +16 -8
- package/dist/utils/ExplorerClient.js.map +1 -1
- package/dist/utils/bridgeUtils.d.ts +27 -4
- package/dist/utils/bridgeUtils.d.ts.map +1 -1
- package/dist/utils/bridgeUtils.js +38 -0
- package/dist/utils/bridgeUtils.js.map +1 -1
- package/dist/utils/bridgeUtils.test.js +9 -0
- package/dist/utils/bridgeUtils.test.js.map +1 -1
- package/dist/utils/gasEstimation.d.ts +65 -0
- package/dist/utils/gasEstimation.d.ts.map +1 -0
- package/dist/utils/gasEstimation.js +176 -0
- package/dist/utils/gasEstimation.js.map +1 -0
- package/dist/utils/tokenUtils.d.ts +9 -1
- package/dist/utils/tokenUtils.d.ts.map +1 -1
- package/dist/utils/tokenUtils.js +11 -0
- package/dist/utils/tokenUtils.js.map +1 -1
- package/package.json +9 -7
- package/src/bridges/LiFiBridge.ts +538 -0
- package/src/config/RebalancerConfig.test.ts +162 -0
- package/src/config/RebalancerConfig.ts +21 -3
- package/src/config/types.ts +147 -10
- package/src/core/InventoryRebalancer.test.ts +1721 -0
- package/src/core/InventoryRebalancer.ts +1265 -0
- package/src/core/Rebalancer.test.ts +84 -30
- package/src/core/Rebalancer.ts +144 -23
- package/src/core/RebalancerOrchestrator.test.ts +869 -0
- package/src/core/RebalancerOrchestrator.ts +146 -95
- package/src/core/RebalancerService.test.ts +86 -124
- package/src/core/RebalancerService.ts +67 -33
- package/src/e2e/collateral-deficit.e2e-test.ts +2 -4
- package/src/e2e/composite.e2e-test.ts +5 -5
- package/src/e2e/harness/BridgeSetup.ts +28 -1
- package/src/e2e/harness/ForkIndexer.ts +1 -0
- package/src/e2e/harness/TestHelpers.ts +1 -4
- package/src/e2e/harness/TestRebalancer.ts +10 -7
- package/src/e2e/minAmount.e2e-test.ts +1 -2
- package/src/e2e/weighted.e2e-test.ts +1 -2
- package/src/factories/RebalancerContextFactory.ts +294 -24
- package/src/index.ts +22 -5
- package/src/interfaces/IExternalBridge.ts +115 -0
- package/src/interfaces/IMonitor.ts +1 -0
- package/src/interfaces/IRebalancer.ts +45 -29
- package/src/interfaces/IStrategy.ts +50 -3
- package/src/metrics/PriceGetter.ts +1 -1
- package/src/monitor/Monitor.ts +81 -2
- package/src/service.ts +59 -18
- package/src/strategy/BaseStrategy.ts +77 -24
- package/src/strategy/CollateralDeficitStrategy.test.ts +181 -4
- package/src/strategy/CollateralDeficitStrategy.ts +42 -15
- package/src/strategy/CompositeStrategy.test.ts +13 -0
- package/src/strategy/MinAmountStrategy.test.ts +4 -0
- package/src/strategy/StrategyFactory.ts +33 -6
- package/src/strategy/WeightedStrategy.test.ts +6 -0
- package/src/test/helpers.ts +39 -14
- package/src/test/lifiMocks.ts +174 -0
- package/src/tracking/ActionTracker.test.ts +443 -19
- package/src/tracking/ActionTracker.ts +339 -28
- package/src/tracking/IActionTracker.ts +59 -3
- package/src/tracking/InflightContextAdapter.test.ts +7 -4
- package/src/tracking/InflightContextAdapter.ts +42 -9
- package/src/tracking/types.ts +45 -2
- package/src/utils/ExplorerClient.ts +27 -10
- package/src/utils/bridgeUtils.test.ts +9 -0
- package/src/utils/bridgeUtils.ts +75 -6
- package/src/utils/gasEstimation.ts +272 -0
- package/src/utils/tokenUtils.ts +12 -0
- package/dist/tracking/index.d.ts +0 -7
- package/dist/tracking/index.d.ts.map +0 -1
- package/dist/tracking/index.js +0 -6
- package/dist/tracking/index.js.map +0 -1
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -5
- package/dist/utils/index.js.map +0 -1
- package/src/tracking/index.ts +0 -36
- package/src/utils/index.ts +0 -4
|
@@ -5,6 +5,7 @@ import Sinon from 'sinon';
|
|
|
5
5
|
|
|
6
6
|
import { EthJsonRpcBlockParameterTag } from '@hyperlane-xyz/sdk';
|
|
7
7
|
|
|
8
|
+
import { DEFAULT_INTENT_TTL_MS } from '../config/types.js';
|
|
8
9
|
import type { ExplorerMessage } from '../utils/ExplorerClient.js';
|
|
9
10
|
|
|
10
11
|
import { ActionTracker, type ActionTrackerConfig } from './ActionTracker.js';
|
|
@@ -71,6 +72,7 @@ describe('ActionTracker', () => {
|
|
|
71
72
|
},
|
|
72
73
|
bridges: ['0xbridge1', '0xbridge2'],
|
|
73
74
|
rebalancerAddress: '0xrebalancer',
|
|
75
|
+
intentTTL: DEFAULT_INTENT_TTL_MS,
|
|
74
76
|
};
|
|
75
77
|
|
|
76
78
|
tracker = new ActionTracker(
|
|
@@ -99,6 +101,7 @@ describe('ActionTracker', () => {
|
|
|
99
101
|
is_delivered: false,
|
|
100
102
|
message_body:
|
|
101
103
|
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
104
|
+
send_occurred_at: null,
|
|
102
105
|
},
|
|
103
106
|
];
|
|
104
107
|
|
|
@@ -128,6 +131,102 @@ describe('ActionTracker', () => {
|
|
|
128
131
|
expect(actions[0].messageId).to.equal('0xmsg1');
|
|
129
132
|
});
|
|
130
133
|
|
|
134
|
+
it('should use send_occurred_at for createdAt when available', async () => {
|
|
135
|
+
const inflightMessages: ExplorerMessage[] = [
|
|
136
|
+
{
|
|
137
|
+
msg_id: '0xmsg1',
|
|
138
|
+
origin_domain_id: 1,
|
|
139
|
+
destination_domain_id: 2,
|
|
140
|
+
sender: '0xrouter1',
|
|
141
|
+
recipient: '0xrouter2',
|
|
142
|
+
origin_tx_hash: '0xtx1',
|
|
143
|
+
origin_tx_sender: '0xrebalancer',
|
|
144
|
+
origin_tx_recipient: '0xrouter1',
|
|
145
|
+
is_delivered: false,
|
|
146
|
+
message_body:
|
|
147
|
+
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
148
|
+
send_occurred_at: '2024-01-15T12:30:45',
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
explorerClient.getInflightRebalanceActions.resolves(inflightMessages);
|
|
153
|
+
explorerClient.getInflightUserTransfers.resolves([]);
|
|
154
|
+
mailboxStub.isDelivered.resolves(false);
|
|
155
|
+
|
|
156
|
+
await tracker.initialize();
|
|
157
|
+
|
|
158
|
+
const intents = await rebalanceIntentStore.getAll();
|
|
159
|
+
expect(intents).to.have.lengthOf(1);
|
|
160
|
+
// Hasura timestamps are UTC without 'Z'; recoverAction appends 'Z' before parsing
|
|
161
|
+
const expectedMs = new Date('2024-01-15T12:30:45Z').getTime();
|
|
162
|
+
expect(intents[0].createdAt).to.equal(expectedMs);
|
|
163
|
+
|
|
164
|
+
const actions = await rebalanceActionStore.getAll();
|
|
165
|
+
expect(actions[0].createdAt).to.equal(expectedMs);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should fall back to Date.now() when send_occurred_at is null', async () => {
|
|
169
|
+
const before = Date.now();
|
|
170
|
+
const inflightMessages: ExplorerMessage[] = [
|
|
171
|
+
{
|
|
172
|
+
msg_id: '0xmsg1',
|
|
173
|
+
origin_domain_id: 1,
|
|
174
|
+
destination_domain_id: 2,
|
|
175
|
+
sender: '0xrouter1',
|
|
176
|
+
recipient: '0xrouter2',
|
|
177
|
+
origin_tx_hash: '0xtx1',
|
|
178
|
+
origin_tx_sender: '0xrebalancer',
|
|
179
|
+
origin_tx_recipient: '0xrouter1',
|
|
180
|
+
is_delivered: false,
|
|
181
|
+
message_body:
|
|
182
|
+
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
183
|
+
send_occurred_at: null,
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
explorerClient.getInflightRebalanceActions.resolves(inflightMessages);
|
|
188
|
+
explorerClient.getInflightUserTransfers.resolves([]);
|
|
189
|
+
mailboxStub.isDelivered.resolves(false);
|
|
190
|
+
|
|
191
|
+
await tracker.initialize();
|
|
192
|
+
const after = Date.now();
|
|
193
|
+
|
|
194
|
+
const intents = await rebalanceIntentStore.getAll();
|
|
195
|
+
expect(intents[0].createdAt).to.be.at.least(before);
|
|
196
|
+
expect(intents[0].createdAt).to.be.at.most(after);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should skip action with invalid send_occurred_at timestamp', async () => {
|
|
200
|
+
const inflightMessages: ExplorerMessage[] = [
|
|
201
|
+
{
|
|
202
|
+
msg_id: '0xmsg1',
|
|
203
|
+
origin_domain_id: 1,
|
|
204
|
+
destination_domain_id: 2,
|
|
205
|
+
sender: '0xrouter1',
|
|
206
|
+
recipient: '0xrouter2',
|
|
207
|
+
origin_tx_hash: '0xtx1',
|
|
208
|
+
origin_tx_sender: '0xrebalancer',
|
|
209
|
+
origin_tx_recipient: '0xrouter1',
|
|
210
|
+
is_delivered: false,
|
|
211
|
+
message_body:
|
|
212
|
+
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
213
|
+
send_occurred_at: 'garbage',
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
explorerClient.getInflightRebalanceActions.resolves(inflightMessages);
|
|
218
|
+
explorerClient.getInflightUserTransfers.resolves([]);
|
|
219
|
+
mailboxStub.isDelivered.resolves(false);
|
|
220
|
+
|
|
221
|
+
await tracker.initialize();
|
|
222
|
+
|
|
223
|
+
// Invalid timestamp is caught by recoverAction's catch block, so the action is skipped
|
|
224
|
+
const intents = await rebalanceIntentStore.getAll();
|
|
225
|
+
expect(intents).to.have.lengthOf(0);
|
|
226
|
+
const actions = await rebalanceActionStore.getAll();
|
|
227
|
+
expect(actions).to.have.lengthOf(0);
|
|
228
|
+
});
|
|
229
|
+
|
|
131
230
|
it('should skip creating action if it already exists', async () => {
|
|
132
231
|
const inflightMessages: ExplorerMessage[] = [
|
|
133
232
|
{
|
|
@@ -142,12 +241,14 @@ describe('ActionTracker', () => {
|
|
|
142
241
|
is_delivered: false,
|
|
143
242
|
message_body:
|
|
144
243
|
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
244
|
+
send_occurred_at: null,
|
|
145
245
|
},
|
|
146
246
|
];
|
|
147
247
|
|
|
148
248
|
// Pre-create action
|
|
149
249
|
await rebalanceActionStore.save({
|
|
150
250
|
id: '0xmsg1',
|
|
251
|
+
type: 'rebalance_message',
|
|
151
252
|
status: 'in_progress',
|
|
152
253
|
intentId: 'existing-intent',
|
|
153
254
|
messageId: '0xmsg1',
|
|
@@ -188,6 +289,7 @@ describe('ActionTracker', () => {
|
|
|
188
289
|
is_delivered: false,
|
|
189
290
|
message_body:
|
|
190
291
|
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
292
|
+
send_occurred_at: null,
|
|
191
293
|
},
|
|
192
294
|
];
|
|
193
295
|
|
|
@@ -231,6 +333,7 @@ describe('ActionTracker', () => {
|
|
|
231
333
|
is_delivered: false,
|
|
232
334
|
message_body:
|
|
233
335
|
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
|
|
336
|
+
send_occurred_at: null,
|
|
234
337
|
},
|
|
235
338
|
];
|
|
236
339
|
|
|
@@ -269,18 +372,32 @@ describe('ActionTracker', () => {
|
|
|
269
372
|
|
|
270
373
|
describe('syncRebalanceIntents', () => {
|
|
271
374
|
it('should mark intents as complete when fully fulfilled', async () => {
|
|
375
|
+
// Intent derives completion from action states, so we need a complete action
|
|
272
376
|
const intent: RebalanceIntent = {
|
|
273
377
|
id: 'intent-1',
|
|
274
378
|
status: 'in_progress',
|
|
275
379
|
origin: 1,
|
|
276
380
|
destination: 2,
|
|
277
381
|
amount: 100n,
|
|
278
|
-
|
|
382
|
+
createdAt: Date.now(),
|
|
383
|
+
updatedAt: Date.now(),
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const action: RebalanceAction = {
|
|
387
|
+
id: 'action-1',
|
|
388
|
+
type: 'rebalance_message',
|
|
389
|
+
status: 'complete',
|
|
390
|
+
intentId: 'intent-1',
|
|
391
|
+
messageId: '0xmsg1',
|
|
392
|
+
origin: 1,
|
|
393
|
+
destination: 2,
|
|
394
|
+
amount: 100n,
|
|
279
395
|
createdAt: Date.now(),
|
|
280
396
|
updatedAt: Date.now(),
|
|
281
397
|
};
|
|
282
398
|
|
|
283
399
|
await rebalanceIntentStore.save(intent);
|
|
400
|
+
await rebalanceActionStore.save(action);
|
|
284
401
|
|
|
285
402
|
await tracker.syncRebalanceIntents();
|
|
286
403
|
|
|
@@ -289,17 +406,86 @@ describe('ActionTracker', () => {
|
|
|
289
406
|
});
|
|
290
407
|
|
|
291
408
|
it('should not mark intents as complete if not fully fulfilled', async () => {
|
|
409
|
+
// Intent with only partial completion via actions
|
|
410
|
+
const intent: RebalanceIntent = {
|
|
411
|
+
id: 'intent-1',
|
|
412
|
+
status: 'in_progress',
|
|
413
|
+
origin: 1,
|
|
414
|
+
destination: 2,
|
|
415
|
+
amount: 100n,
|
|
416
|
+
createdAt: Date.now(),
|
|
417
|
+
updatedAt: Date.now(),
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const action: RebalanceAction = {
|
|
421
|
+
id: 'action-1',
|
|
422
|
+
type: 'rebalance_message',
|
|
423
|
+
status: 'complete',
|
|
424
|
+
intentId: 'intent-1',
|
|
425
|
+
messageId: '0xmsg1',
|
|
426
|
+
origin: 1,
|
|
427
|
+
destination: 2,
|
|
428
|
+
amount: 50n, // Only partial
|
|
429
|
+
createdAt: Date.now(),
|
|
430
|
+
updatedAt: Date.now(),
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
await rebalanceIntentStore.save(intent);
|
|
434
|
+
await rebalanceActionStore.save(action);
|
|
435
|
+
|
|
436
|
+
await tracker.syncRebalanceIntents();
|
|
437
|
+
|
|
438
|
+
const updated = await rebalanceIntentStore.get('intent-1');
|
|
439
|
+
expect(updated?.status).to.equal('in_progress');
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it('should mark unfulfilled intents as failed when TTL exceeded', async () => {
|
|
292
443
|
const intent: RebalanceIntent = {
|
|
293
444
|
id: 'intent-1',
|
|
294
445
|
status: 'in_progress',
|
|
295
446
|
origin: 1,
|
|
296
447
|
destination: 2,
|
|
297
448
|
amount: 100n,
|
|
298
|
-
|
|
449
|
+
createdAt: Date.now() - DEFAULT_INTENT_TTL_MS - 1,
|
|
450
|
+
updatedAt: Date.now(),
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
const action: RebalanceAction = {
|
|
454
|
+
id: 'action-1',
|
|
455
|
+
type: 'rebalance_message',
|
|
456
|
+
status: 'in_progress',
|
|
457
|
+
intentId: 'intent-1',
|
|
458
|
+
messageId: '0xmsg1',
|
|
459
|
+
origin: 1,
|
|
460
|
+
destination: 2,
|
|
461
|
+
amount: 50n,
|
|
299
462
|
createdAt: Date.now(),
|
|
300
463
|
updatedAt: Date.now(),
|
|
301
464
|
};
|
|
302
465
|
|
|
466
|
+
await rebalanceIntentStore.save(intent);
|
|
467
|
+
await rebalanceActionStore.save(action);
|
|
468
|
+
|
|
469
|
+
await tracker.syncRebalanceIntents();
|
|
470
|
+
|
|
471
|
+
const updatedIntent = await rebalanceIntentStore.get('intent-1');
|
|
472
|
+
expect(updatedIntent?.status).to.equal('failed');
|
|
473
|
+
|
|
474
|
+
const updatedAction = await rebalanceActionStore.get('action-1');
|
|
475
|
+
expect(updatedAction?.status).to.equal('failed');
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('should not expire intents within TTL', async () => {
|
|
479
|
+
const intent: RebalanceIntent = {
|
|
480
|
+
id: 'intent-1',
|
|
481
|
+
status: 'in_progress',
|
|
482
|
+
origin: 1,
|
|
483
|
+
destination: 2,
|
|
484
|
+
amount: 100n,
|
|
485
|
+
createdAt: Date.now() - DEFAULT_INTENT_TTL_MS + 60_000,
|
|
486
|
+
updatedAt: Date.now(),
|
|
487
|
+
};
|
|
488
|
+
|
|
303
489
|
await rebalanceIntentStore.save(intent);
|
|
304
490
|
|
|
305
491
|
await tracker.syncRebalanceIntents();
|
|
@@ -317,13 +503,13 @@ describe('ActionTracker', () => {
|
|
|
317
503
|
origin: 1,
|
|
318
504
|
destination: 2,
|
|
319
505
|
amount: 100n,
|
|
320
|
-
fulfilledAmount: 0n,
|
|
321
506
|
createdAt: Date.now(),
|
|
322
507
|
updatedAt: Date.now(),
|
|
323
508
|
};
|
|
324
509
|
|
|
325
510
|
const action: RebalanceAction = {
|
|
326
511
|
id: 'action-1',
|
|
512
|
+
type: 'rebalance_message',
|
|
327
513
|
status: 'in_progress',
|
|
328
514
|
intentId: 'intent-1',
|
|
329
515
|
messageId: '0xmsg1',
|
|
@@ -345,15 +531,15 @@ describe('ActionTracker', () => {
|
|
|
345
531
|
const updatedAction = await rebalanceActionStore.get('action-1');
|
|
346
532
|
expect(updatedAction?.status).to.equal('complete');
|
|
347
533
|
|
|
348
|
-
// Intent should be
|
|
534
|
+
// Intent should be complete (derived from completed action amounts)
|
|
349
535
|
const updatedIntent = await rebalanceIntentStore.get('intent-1');
|
|
350
|
-
expect(updatedIntent?.fulfilledAmount).to.equal(100n);
|
|
351
536
|
expect(updatedIntent?.status).to.equal('complete');
|
|
352
537
|
});
|
|
353
538
|
|
|
354
539
|
it('should not mark actions as complete if not delivered', async () => {
|
|
355
540
|
const action: RebalanceAction = {
|
|
356
541
|
id: 'action-1',
|
|
542
|
+
type: 'rebalance_message',
|
|
357
543
|
status: 'in_progress',
|
|
358
544
|
intentId: 'intent-1',
|
|
359
545
|
messageId: '0xmsg1',
|
|
@@ -417,7 +603,6 @@ describe('ActionTracker', () => {
|
|
|
417
603
|
origin: 1,
|
|
418
604
|
destination: 2,
|
|
419
605
|
amount: 100n,
|
|
420
|
-
fulfilledAmount: 0n,
|
|
421
606
|
createdAt: Date.now(),
|
|
422
607
|
updatedAt: Date.now(),
|
|
423
608
|
});
|
|
@@ -428,7 +613,6 @@ describe('ActionTracker', () => {
|
|
|
428
613
|
origin: 2,
|
|
429
614
|
destination: 3,
|
|
430
615
|
amount: 200n,
|
|
431
|
-
fulfilledAmount: 50n,
|
|
432
616
|
createdAt: Date.now(),
|
|
433
617
|
updatedAt: Date.now(),
|
|
434
618
|
});
|
|
@@ -439,7 +623,6 @@ describe('ActionTracker', () => {
|
|
|
439
623
|
origin: 3,
|
|
440
624
|
destination: 1,
|
|
441
625
|
amount: 300n,
|
|
442
|
-
fulfilledAmount: 300n,
|
|
443
626
|
createdAt: Date.now(),
|
|
444
627
|
updatedAt: Date.now(),
|
|
445
628
|
});
|
|
@@ -452,6 +635,249 @@ describe('ActionTracker', () => {
|
|
|
452
635
|
});
|
|
453
636
|
});
|
|
454
637
|
|
|
638
|
+
describe('getPartiallyFulfilledInventoryIntents', () => {
|
|
639
|
+
it('returns not_started inventory intents', async () => {
|
|
640
|
+
// Create a not_started inventory intent (simulates failed execution before any action created)
|
|
641
|
+
await rebalanceIntentStore.save({
|
|
642
|
+
id: 'stuck-intent',
|
|
643
|
+
status: 'not_started',
|
|
644
|
+
origin: 1,
|
|
645
|
+
destination: 2,
|
|
646
|
+
amount: 1000000000000000000n, // 1 ETH
|
|
647
|
+
executionMethod: 'inventory',
|
|
648
|
+
createdAt: Date.now(),
|
|
649
|
+
updatedAt: Date.now(),
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
// Should be returned even though status is 'not_started'
|
|
653
|
+
const partialIntents =
|
|
654
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
655
|
+
|
|
656
|
+
expect(partialIntents).to.have.lengthOf(1);
|
|
657
|
+
expect(partialIntents[0].intent.id).to.equal('stuck-intent');
|
|
658
|
+
expect(partialIntents[0].completedAmount).to.equal(0n);
|
|
659
|
+
expect(partialIntents[0].remaining).to.equal(1000000000000000000n);
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
it('returns in_progress inventory intents with partial completion', async () => {
|
|
663
|
+
// Create an in_progress inventory intent with a completed action
|
|
664
|
+
await rebalanceIntentStore.save({
|
|
665
|
+
id: 'partial-intent',
|
|
666
|
+
status: 'in_progress',
|
|
667
|
+
origin: 1,
|
|
668
|
+
destination: 2,
|
|
669
|
+
amount: 1000000000000000000n, // 1 ETH
|
|
670
|
+
executionMethod: 'inventory',
|
|
671
|
+
createdAt: Date.now(),
|
|
672
|
+
updatedAt: Date.now(),
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
// Create a completed inventory_deposit action for partial amount
|
|
676
|
+
await rebalanceActionStore.save({
|
|
677
|
+
id: 'action-1',
|
|
678
|
+
type: 'inventory_deposit',
|
|
679
|
+
status: 'complete',
|
|
680
|
+
intentId: 'partial-intent',
|
|
681
|
+
origin: 1,
|
|
682
|
+
destination: 2,
|
|
683
|
+
amount: 400000000000000000n, // 0.4 ETH completed
|
|
684
|
+
createdAt: Date.now(),
|
|
685
|
+
updatedAt: Date.now(),
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
const partialIntents =
|
|
689
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
690
|
+
|
|
691
|
+
expect(partialIntents).to.have.lengthOf(1);
|
|
692
|
+
expect(partialIntents[0].intent.id).to.equal('partial-intent');
|
|
693
|
+
expect(partialIntents[0].completedAmount).to.equal(400000000000000000n);
|
|
694
|
+
expect(partialIntents[0].remaining).to.equal(600000000000000000n); // 0.6 ETH remaining
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
it('does not return non-inventory intents', async () => {
|
|
698
|
+
// Create a not_started intent without executionMethod: 'inventory'
|
|
699
|
+
await rebalanceIntentStore.save({
|
|
700
|
+
id: 'non-inventory-intent',
|
|
701
|
+
status: 'not_started',
|
|
702
|
+
origin: 1,
|
|
703
|
+
destination: 2,
|
|
704
|
+
amount: 1000000000000000000n,
|
|
705
|
+
// executionMethod is undefined - not an inventory intent
|
|
706
|
+
createdAt: Date.now(),
|
|
707
|
+
updatedAt: Date.now(),
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const partialIntents =
|
|
711
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
712
|
+
|
|
713
|
+
expect(partialIntents).to.have.lengthOf(0);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
it('returns intent with in-flight deposit and sets hasInflightDeposit flag', async () => {
|
|
717
|
+
// Setup: in_progress inventory intent (amount: 1 ETH = 1_000_000_000_000_000_000n)
|
|
718
|
+
await rebalanceIntentStore.save({
|
|
719
|
+
id: 'intent-with-inflight',
|
|
720
|
+
status: 'in_progress',
|
|
721
|
+
origin: 1,
|
|
722
|
+
destination: 2,
|
|
723
|
+
amount: 1000000000000000000n, // 1 ETH
|
|
724
|
+
executionMethod: 'inventory',
|
|
725
|
+
createdAt: Date.now(),
|
|
726
|
+
updatedAt: Date.now(),
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// Complete inventory_deposit action (amount: 400_000_000_000_000_000n = 0.4 ETH)
|
|
730
|
+
await rebalanceActionStore.save({
|
|
731
|
+
id: 'action-complete',
|
|
732
|
+
type: 'inventory_deposit',
|
|
733
|
+
status: 'complete',
|
|
734
|
+
intentId: 'intent-with-inflight',
|
|
735
|
+
origin: 1,
|
|
736
|
+
destination: 2,
|
|
737
|
+
amount: 400000000000000000n, // 0.4 ETH completed
|
|
738
|
+
createdAt: Date.now(),
|
|
739
|
+
updatedAt: Date.now(),
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
// In_progress inventory_deposit action (amount: 300_000_000_000_000_000n = 0.3 ETH)
|
|
743
|
+
await rebalanceActionStore.save({
|
|
744
|
+
id: 'action-inflight',
|
|
745
|
+
type: 'inventory_deposit',
|
|
746
|
+
status: 'in_progress',
|
|
747
|
+
intentId: 'intent-with-inflight',
|
|
748
|
+
origin: 1,
|
|
749
|
+
destination: 2,
|
|
750
|
+
amount: 300000000000000000n, // 0.3 ETH in-flight
|
|
751
|
+
createdAt: Date.now(),
|
|
752
|
+
updatedAt: Date.now(),
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
const partialIntents =
|
|
756
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
757
|
+
|
|
758
|
+
expect(partialIntents).to.have.lengthOf(1);
|
|
759
|
+
expect(partialIntents[0].hasInflightDeposit).to.be.true;
|
|
760
|
+
expect(partialIntents[0].completedAmount).to.equal(400000000000000000n);
|
|
761
|
+
expect(partialIntents[0].remaining).to.equal(300000000000000000n); // 1.0 - 0.4 - 0.3
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
it('returns intent without in-flight deposit with hasInflightDeposit false', async () => {
|
|
765
|
+
// Setup: in_progress inventory intent (amount: 1 ETH)
|
|
766
|
+
await rebalanceIntentStore.save({
|
|
767
|
+
id: 'intent-no-inflight',
|
|
768
|
+
status: 'in_progress',
|
|
769
|
+
origin: 1,
|
|
770
|
+
destination: 2,
|
|
771
|
+
amount: 1000000000000000000n, // 1 ETH
|
|
772
|
+
executionMethod: 'inventory',
|
|
773
|
+
createdAt: Date.now(),
|
|
774
|
+
updatedAt: Date.now(),
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
// Complete inventory_deposit action (amount: 0.4 ETH)
|
|
778
|
+
await rebalanceActionStore.save({
|
|
779
|
+
id: 'action-complete-only',
|
|
780
|
+
type: 'inventory_deposit',
|
|
781
|
+
status: 'complete',
|
|
782
|
+
intentId: 'intent-no-inflight',
|
|
783
|
+
origin: 1,
|
|
784
|
+
destination: 2,
|
|
785
|
+
amount: 400000000000000000n, // 0.4 ETH completed
|
|
786
|
+
createdAt: Date.now(),
|
|
787
|
+
updatedAt: Date.now(),
|
|
788
|
+
});
|
|
789
|
+
// NO in_progress inventory_deposit actions
|
|
790
|
+
|
|
791
|
+
const partialIntents =
|
|
792
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
793
|
+
|
|
794
|
+
expect(partialIntents).to.have.lengthOf(1);
|
|
795
|
+
expect(partialIntents[0].hasInflightDeposit).to.be.false;
|
|
796
|
+
expect(partialIntents[0].remaining).to.equal(600000000000000000n);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it('returns intent when remaining is 0n but has in-flight deposit', async () => {
|
|
800
|
+
// intent.amount = 1 ETH, completedAmount = 0.7 ETH, inflightAmount = 0.3 ETH → remaining = 0n
|
|
801
|
+
await rebalanceIntentStore.save({
|
|
802
|
+
id: 'intent-zero-remaining',
|
|
803
|
+
status: 'in_progress',
|
|
804
|
+
origin: 1,
|
|
805
|
+
destination: 2,
|
|
806
|
+
amount: 1000000000000000000n, // 1 ETH
|
|
807
|
+
executionMethod: 'inventory',
|
|
808
|
+
createdAt: Date.now(),
|
|
809
|
+
updatedAt: Date.now(),
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// 0.7 ETH already completed
|
|
813
|
+
await rebalanceActionStore.save({
|
|
814
|
+
id: 'action-complete-part',
|
|
815
|
+
type: 'inventory_deposit',
|
|
816
|
+
status: 'complete',
|
|
817
|
+
intentId: 'intent-zero-remaining',
|
|
818
|
+
origin: 1,
|
|
819
|
+
destination: 2,
|
|
820
|
+
amount: 700000000000000000n, // 0.7 ETH
|
|
821
|
+
createdAt: Date.now(),
|
|
822
|
+
updatedAt: Date.now(),
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
// 0.3 ETH in-flight — exactly fills the remaining gap
|
|
826
|
+
await rebalanceActionStore.save({
|
|
827
|
+
id: 'action-inflight-rest',
|
|
828
|
+
type: 'inventory_deposit',
|
|
829
|
+
status: 'in_progress',
|
|
830
|
+
intentId: 'intent-zero-remaining',
|
|
831
|
+
origin: 1,
|
|
832
|
+
destination: 2,
|
|
833
|
+
amount: 300000000000000000n, // 0.3 ETH in-flight
|
|
834
|
+
createdAt: Date.now(),
|
|
835
|
+
updatedAt: Date.now(),
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
const partialIntents =
|
|
839
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
840
|
+
|
|
841
|
+
expect(partialIntents).to.have.lengthOf(1);
|
|
842
|
+
expect(partialIntents[0].remaining).to.equal(0n);
|
|
843
|
+
expect(partialIntents[0].hasInflightDeposit).to.be.true;
|
|
844
|
+
expect(partialIntents[0].completedAmount).to.equal(700000000000000000n);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it('does not return fully completed intent with no in-flight deposits', async () => {
|
|
848
|
+
// intent.amount = 1 ETH, completedAmount = 1 ETH, inflightAmount = 0 → remaining = 0n, no inflight
|
|
849
|
+
await rebalanceIntentStore.save({
|
|
850
|
+
id: 'intent-fully-done',
|
|
851
|
+
status: 'in_progress',
|
|
852
|
+
origin: 1,
|
|
853
|
+
destination: 2,
|
|
854
|
+
amount: 1000000000000000000n, // 1 ETH
|
|
855
|
+
executionMethod: 'inventory',
|
|
856
|
+
createdAt: Date.now(),
|
|
857
|
+
updatedAt: Date.now(),
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
// Full amount completed
|
|
861
|
+
await rebalanceActionStore.save({
|
|
862
|
+
id: 'action-all-done',
|
|
863
|
+
type: 'inventory_deposit',
|
|
864
|
+
status: 'complete',
|
|
865
|
+
intentId: 'intent-fully-done',
|
|
866
|
+
origin: 1,
|
|
867
|
+
destination: 2,
|
|
868
|
+
amount: 1000000000000000000n, // 1 ETH — full amount
|
|
869
|
+
createdAt: Date.now(),
|
|
870
|
+
updatedAt: Date.now(),
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
const partialIntents =
|
|
874
|
+
await tracker.getPartiallyFulfilledInventoryIntents();
|
|
875
|
+
|
|
876
|
+
// remaining = 0n AND inflightAmount = 0n → should NOT be returned
|
|
877
|
+
expect(partialIntents).to.have.lengthOf(0);
|
|
878
|
+
});
|
|
879
|
+
});
|
|
880
|
+
|
|
455
881
|
describe('createRebalanceIntent', () => {
|
|
456
882
|
it('should create a new intent with status not_started', async () => {
|
|
457
883
|
const result = await tracker.createRebalanceIntent({
|
|
@@ -466,7 +892,6 @@ describe('ActionTracker', () => {
|
|
|
466
892
|
expect(result.origin).to.equal(1);
|
|
467
893
|
expect(result.destination).to.equal(2);
|
|
468
894
|
expect(result.amount).to.equal(100n);
|
|
469
|
-
expect(result.fulfilledAmount).to.equal(0n);
|
|
470
895
|
expect(result.priority).to.equal(1);
|
|
471
896
|
expect(result.strategyType).to.equal('MinAmountStrategy');
|
|
472
897
|
|
|
@@ -483,7 +908,6 @@ describe('ActionTracker', () => {
|
|
|
483
908
|
origin: 1,
|
|
484
909
|
destination: 2,
|
|
485
910
|
amount: 100n,
|
|
486
|
-
fulfilledAmount: 0n,
|
|
487
911
|
createdAt: Date.now(),
|
|
488
912
|
updatedAt: Date.now(),
|
|
489
913
|
};
|
|
@@ -491,6 +915,7 @@ describe('ActionTracker', () => {
|
|
|
491
915
|
await rebalanceIntentStore.save(intent);
|
|
492
916
|
|
|
493
917
|
const result = await tracker.createRebalanceAction({
|
|
918
|
+
type: 'rebalance_message',
|
|
494
919
|
intentId: 'intent-1',
|
|
495
920
|
origin: 1,
|
|
496
921
|
destination: 2,
|
|
@@ -514,7 +939,6 @@ describe('ActionTracker', () => {
|
|
|
514
939
|
origin: 1,
|
|
515
940
|
destination: 2,
|
|
516
941
|
amount: 100n,
|
|
517
|
-
fulfilledAmount: 50n,
|
|
518
942
|
createdAt: Date.now(),
|
|
519
943
|
updatedAt: Date.now(),
|
|
520
944
|
};
|
|
@@ -522,6 +946,7 @@ describe('ActionTracker', () => {
|
|
|
522
946
|
await rebalanceIntentStore.save(intent);
|
|
523
947
|
|
|
524
948
|
await tracker.createRebalanceAction({
|
|
949
|
+
type: 'rebalance_message',
|
|
525
950
|
intentId: 'intent-1',
|
|
526
951
|
origin: 1,
|
|
527
952
|
destination: 2,
|
|
@@ -532,25 +957,24 @@ describe('ActionTracker', () => {
|
|
|
532
957
|
|
|
533
958
|
const updatedIntent = await rebalanceIntentStore.get('intent-1');
|
|
534
959
|
expect(updatedIntent?.status).to.equal('in_progress');
|
|
535
|
-
expect(updatedIntent?.fulfilledAmount).to.equal(50n); // Should not change
|
|
536
960
|
});
|
|
537
961
|
});
|
|
538
962
|
|
|
539
963
|
describe('completeRebalanceAction', () => {
|
|
540
|
-
it('should mark action as complete and
|
|
964
|
+
it('should mark action as complete and mark parent intent complete if fully fulfilled', async () => {
|
|
541
965
|
const intent: RebalanceIntent = {
|
|
542
966
|
id: 'intent-1',
|
|
543
967
|
status: 'in_progress',
|
|
544
968
|
origin: 1,
|
|
545
969
|
destination: 2,
|
|
546
970
|
amount: 100n,
|
|
547
|
-
fulfilledAmount: 0n,
|
|
548
971
|
createdAt: Date.now(),
|
|
549
972
|
updatedAt: Date.now(),
|
|
550
973
|
};
|
|
551
974
|
|
|
552
975
|
const action: RebalanceAction = {
|
|
553
976
|
id: 'action-1',
|
|
977
|
+
type: 'rebalance_message',
|
|
554
978
|
status: 'in_progress',
|
|
555
979
|
intentId: 'intent-1',
|
|
556
980
|
messageId: '0xmsg1',
|
|
@@ -569,8 +993,8 @@ describe('ActionTracker', () => {
|
|
|
569
993
|
const updatedAction = await rebalanceActionStore.get('action-1');
|
|
570
994
|
expect(updatedAction?.status).to.equal('complete');
|
|
571
995
|
|
|
996
|
+
// Intent should be complete (derived from completed action amounts)
|
|
572
997
|
const updatedIntent = await rebalanceIntentStore.get('intent-1');
|
|
573
|
-
expect(updatedIntent?.fulfilledAmount).to.equal(100n);
|
|
574
998
|
expect(updatedIntent?.status).to.equal('complete');
|
|
575
999
|
});
|
|
576
1000
|
|
|
@@ -589,7 +1013,6 @@ describe('ActionTracker', () => {
|
|
|
589
1013
|
origin: 1,
|
|
590
1014
|
destination: 2,
|
|
591
1015
|
amount: 100n,
|
|
592
|
-
fulfilledAmount: 0n,
|
|
593
1016
|
createdAt: Date.now(),
|
|
594
1017
|
updatedAt: Date.now(),
|
|
595
1018
|
};
|
|
@@ -607,6 +1030,7 @@ describe('ActionTracker', () => {
|
|
|
607
1030
|
it('should mark action as failed', async () => {
|
|
608
1031
|
const action: RebalanceAction = {
|
|
609
1032
|
id: 'action-1',
|
|
1033
|
+
type: 'rebalance_message',
|
|
610
1034
|
status: 'in_progress',
|
|
611
1035
|
intentId: 'intent-1',
|
|
612
1036
|
messageId: '0xmsg1',
|
|
@@ -653,7 +1077,7 @@ describe('ActionTracker', () => {
|
|
|
653
1077
|
|
|
654
1078
|
const params = call.args[0];
|
|
655
1079
|
expect(params.routersByDomain).to.deep.equal(config.routersByDomain);
|
|
656
|
-
expect(params.
|
|
1080
|
+
expect(params.excludeTxSenders).to.deep.equal([config.rebalancerAddress]);
|
|
657
1081
|
});
|
|
658
1082
|
});
|
|
659
1083
|
|
|
@@ -692,13 +1116,13 @@ describe('ActionTracker', () => {
|
|
|
692
1116
|
origin: 1,
|
|
693
1117
|
destination: 2,
|
|
694
1118
|
amount: 100n,
|
|
695
|
-
fulfilledAmount: 0n,
|
|
696
1119
|
createdAt: Date.now(),
|
|
697
1120
|
updatedAt: Date.now(),
|
|
698
1121
|
};
|
|
699
1122
|
|
|
700
1123
|
const action: RebalanceAction = {
|
|
701
1124
|
id: 'action-1',
|
|
1125
|
+
type: 'rebalance_message',
|
|
702
1126
|
status: 'in_progress',
|
|
703
1127
|
intentId: 'intent-1',
|
|
704
1128
|
messageId: '0xmsg1',
|
|
@@ -806,7 +1230,6 @@ describe('ActionTracker', () => {
|
|
|
806
1230
|
origin: 1,
|
|
807
1231
|
destination: 2,
|
|
808
1232
|
amount: 100n,
|
|
809
|
-
fulfilledAmount: 0n,
|
|
810
1233
|
createdAt: Date.now(),
|
|
811
1234
|
updatedAt: Date.now(),
|
|
812
1235
|
};
|
|
@@ -814,6 +1237,7 @@ describe('ActionTracker', () => {
|
|
|
814
1237
|
const action: RebalanceAction = {
|
|
815
1238
|
id: 'action-1',
|
|
816
1239
|
status: 'in_progress',
|
|
1240
|
+
type: 'rebalance_message',
|
|
817
1241
|
intentId: 'intent-1',
|
|
818
1242
|
messageId: '0xmsg1',
|
|
819
1243
|
origin: 1,
|