Skip to content

Commit 1e6c600

Browse files
Merge pull request #1389 from input-output-hk/fix/debounced-pending-requests
fix(wallet): tx not withdrawing all rewards
2 parents df77cab + 9c74668 commit 1e6c600

File tree

3 files changed

+52
-12
lines changed

3 files changed

+52
-12
lines changed

packages/e2e/src/util/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ export const normalizeTxBody = (body: Cardano.HydratedTxBody | Cardano.TxBody) =
8383
dehydratedTx.inputs = sortTxIn(dehydratedTx.inputs);
8484
dehydratedTx.collaterals = sortTxIn(dehydratedTx.collaterals);
8585
dehydratedTx.referenceInputs = sortTxIn(dehydratedTx.referenceInputs);
86+
if (dehydratedTx.withdrawals) {
87+
dehydratedTx.withdrawals = sortBy(dehydratedTx.withdrawals, ['stakeAddress']);
88+
}
8689

8790
return dehydratedTx;
8891
};

packages/wallet/src/services/ProviderTracker/ProviderStatusTracker.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import {
33
Observable,
44
combineLatest,
55
concat,
6+
debounce,
67
debounceTime,
78
distinctUntilChanged,
89
filter,
10+
interval,
911
map,
1012
mergeMap,
1113
of,
@@ -79,13 +81,15 @@ export const createProviderStatusTracker = (
7981
const relevantStats$ = getProviderSyncRelevantStats(dependencies).pipe(share());
8082
const isAnyRequestPending$ = new TrackerSubject<boolean>(
8183
relevantStats$.pipe(
82-
debounceTime(1), // resolved requests could trigger new requests
8384
map((allStats) =>
8485
allStats.some(
8586
({ numCalls, numFailures, numResponses, didLastRequestFail }) =>
8687
didLastRequestFail || numCalls > numResponses + numFailures
8788
)
8889
),
90+
// do not debounce if there are pending requests; in case of many requests, it will be debounced
91+
// for a long time, leaving the previous status unchanged
92+
debounce((isReqPending) => (isReqPending ? of(true) : interval(1))),
8993
distinctUntilChanged(),
9094
tap((isReqPending) => logger.debug(`${isReqPending ? 'Some' : 'No'} requests are pending`))
9195
)

packages/wallet/test/services/ProviderTracker/ProviderStatusTracker.test.ts

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,15 @@ describe('createProviderStatusTracker', () => {
8080
rewardsProvider = new TrackedRewardsProvider(mockRewardsProvider());
8181
});
8282

83+
// n - not pending
84+
// p - pending
8385
it('isAnyRequestPending$: true if there are any reqs in flight, false when all resolved', () => {
8486
createTestScheduler().run(({ cold, expectObservable }) => {
87+
const source = 'ab-c-d-e-f-g-h-i';
88+
const status = '-p--np--np------n';
8589
const getProviderSyncRelevantStats = jest
8690
.fn()
87-
.mockReturnValueOnce(cold<ProviderFnStats[]>('ab-c-d-e-f-g-h-i', providerFnStats));
91+
.mockReturnValueOnce(cold<ProviderFnStats[]>(source, providerFnStats));
8892
const tracker = createProviderStatusTracker(
8993
{
9094
assetProvider,
@@ -99,23 +103,52 @@ describe('createProviderStatusTracker', () => {
99103
{ getProviderSyncRelevantStats }
100104
);
101105
// debounced by 1
102-
expectObservable(tracker.isAnyRequestPending$).toBe('--b-c-d-e-f-----i', {
103-
b: true,
104-
c: false,
105-
d: true,
106-
e: false,
107-
f: true,
108-
i: false
106+
expectObservable(tracker.isAnyRequestPending$).toBe(status, {
107+
n: false,
108+
p: true
109109
});
110110
});
111111
});
112112

113-
// eslint-disable-next-line max-len
113+
it.each([
114+
{ descr: 'not-pending is debounced', expected: '---n|', source: 'aaa-|' },
115+
{ descr: 'pending are not debounced', expected: 'p--|', source: 'bbb|' },
116+
{ descr: 'not-pending are dropped because they were debounced, pending is emitted immediately', expected: '--p|', source: 'aab|' },
117+
{ descr: 'flipping pending status shows pending, then waits for the first not-pending debounce to expire', expected: 'p-----n|', source: 'bababa-|' }
118+
])('isAnyRequestPending$: %s', ({ descr, source, expected }) => {
119+
createTestScheduler().run(({ cold, expectObservable }) => {
120+
const getProviderSyncRelevantStats = jest
121+
.fn()
122+
.mockReturnValueOnce(cold<ProviderFnStats[]>(source, providerFnStats));
123+
124+
const tracker = createProviderStatusTracker(
125+
{
126+
assetProvider,
127+
chainHistoryProvider,
128+
logger: dummyLogger,
129+
networkInfoProvider,
130+
rewardsProvider,
131+
stakePoolProvider,
132+
utxoProvider
133+
},
134+
{ consideredOutOfSyncAfter: timeout },
135+
{ getProviderSyncRelevantStats }
136+
);
137+
138+
expectObservable(tracker.isAnyRequestPending$).toBe(expected, {
139+
n: false,
140+
p: true
141+
}, descr);
142+
});
143+
});
144+
114145
it('isSettled$: false on load, true when all requests are resolved, then reverse of isAnyRequestPending', async () => {
115146
createTestScheduler().run(({ cold, expectObservable }) => {
147+
const source = '-a-b-c-d-e-f-g-h-i';
148+
const settle = 'a---------ef------i';
116149
const getProviderSyncRelevantStats = jest
117150
.fn()
118-
.mockReturnValueOnce(cold<ProviderFnStats[]>('-a-b-c-d-e-f-g-h-i', providerFnStats));
151+
.mockReturnValueOnce(cold<ProviderFnStats[]>(source, providerFnStats));
119152
const tracker = createProviderStatusTracker(
120153
{
121154
assetProvider,
@@ -130,7 +163,7 @@ describe('createProviderStatusTracker', () => {
130163
{ getProviderSyncRelevantStats }
131164
);
132165
// debounced by 1
133-
expectObservable(tracker.isSettled$).toBe('a---------e-f-----i', {
166+
expectObservable(tracker.isSettled$).toBe(settle, {
134167
a: false,
135168
e: true,
136169
f: false,

0 commit comments

Comments
 (0)