1
1
/* eslint-disable no-bitwise */
2
2
import * as Crypto from '@cardano-sdk/crypto' ;
3
- import { Cardano } from '@cardano-sdk/core' ;
3
+ import { Cardano , ChainHistoryProvider } from '@cardano-sdk/core' ;
4
4
import { GroupedAddress , util as KeyManagementUtil } from '@cardano-sdk/key-management' ;
5
5
import { Observable , firstValueFrom } from 'rxjs' ;
6
6
import { ObservableWallet , ScriptAddress , isScriptAddress } from '../types' ;
@@ -23,11 +23,79 @@ export interface WalletOutputValidatorContext {
23
23
export type WalletUtilContext = WalletOutputValidatorContext & InputResolverContext ;
24
24
25
25
export const createInputResolver = ( { utxo } : InputResolverContext ) : Cardano . InputResolver => ( {
26
- async resolveInput ( input : Cardano . TxIn ) {
26
+ async resolveInput ( input : Cardano . TxIn , options ?: Cardano . ResolveOptions ) {
27
27
const utxoAvailable = await firstValueFrom ( utxo . available$ ) ;
28
28
const availableUtxo = utxoAvailable ?. find ( ( [ txIn ] ) => txInEquals ( txIn , input ) ) ;
29
- if ( ! availableUtxo ) return null ;
30
- return availableUtxo [ 1 ] ;
29
+
30
+ if ( availableUtxo ) return availableUtxo [ 1 ] ;
31
+
32
+ if ( options ?. hints ) {
33
+ const tx = options ?. hints . find ( ( hint ) => hint . id === input . txId ) ;
34
+
35
+ if ( tx && tx . body . outputs . length > input . index ) {
36
+ return tx . body . outputs [ input . index ] ;
37
+ }
38
+ }
39
+ return null ;
40
+ }
41
+ } ) ;
42
+
43
+ /**
44
+ * Creates an input resolver that fetch transaction inputs from the backend.
45
+ *
46
+ * This function tries to fetch the transaction from the backend using a `ChainHistoryProvider`. It
47
+ * also caches fetched transactions to optimize subsequent input resolutions.
48
+ *
49
+ * @param provider The backend provider used to fetch transactions by their hashes if
50
+ * they are not found by the inputResolver.
51
+ * @returns An input resolver that can fetch unresolved inputs from the backend.
52
+ */
53
+ export const createBackendInputResolver = ( provider : ChainHistoryProvider ) : Cardano . InputResolver => {
54
+ const txCache = new Map < Cardano . TransactionId , Cardano . Tx > ( ) ;
55
+
56
+ const fetchAndCacheTransaction = async ( txId : Cardano . TransactionId ) : Promise < Cardano . Tx | null > => {
57
+ if ( txCache . has ( txId ) ) {
58
+ return txCache . get ( txId ) ! ;
59
+ }
60
+
61
+ const txs = await provider . transactionsByHashes ( { ids : [ txId ] } ) ;
62
+ if ( txs . length > 0 ) {
63
+ txCache . set ( txId , txs [ 0 ] ) ;
64
+ return txs [ 0 ] ;
65
+ }
66
+
67
+ return null ;
68
+ } ;
69
+
70
+ return {
71
+ async resolveInput ( input : Cardano . TxIn , options ?: Cardano . ResolveOptions ) {
72
+ // Add hints to the cache
73
+ if ( options ?. hints ) {
74
+ for ( const hint of options . hints ) {
75
+ txCache . set ( hint . id , hint ) ;
76
+ }
77
+ }
78
+
79
+ const tx = await fetchAndCacheTransaction ( input . txId ) ;
80
+ if ( ! tx ) return null ;
81
+
82
+ return tx . body . outputs . length > input . index ? tx . body . outputs [ input . index ] : null ;
83
+ }
84
+ } ;
85
+ } ;
86
+
87
+ /**
88
+ * Combines multiple input resolvers into a single resolver.
89
+ *
90
+ * @param resolvers The input resolvers to combine.
91
+ */
92
+ export const combineInputResolvers = ( ...resolvers : Cardano . InputResolver [ ] ) : Cardano . InputResolver => ( {
93
+ async resolveInput ( txIn : Cardano . TxIn , options ?: Cardano . ResolveOptions ) {
94
+ for ( const resolver of resolvers ) {
95
+ const resolved = await resolver . resolveInput ( txIn , options ) ;
96
+ if ( resolved ) return resolved ;
97
+ }
98
+ return null ;
31
99
}
32
100
} ) ;
33
101
0 commit comments