Skip to content

Commit e452da3

Browse files
feat(wallet): input resolver now searches TX history if input cant be found in current UTXO set
1 parent fed893b commit e452da3

File tree

3 files changed

+81
-7
lines changed

3 files changed

+81
-7
lines changed

packages/wallet/src/global.d.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export {}
2+
3+
declare global {
4+
interface Array<T> {
5+
findLastIndex(
6+
predicate: (value: T, index: number, obj: T[]) => unknown,
7+
thisArg?: any
8+
): number;
9+
10+
findLast(
11+
predicate: (value: T, index: number, obj: T[]) => unknown,
12+
thisArg?: any
13+
): T | undefined;
14+
}
15+
}

packages/wallet/src/services/WalletUtil.ts

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface InputResolverContext {
1414
available$: Observable<Cardano.Utxo[]>;
1515
};
1616
transactions: {
17+
history$: Observable<Cardano.HydratedTx[]>;
1718
outgoing: {
1819
signed$: Observable<WitnessedTx[]>;
1920
};
@@ -30,6 +31,7 @@ export type WalletUtilContext = WalletOutputValidatorContext &
3031

3132
export const createInputResolver = ({ utxo, transactions }: InputResolverContext): Cardano.InputResolver => ({
3233
async resolveInput(input: Cardano.TxIn, options?: Cardano.ResolveOptions) {
34+
const txHistory = await firstValueFrom(transactions.history$);
3335
const utxoAvailable = await firstValueFrom(utxo.available$, { defaultValue: [] });
3436
const signedTransactions = await firstValueFrom(transactions.outgoing.signed$, { defaultValue: [] });
3537
const utxoFromSigned = signedTransactions.flatMap(({ tx: signedTx }, signedTxIndex) =>
@@ -63,6 +65,13 @@ export const createInputResolver = ({ utxo, transactions }: InputResolverContext
6365
return tx.body.outputs[input.index];
6466
}
6567
}
68+
69+
const historyTx = txHistory.findLast((entry) => entry.id === input.txId);
70+
71+
if (historyTx && historyTx.body.outputs.length > input.index) {
72+
return historyTx.body.outputs[input.index];
73+
}
74+
6675
return null;
6776
}
6877
});

packages/wallet/test/services/WalletUtil.test.ts

+57-7
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,45 @@ describe('WalletUtil', () => {
5555
]
5656
];
5757
const resolver = createInputResolver({
58-
transactions: { outgoing: { signed$: of() } },
58+
transactions: { history$: of([]), outgoing: { signed$: of() } },
59+
utxo: { available$: of(utxo) }
60+
});
61+
expect(
62+
await resolver.resolveInput({
63+
index: 0,
64+
txId: Cardano.TransactionId('0f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5')
65+
})
66+
).toEqual({
67+
address: 'addr_test1vr8nl4u0u6fmtfnawx2rxfz95dy7m46t6dhzdftp2uha87syeufdg',
68+
value: { coins: 50_000_000n }
69+
});
70+
expect(
71+
await resolver.resolveInput({
72+
index: 0,
73+
txId: Cardano.TransactionId('0f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d4')
74+
})
75+
).toBeNull();
76+
});
77+
78+
it('resolveInput resolves inputs from tx history', async () => {
79+
const utxo: Cardano.Utxo[] = [];
80+
const resolver = createInputResolver({
81+
transactions: {
82+
history$: of([
83+
{
84+
body: {
85+
outputs: [
86+
{
87+
address: Cardano.PaymentAddress('addr_test1vr8nl4u0u6fmtfnawx2rxfz95dy7m46t6dhzdftp2uha87syeufdg'),
88+
value: { coins: 50_000_000n }
89+
}
90+
]
91+
},
92+
id: Cardano.TransactionId('0f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5')
93+
} as Cardano.HydratedTx
94+
]),
95+
outgoing: { signed$: of() }
96+
},
5997
utxo: { available$: of(utxo) }
6098
});
6199
expect(
@@ -97,7 +135,7 @@ describe('WalletUtil', () => {
97135
} as Cardano.HydratedTx;
98136

99137
const resolver = createInputResolver({
100-
transactions: { outgoing: { signed$: of() } },
138+
transactions: { history$: of([]), outgoing: { signed$: of() } },
101139
utxo: { available$: of([]) }
102140
});
103141

@@ -134,7 +172,7 @@ describe('WalletUtil', () => {
134172
const signedTxs = mocks.queryTransactionsResult.pageResults.map(toSignedTx);
135173

136174
const resolver = createInputResolver({
137-
transactions: { outgoing: { signed$: of(signedTxs) } },
175+
transactions: { history$: of([]), outgoing: { signed$: of(signedTxs) } },
138176
utxo: { available$: of() }
139177
});
140178
expect(
@@ -273,7 +311,10 @@ describe('WalletUtil', () => {
273311
]
274312
];
275313
const resolver = combineInputResolvers(
276-
createInputResolver({ transactions: { outgoing: { signed$: of() } }, utxo: { available$: of(utxo) } }),
314+
createInputResolver({
315+
transactions: { history$: of([]), outgoing: { signed$: of() } },
316+
utxo: { available$: of(utxo) }
317+
}),
277318
createBackendInputResolver(createMockChainHistoryProvider())
278319
);
279320

@@ -315,7 +356,10 @@ describe('WalletUtil', () => {
315356
} as Cardano.HydratedTx;
316357

317358
const resolver = combineInputResolvers(
318-
createInputResolver({ transactions: { outgoing: { signed$: of() } }, utxo: { available$: of([]) } }),
359+
createInputResolver({
360+
transactions: { history$: of([]), outgoing: { signed$: of() } },
361+
utxo: { available$: of([]) }
362+
}),
319363
createBackendInputResolver(createMockChainHistoryProvider([tx]))
320364
);
321365

@@ -395,7 +439,10 @@ describe('WalletUtil', () => {
395439
];
396440

397441
const resolver = combineInputResolvers(
398-
createInputResolver({ transactions: { outgoing: { signed$: of() } }, utxo: { available$: of(utxo) } }),
442+
createInputResolver({
443+
transactions: { history$: of([]), outgoing: { signed$: of() } },
444+
utxo: { available$: of(utxo) }
445+
}),
399446
createBackendInputResolver(createMockChainHistoryProvider([tx]))
400447
);
401448

@@ -456,7 +503,10 @@ describe('WalletUtil', () => {
456503

457504
it('resolveInput resolves to null if the input can not be found', async () => {
458505
const resolver = combineInputResolvers(
459-
createInputResolver({ transactions: { outgoing: { signed$: of() } }, utxo: { available$: of([]) } }),
506+
createInputResolver({
507+
transactions: { history$: of([]), outgoing: { signed$: of() } },
508+
utxo: { available$: of([]) }
509+
}),
460510
createBackendInputResolver(createMockChainHistoryProvider())
461511
);
462512

0 commit comments

Comments
 (0)