@etherkit/viem-tx-tracker 0.1.0 → 0.2.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/README.md +57 -12
- package/dist/TrackedWalletClient.d.ts.map +1 -1
- package/dist/TrackedWalletClient.js +94 -52
- package/dist/TrackedWalletClient.js.map +1 -1
- package/dist/types.d.ts +88 -11
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrackedWalletClient.ts +180 -67
- package/src/types.ts +93 -11
|
@@ -136,6 +136,32 @@ function resolveSource<TSource>(
|
|
|
136
136
|
: (source as TSource);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* The values that are carried onto a tracked transaction rather than observed:
|
|
141
|
+
* they exist only because the caller (or the client construction) supplied
|
|
142
|
+
* them, so every emission path must thread them explicitly.
|
|
143
|
+
*
|
|
144
|
+
* They travel as one object so that adding a carried field cannot silently
|
|
145
|
+
* miss a path, and so that two same-typed markers cannot be swapped by a
|
|
146
|
+
* positional-argument mistake.
|
|
147
|
+
*
|
|
148
|
+
* The tracker never inspects any of them.
|
|
149
|
+
*/
|
|
150
|
+
interface CarriedFields<TMetadata, TSource> {
|
|
151
|
+
/** What the application says the transaction MEANS. Persisted by consumers. */
|
|
152
|
+
metadata: TMetadata;
|
|
153
|
+
/** WHICH SIGNING ROUTE produced it. Observed at dispatch, persisted. */
|
|
154
|
+
source: TSource;
|
|
155
|
+
/**
|
|
156
|
+
* Which CALLER-SIDE REQUEST this send answers. Ephemeral plumbing.
|
|
157
|
+
*
|
|
158
|
+
* Deliberately a required property of type `string | undefined` rather than
|
|
159
|
+
* an optional one: a new call site must state that it has no correlation,
|
|
160
|
+
* instead of getting `undefined` by forgetting the field.
|
|
161
|
+
*/
|
|
162
|
+
correlation: string | undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
139
165
|
/**
|
|
140
166
|
* Create an UnknownTrackedTransaction for immediate emission.
|
|
141
167
|
* Populates all known intended values from the transaction parameters.
|
|
@@ -145,8 +171,7 @@ function createUnknownTrackedTransaction<TMetadata, TSource>(
|
|
|
145
171
|
from: Address,
|
|
146
172
|
nonce: number,
|
|
147
173
|
chainId: number | undefined,
|
|
148
|
-
|
|
149
|
-
source: TSource,
|
|
174
|
+
carried: CarriedFields<TMetadata, TSource>,
|
|
150
175
|
broadcastTimestampMs: number,
|
|
151
176
|
params: IntendedTransactionParams,
|
|
152
177
|
): UnknownTrackedTransaction<TMetadata, TSource> {
|
|
@@ -157,8 +182,7 @@ function createUnknownTrackedTransaction<TMetadata, TSource>(
|
|
|
157
182
|
from,
|
|
158
183
|
nonce,
|
|
159
184
|
broadcastTimestampMs,
|
|
160
|
-
|
|
161
|
-
source,
|
|
185
|
+
...carried,
|
|
162
186
|
to: params.to,
|
|
163
187
|
value: params.value,
|
|
164
188
|
data: params.data,
|
|
@@ -278,13 +302,12 @@ function extractTransactionTypeFields(tx: Transaction):
|
|
|
278
302
|
* Create a KnownTrackedTransaction from a fetched transaction.
|
|
279
303
|
*
|
|
280
304
|
* Note: this object is rebuilt from the chain fetch, not copied from the
|
|
281
|
-
* broadcasted one, so every carried-but-not-observed field (metadata, source
|
|
282
|
-
* must be threaded in explicitly.
|
|
305
|
+
* broadcasted one, so every carried-but-not-observed field (metadata, source,
|
|
306
|
+
* correlation) must be threaded in explicitly.
|
|
283
307
|
*/
|
|
284
308
|
function createKnownTrackedTransaction<TMetadata, TSource>(
|
|
285
309
|
tx: Transaction,
|
|
286
|
-
|
|
287
|
-
source: TSource,
|
|
310
|
+
carried: CarriedFields<TMetadata, TSource>,
|
|
288
311
|
broadcastTimestampMs: number,
|
|
289
312
|
): KnownTrackedTransaction<TMetadata, TSource> {
|
|
290
313
|
const base = {
|
|
@@ -296,8 +319,7 @@ function createKnownTrackedTransaction<TMetadata, TSource>(
|
|
|
296
319
|
value: tx.value,
|
|
297
320
|
data: tx.input,
|
|
298
321
|
broadcastTimestampMs,
|
|
299
|
-
|
|
300
|
-
source,
|
|
322
|
+
...carried,
|
|
301
323
|
};
|
|
302
324
|
|
|
303
325
|
const typeFields = extractTransactionTypeFields(tx);
|
|
@@ -315,8 +337,7 @@ function createKnownTrackedTransactionFromRaw<TMetadata, TSource>(
|
|
|
315
337
|
parsedTx: ParseTransactionReturnType<`0x${string}`>,
|
|
316
338
|
from: `0x${string}`,
|
|
317
339
|
hash: Hash,
|
|
318
|
-
|
|
319
|
-
source: TSource,
|
|
340
|
+
carried: CarriedFields<TMetadata, TSource>,
|
|
320
341
|
chainId: number | undefined,
|
|
321
342
|
broadcastTimestampMs: number,
|
|
322
343
|
): KnownTrackedTransaction<TMetadata, TSource> {
|
|
@@ -329,8 +350,7 @@ function createKnownTrackedTransactionFromRaw<TMetadata, TSource>(
|
|
|
329
350
|
value: parsedTx.value ?? 0n,
|
|
330
351
|
data: parsedTx.data ?? '0x',
|
|
331
352
|
broadcastTimestampMs,
|
|
332
|
-
|
|
333
|
-
source,
|
|
353
|
+
...carried,
|
|
334
354
|
};
|
|
335
355
|
|
|
336
356
|
// Determine transaction type from parsed tx
|
|
@@ -629,7 +649,7 @@ export function createTrackedWalletClient<
|
|
|
629
649
|
// Create emitter for transaction events
|
|
630
650
|
const emitter = new Emitter<{
|
|
631
651
|
'transaction:broadcasted': TrackedTransaction<TMetadata, TSource>;
|
|
632
|
-
'transaction:
|
|
652
|
+
'transaction:known': KnownTrackedTransaction<TMetadata, TSource>;
|
|
633
653
|
}>();
|
|
634
654
|
|
|
635
655
|
/**
|
|
@@ -685,29 +705,27 @@ export function createTrackedWalletClient<
|
|
|
685
705
|
}
|
|
686
706
|
|
|
687
707
|
/**
|
|
688
|
-
* Fetch full transaction data and emit transaction:
|
|
708
|
+
* Fetch full transaction data and emit transaction:known event.
|
|
689
709
|
* Non-blocking, runs in background. Does not throw.
|
|
690
710
|
*/
|
|
691
711
|
async function fetchAndEmitFullData(
|
|
692
712
|
hash: Hash,
|
|
693
|
-
|
|
694
|
-
source: TSource,
|
|
713
|
+
carried: CarriedFields<TMetadata, TSource>,
|
|
695
714
|
broadcastTimestampMs: number,
|
|
696
715
|
): Promise<void> {
|
|
697
716
|
try {
|
|
698
717
|
const tx = await publicClient.getTransaction({hash});
|
|
699
718
|
const knownTx = createKnownTrackedTransaction(
|
|
700
719
|
tx,
|
|
701
|
-
|
|
702
|
-
source,
|
|
720
|
+
carried,
|
|
703
721
|
broadcastTimestampMs,
|
|
704
722
|
);
|
|
705
|
-
emitter.emit('transaction:
|
|
723
|
+
emitter.emit('transaction:known', knownTx);
|
|
706
724
|
} catch (error) {
|
|
707
|
-
// Log but don't throw - transaction:
|
|
725
|
+
// Log but don't throw - transaction:known simply won't fire
|
|
708
726
|
console.warn(
|
|
709
727
|
`[TrackedWalletClient] Could not fetch tx ${hash}. ` +
|
|
710
|
-
`transaction:
|
|
728
|
+
`transaction:known event will not be emitted. Error: ${error}`,
|
|
711
729
|
);
|
|
712
730
|
}
|
|
713
731
|
}
|
|
@@ -715,22 +733,46 @@ export function createTrackedWalletClient<
|
|
|
715
733
|
/**
|
|
716
734
|
* Common wrapper for transaction methods that broadcast (sendTransaction, writeContract).
|
|
717
735
|
* Emits transaction:broadcasted immediately with intended values,
|
|
718
|
-
* then fetches and emits transaction:
|
|
736
|
+
* then fetches and emits transaction:known with actual values.
|
|
719
737
|
*/
|
|
720
738
|
async function executeTrackedTransaction<T, R>(args: {
|
|
721
739
|
account?: Account | Address;
|
|
722
740
|
nonce?: NonceOption;
|
|
723
741
|
metadata: TMetadata;
|
|
724
|
-
|
|
742
|
+
correlation: string | undefined;
|
|
743
|
+
/**
|
|
744
|
+
* The caller's remaining args, spread verbatim into viem's own call.
|
|
745
|
+
*
|
|
746
|
+
* `{correlation?: never}` is the compile-time half of the no-forwarding
|
|
747
|
+
* rule: a wrapper that forgets to destructure `correlation` out fails
|
|
748
|
+
* here instead of handing the wallet an unrecognised parameter. Nothing
|
|
749
|
+
* downstream would catch it, since the viem call is behind an `as any`.
|
|
750
|
+
*/
|
|
751
|
+
restArgs: T & {correlation?: never};
|
|
725
752
|
intendedParams: IntendedTransactionParams;
|
|
726
753
|
execute: (argsWithNonce: T & {nonce: number}) => Promise<R>;
|
|
727
754
|
extractHash: (result: R) => Hash;
|
|
728
755
|
}): Promise<R> {
|
|
729
|
-
const {
|
|
756
|
+
const {
|
|
757
|
+
metadata,
|
|
758
|
+
correlation,
|
|
759
|
+
restArgs,
|
|
760
|
+
intendedParams,
|
|
761
|
+
execute,
|
|
762
|
+
extractHash,
|
|
763
|
+
} = args;
|
|
730
764
|
const broadcastTimestampMs = clock();
|
|
731
765
|
// Stamped here, in the same step as from/nonce/broadcastTimestampMs.
|
|
732
766
|
// A thunk is re-evaluated on every send, never captured once.
|
|
733
767
|
const source = resolveSource(sourceOption);
|
|
768
|
+
// The carried values travel as one bundle from here on: metadata (what
|
|
769
|
+
// the tx means), source (which route signed) and correlation (which
|
|
770
|
+
// caller-side request this send answers). None is interpreted.
|
|
771
|
+
const carried: CarriedFields<TMetadata, TSource> = {
|
|
772
|
+
metadata,
|
|
773
|
+
source,
|
|
774
|
+
correlation,
|
|
775
|
+
};
|
|
734
776
|
|
|
735
777
|
// Extract common context
|
|
736
778
|
const {from, intendedNonce} = await extractTransactionContext(args);
|
|
@@ -750,15 +792,14 @@ export function createTrackedWalletClient<
|
|
|
750
792
|
from,
|
|
751
793
|
intendedNonce,
|
|
752
794
|
walletClient.chain?.id,
|
|
753
|
-
|
|
754
|
-
source,
|
|
795
|
+
carried,
|
|
755
796
|
broadcastTimestampMs,
|
|
756
797
|
intendedParams,
|
|
757
798
|
);
|
|
758
799
|
emitter.emit('transaction:broadcasted', unknownTx);
|
|
759
800
|
|
|
760
|
-
// Fire-and-forget: fetch full data and emit transaction:
|
|
761
|
-
fetchAndEmitFullData(hash,
|
|
801
|
+
// Fire-and-forget: fetch full data and emit transaction:known
|
|
802
|
+
fetchAndEmitFullData(hash, carried, broadcastTimestampMs);
|
|
762
803
|
|
|
763
804
|
return result;
|
|
764
805
|
}
|
|
@@ -771,14 +812,26 @@ export function createTrackedWalletClient<
|
|
|
771
812
|
async function executeTrackedRawTransaction<R>(args: {
|
|
772
813
|
serializedTransaction: TransactionSerialized;
|
|
773
814
|
metadata: TMetadata;
|
|
815
|
+
correlation: string | undefined;
|
|
774
816
|
execute: () => Promise<R>;
|
|
775
817
|
extractHash: (result: R) => Hash;
|
|
776
818
|
}): Promise<R> {
|
|
777
|
-
const {
|
|
819
|
+
const {
|
|
820
|
+
serializedTransaction,
|
|
821
|
+
metadata,
|
|
822
|
+
correlation,
|
|
823
|
+
execute,
|
|
824
|
+
extractHash,
|
|
825
|
+
} = args;
|
|
778
826
|
const broadcastTimestampMs = clock();
|
|
779
827
|
// Stamped here, in the same step as from/nonce/broadcastTimestampMs.
|
|
780
828
|
// A thunk is re-evaluated on every send, never captured once.
|
|
781
829
|
const source = resolveSource(sourceOption);
|
|
830
|
+
const carried: CarriedFields<TMetadata, TSource> = {
|
|
831
|
+
metadata,
|
|
832
|
+
source,
|
|
833
|
+
correlation,
|
|
834
|
+
};
|
|
782
835
|
|
|
783
836
|
const from = await recoverTransactionAddress({serializedTransaction});
|
|
784
837
|
|
|
@@ -793,8 +846,7 @@ export function createTrackedWalletClient<
|
|
|
793
846
|
parsedTx,
|
|
794
847
|
from,
|
|
795
848
|
hash,
|
|
796
|
-
|
|
797
|
-
source,
|
|
849
|
+
carried,
|
|
798
850
|
walletClient.chain?.id,
|
|
799
851
|
broadcastTimestampMs,
|
|
800
852
|
);
|
|
@@ -802,8 +854,11 @@ export function createTrackedWalletClient<
|
|
|
802
854
|
// Emit as KnownTrackedTransaction since we have all data
|
|
803
855
|
emitter.emit('transaction:broadcasted', knownTx);
|
|
804
856
|
|
|
805
|
-
//
|
|
806
|
-
|
|
857
|
+
// The values are final (parsed from the signed payload, not merely
|
|
858
|
+
// intended), which is exactly what transaction:known promises, so it
|
|
859
|
+
// is emitted here too: every tracked transaction reaches that event,
|
|
860
|
+
// and a consumer can persist on it alone.
|
|
861
|
+
emitter.emit('transaction:known', knownTx);
|
|
807
862
|
|
|
808
863
|
return result;
|
|
809
864
|
}
|
|
@@ -843,13 +898,14 @@ export function createTrackedWalletClient<
|
|
|
843
898
|
TChainOverride
|
|
844
899
|
>,
|
|
845
900
|
): Promise<Hash> {
|
|
846
|
-
const {metadata, nonce, ...writeArgs} = args;
|
|
901
|
+
const {metadata, correlation, nonce, ...writeArgs} = args;
|
|
847
902
|
const intendedParams = extractIntendedParamsFromWriteContract(args);
|
|
848
903
|
|
|
849
904
|
return executeTrackedTransaction({
|
|
850
905
|
account: normalizeAccount(args.account),
|
|
851
906
|
nonce,
|
|
852
907
|
metadata: metadata as TMetadata,
|
|
908
|
+
correlation,
|
|
853
909
|
restArgs: writeArgs,
|
|
854
910
|
intendedParams,
|
|
855
911
|
execute: (argsWithNonce) =>
|
|
@@ -868,13 +924,14 @@ export function createTrackedWalletClient<
|
|
|
868
924
|
TChainOverride
|
|
869
925
|
>,
|
|
870
926
|
): Promise<Hash> {
|
|
871
|
-
const {metadata, nonce, ...sendArgs} = args;
|
|
927
|
+
const {metadata, correlation, nonce, ...sendArgs} = args;
|
|
872
928
|
const intendedParams = extractIntendedParamsFromSendTransaction(args);
|
|
873
929
|
|
|
874
930
|
return executeTrackedTransaction({
|
|
875
931
|
account: normalizeAccount(args.account),
|
|
876
932
|
nonce,
|
|
877
933
|
metadata: metadata as TMetadata,
|
|
934
|
+
correlation,
|
|
878
935
|
restArgs: sendArgs,
|
|
879
936
|
intendedParams,
|
|
880
937
|
execute: (argsWithNonce) =>
|
|
@@ -886,11 +943,12 @@ export function createTrackedWalletClient<
|
|
|
886
943
|
async sendRawTransaction(
|
|
887
944
|
args: TrackedRawTransactionParameters<TMetadata>,
|
|
888
945
|
): Promise<Hash> {
|
|
889
|
-
const {metadata, serializedTransaction} = args;
|
|
946
|
+
const {metadata, correlation, serializedTransaction} = args;
|
|
890
947
|
|
|
891
948
|
return executeTrackedRawTransaction({
|
|
892
949
|
serializedTransaction,
|
|
893
950
|
metadata: metadata as TMetadata,
|
|
951
|
+
correlation,
|
|
894
952
|
execute: () =>
|
|
895
953
|
walletClient.sendRawTransaction({serializedTransaction}),
|
|
896
954
|
extractHash: (hash) => hash,
|
|
@@ -924,13 +982,14 @@ export function createTrackedWalletClient<
|
|
|
924
982
|
TChainOverride
|
|
925
983
|
>,
|
|
926
984
|
): Promise<TransactionReceipt> {
|
|
927
|
-
const {metadata, nonce, ...writeArgs} = args;
|
|
985
|
+
const {metadata, correlation, nonce, ...writeArgs} = args;
|
|
928
986
|
const intendedParams = extractIntendedParamsFromWriteContract(args);
|
|
929
987
|
|
|
930
988
|
return executeTrackedTransaction({
|
|
931
989
|
account: normalizeAccount(args.account),
|
|
932
990
|
nonce,
|
|
933
991
|
metadata: metadata as TMetadata,
|
|
992
|
+
correlation,
|
|
934
993
|
restArgs: writeArgs,
|
|
935
994
|
intendedParams,
|
|
936
995
|
execute: (argsWithNonce) =>
|
|
@@ -949,13 +1008,14 @@ export function createTrackedWalletClient<
|
|
|
949
1008
|
TChainOverride
|
|
950
1009
|
>,
|
|
951
1010
|
): Promise<TransactionReceipt> {
|
|
952
|
-
const {metadata, nonce, ...sendArgs} = args;
|
|
1011
|
+
const {metadata, correlation, nonce, ...sendArgs} = args;
|
|
953
1012
|
const intendedParams = extractIntendedParamsFromSendTransaction(args);
|
|
954
1013
|
|
|
955
1014
|
return executeTrackedTransaction({
|
|
956
1015
|
account: normalizeAccount(args.account),
|
|
957
1016
|
nonce,
|
|
958
1017
|
metadata: metadata as TMetadata,
|
|
1018
|
+
correlation,
|
|
959
1019
|
restArgs: sendArgs,
|
|
960
1020
|
intendedParams,
|
|
961
1021
|
execute: (argsWithNonce) =>
|
|
@@ -967,11 +1027,12 @@ export function createTrackedWalletClient<
|
|
|
967
1027
|
async sendRawTransactionSync(
|
|
968
1028
|
args: TrackedRawTransactionParameters<TMetadata>,
|
|
969
1029
|
): Promise<TransactionReceipt> {
|
|
970
|
-
const {metadata, serializedTransaction} = args;
|
|
1030
|
+
const {metadata, correlation, serializedTransaction} = args;
|
|
971
1031
|
|
|
972
1032
|
return executeTrackedRawTransaction({
|
|
973
1033
|
serializedTransaction,
|
|
974
1034
|
metadata: metadata as TMetadata,
|
|
1035
|
+
correlation,
|
|
975
1036
|
execute: () =>
|
|
976
1037
|
walletClient.sendRawTransactionSync({serializedTransaction}),
|
|
977
1038
|
extractHash: (receipt) => receipt.transactionHash,
|
|
@@ -1016,7 +1077,7 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1016
1077
|
// Create emitter for transaction events
|
|
1017
1078
|
const emitter = new Emitter<{
|
|
1018
1079
|
'transaction:broadcasted': TrackedTransaction<TMetadata, TSource>;
|
|
1019
|
-
'transaction:
|
|
1080
|
+
'transaction:known': KnownTrackedTransaction<TMetadata, TSource>;
|
|
1020
1081
|
}>();
|
|
1021
1082
|
|
|
1022
1083
|
/**
|
|
@@ -1058,29 +1119,27 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1058
1119
|
}
|
|
1059
1120
|
|
|
1060
1121
|
/**
|
|
1061
|
-
* Fetch full transaction data and emit transaction:
|
|
1122
|
+
* Fetch full transaction data and emit transaction:known event.
|
|
1062
1123
|
* Non-blocking, runs in background. Does not throw.
|
|
1063
1124
|
*/
|
|
1064
1125
|
async function fetchAndEmitFullData(
|
|
1065
1126
|
hash: Hash,
|
|
1066
|
-
|
|
1067
|
-
source: TSource,
|
|
1127
|
+
carried: CarriedFields<TMetadata, TSource>,
|
|
1068
1128
|
broadcastTimestampMs: number,
|
|
1069
1129
|
): Promise<void> {
|
|
1070
1130
|
try {
|
|
1071
1131
|
const tx = await publicClient.getTransaction({hash});
|
|
1072
1132
|
const knownTx = createKnownTrackedTransaction(
|
|
1073
1133
|
tx,
|
|
1074
|
-
|
|
1075
|
-
source,
|
|
1134
|
+
carried,
|
|
1076
1135
|
broadcastTimestampMs,
|
|
1077
1136
|
);
|
|
1078
|
-
emitter.emit('transaction:
|
|
1137
|
+
emitter.emit('transaction:known', knownTx);
|
|
1079
1138
|
} catch (error) {
|
|
1080
|
-
// Log but don't throw - transaction:
|
|
1139
|
+
// Log but don't throw - transaction:known simply won't fire
|
|
1081
1140
|
console.warn(
|
|
1082
1141
|
`[TrackedWalletClient] Could not fetch tx ${hash}. ` +
|
|
1083
|
-
`transaction:
|
|
1142
|
+
`transaction:known event will not be emitted. Error: ${error}`,
|
|
1084
1143
|
);
|
|
1085
1144
|
}
|
|
1086
1145
|
}
|
|
@@ -1117,22 +1176,46 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1117
1176
|
/**
|
|
1118
1177
|
* Common wrapper for transaction methods that broadcast.
|
|
1119
1178
|
* Emits transaction:broadcasted immediately with intended values,
|
|
1120
|
-
* then fetches and emits transaction:
|
|
1179
|
+
* then fetches and emits transaction:known with actual values.
|
|
1121
1180
|
*/
|
|
1122
1181
|
async function executeTrackedTransaction<T, R>(args: {
|
|
1123
1182
|
account?: Account | Address;
|
|
1124
1183
|
nonce?: NonceOption;
|
|
1125
1184
|
metadata: TMetadata;
|
|
1126
|
-
|
|
1185
|
+
correlation: string | undefined;
|
|
1186
|
+
/**
|
|
1187
|
+
* The caller's remaining args, spread verbatim into viem's own call.
|
|
1188
|
+
*
|
|
1189
|
+
* `{correlation?: never}` is the compile-time half of the no-forwarding
|
|
1190
|
+
* rule: a wrapper that forgets to destructure `correlation` out fails
|
|
1191
|
+
* here instead of handing the wallet an unrecognised parameter. Nothing
|
|
1192
|
+
* downstream would catch it, since the viem call is behind an `as any`.
|
|
1193
|
+
*/
|
|
1194
|
+
restArgs: T & {correlation?: never};
|
|
1127
1195
|
intendedParams: IntendedTransactionParams;
|
|
1128
1196
|
execute: (argsWithNonce: T & {nonce: number}) => Promise<R>;
|
|
1129
1197
|
extractHash: (result: R) => Hash;
|
|
1130
1198
|
}): Promise<R> {
|
|
1131
|
-
const {
|
|
1199
|
+
const {
|
|
1200
|
+
metadata,
|
|
1201
|
+
correlation,
|
|
1202
|
+
restArgs,
|
|
1203
|
+
intendedParams,
|
|
1204
|
+
execute,
|
|
1205
|
+
extractHash,
|
|
1206
|
+
} = args;
|
|
1132
1207
|
const broadcastTimestampMs = clock();
|
|
1133
1208
|
// Stamped here, in the same step as from/nonce/broadcastTimestampMs.
|
|
1134
1209
|
// A thunk is re-evaluated on every send, never captured once.
|
|
1135
1210
|
const source = resolveSource(sourceOption);
|
|
1211
|
+
// The carried values travel as one bundle from here on: metadata (what
|
|
1212
|
+
// the tx means), source (which route signed) and correlation (which
|
|
1213
|
+
// caller-side request this send answers). None is interpreted.
|
|
1214
|
+
const carried: CarriedFields<TMetadata, TSource> = {
|
|
1215
|
+
metadata,
|
|
1216
|
+
source,
|
|
1217
|
+
correlation,
|
|
1218
|
+
};
|
|
1136
1219
|
|
|
1137
1220
|
const {from, intendedNonce} = await extractTransactionContext(args);
|
|
1138
1221
|
|
|
@@ -1150,15 +1233,14 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1150
1233
|
from,
|
|
1151
1234
|
intendedNonce,
|
|
1152
1235
|
walletClient.chain?.id,
|
|
1153
|
-
|
|
1154
|
-
source,
|
|
1236
|
+
carried,
|
|
1155
1237
|
broadcastTimestampMs,
|
|
1156
1238
|
intendedParams,
|
|
1157
1239
|
);
|
|
1158
1240
|
emitter.emit('transaction:broadcasted', unknownTx);
|
|
1159
1241
|
|
|
1160
|
-
// Fire-and-forget: fetch full data and emit transaction:
|
|
1161
|
-
fetchAndEmitFullData(hash,
|
|
1242
|
+
// Fire-and-forget: fetch full data and emit transaction:known
|
|
1243
|
+
fetchAndEmitFullData(hash, carried, broadcastTimestampMs);
|
|
1162
1244
|
|
|
1163
1245
|
return result;
|
|
1164
1246
|
}
|
|
@@ -1171,14 +1253,26 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1171
1253
|
async function executeTrackedRawTransaction<R>(args: {
|
|
1172
1254
|
serializedTransaction: TransactionSerialized;
|
|
1173
1255
|
metadata: TMetadata;
|
|
1256
|
+
correlation: string | undefined;
|
|
1174
1257
|
execute: () => Promise<R>;
|
|
1175
1258
|
extractHash: (result: R) => Hash;
|
|
1176
1259
|
}): Promise<R> {
|
|
1177
|
-
const {
|
|
1260
|
+
const {
|
|
1261
|
+
serializedTransaction,
|
|
1262
|
+
metadata,
|
|
1263
|
+
correlation,
|
|
1264
|
+
execute,
|
|
1265
|
+
extractHash,
|
|
1266
|
+
} = args;
|
|
1178
1267
|
const broadcastTimestampMs = clock();
|
|
1179
1268
|
// Stamped here, in the same step as from/nonce/broadcastTimestampMs.
|
|
1180
1269
|
// A thunk is re-evaluated on every send, never captured once.
|
|
1181
1270
|
const source = resolveSource(sourceOption);
|
|
1271
|
+
const carried: CarriedFields<TMetadata, TSource> = {
|
|
1272
|
+
metadata,
|
|
1273
|
+
source,
|
|
1274
|
+
correlation,
|
|
1275
|
+
};
|
|
1182
1276
|
|
|
1183
1277
|
const from = await recoverTransactionAddress({serializedTransaction});
|
|
1184
1278
|
const parsedTx = parseTransaction(serializedTransaction);
|
|
@@ -1192,8 +1286,7 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1192
1286
|
parsedTx,
|
|
1193
1287
|
from,
|
|
1194
1288
|
hash,
|
|
1195
|
-
|
|
1196
|
-
source,
|
|
1289
|
+
carried,
|
|
1197
1290
|
walletClient.chain?.id,
|
|
1198
1291
|
broadcastTimestampMs,
|
|
1199
1292
|
);
|
|
@@ -1201,7 +1294,11 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1201
1294
|
// Emit as KnownTrackedTransaction since we have all data
|
|
1202
1295
|
emitter.emit('transaction:broadcasted', knownTx);
|
|
1203
1296
|
|
|
1204
|
-
//
|
|
1297
|
+
// The values are final (parsed from the signed payload, not merely
|
|
1298
|
+
// intended), which is exactly what transaction:known promises, so it
|
|
1299
|
+
// is emitted here too: every tracked transaction reaches that event,
|
|
1300
|
+
// and a consumer can persist on it alone.
|
|
1301
|
+
emitter.emit('transaction:known', knownTx);
|
|
1205
1302
|
|
|
1206
1303
|
return result;
|
|
1207
1304
|
}
|
|
@@ -1241,7 +1338,12 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1241
1338
|
TChainOverride
|
|
1242
1339
|
>,
|
|
1243
1340
|
): Promise<Hash> {
|
|
1244
|
-
const {
|
|
1341
|
+
const {
|
|
1342
|
+
metadata: userMetadata,
|
|
1343
|
+
correlation,
|
|
1344
|
+
nonce,
|
|
1345
|
+
...writeArgs
|
|
1346
|
+
} = args;
|
|
1245
1347
|
|
|
1246
1348
|
// Validate that user didn't provide operation, functionName or args
|
|
1247
1349
|
validateNoAutoPopulatedFieldsInMetadata(userMetadata);
|
|
@@ -1260,6 +1362,7 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1260
1362
|
account: normalizeAccount(args.account),
|
|
1261
1363
|
nonce,
|
|
1262
1364
|
metadata: finalMetadata,
|
|
1365
|
+
correlation,
|
|
1263
1366
|
restArgs: writeArgs,
|
|
1264
1367
|
intendedParams,
|
|
1265
1368
|
execute: (argsWithNonce) =>
|
|
@@ -1278,13 +1381,14 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1278
1381
|
TChainOverride
|
|
1279
1382
|
>,
|
|
1280
1383
|
): Promise<Hash> {
|
|
1281
|
-
const {metadata, nonce, ...sendArgs} = args;
|
|
1384
|
+
const {metadata, correlation, nonce, ...sendArgs} = args;
|
|
1282
1385
|
const intendedParams = extractIntendedParamsFromSendTransaction(args);
|
|
1283
1386
|
|
|
1284
1387
|
return executeTrackedTransaction({
|
|
1285
1388
|
account: normalizeAccount(args.account),
|
|
1286
1389
|
nonce,
|
|
1287
1390
|
metadata: metadata as TMetadata,
|
|
1391
|
+
correlation,
|
|
1288
1392
|
restArgs: sendArgs,
|
|
1289
1393
|
intendedParams,
|
|
1290
1394
|
execute: (argsWithNonce) =>
|
|
@@ -1296,11 +1400,12 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1296
1400
|
async sendRawTransaction(
|
|
1297
1401
|
args: TrackedRawTransactionParameters<TMetadata>,
|
|
1298
1402
|
): Promise<Hash> {
|
|
1299
|
-
const {metadata, serializedTransaction} = args;
|
|
1403
|
+
const {metadata, correlation, serializedTransaction} = args;
|
|
1300
1404
|
|
|
1301
1405
|
return executeTrackedRawTransaction({
|
|
1302
1406
|
serializedTransaction,
|
|
1303
1407
|
metadata: metadata as TMetadata,
|
|
1408
|
+
correlation,
|
|
1304
1409
|
execute: () =>
|
|
1305
1410
|
walletClient.sendRawTransaction({serializedTransaction}),
|
|
1306
1411
|
extractHash: (hash) => hash,
|
|
@@ -1334,7 +1439,12 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1334
1439
|
TChainOverride
|
|
1335
1440
|
>,
|
|
1336
1441
|
): Promise<TransactionReceipt> {
|
|
1337
|
-
const {
|
|
1442
|
+
const {
|
|
1443
|
+
metadata: userMetadata,
|
|
1444
|
+
correlation,
|
|
1445
|
+
nonce,
|
|
1446
|
+
...writeArgs
|
|
1447
|
+
} = args;
|
|
1338
1448
|
|
|
1339
1449
|
// Validate that user didn't provide operation, functionName or args
|
|
1340
1450
|
validateNoAutoPopulatedFieldsInMetadata(userMetadata);
|
|
@@ -1353,6 +1463,7 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1353
1463
|
account: normalizeAccount(args.account),
|
|
1354
1464
|
nonce,
|
|
1355
1465
|
metadata: finalMetadata,
|
|
1466
|
+
correlation,
|
|
1356
1467
|
restArgs: writeArgs,
|
|
1357
1468
|
intendedParams,
|
|
1358
1469
|
execute: (argsWithNonce) =>
|
|
@@ -1371,13 +1482,14 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1371
1482
|
TChainOverride
|
|
1372
1483
|
>,
|
|
1373
1484
|
): Promise<TransactionReceipt> {
|
|
1374
|
-
const {metadata, nonce, ...sendArgs} = args;
|
|
1485
|
+
const {metadata, correlation, nonce, ...sendArgs} = args;
|
|
1375
1486
|
const intendedParams = extractIntendedParamsFromSendTransaction(args);
|
|
1376
1487
|
|
|
1377
1488
|
return executeTrackedTransaction({
|
|
1378
1489
|
account: normalizeAccount(args.account),
|
|
1379
1490
|
nonce,
|
|
1380
1491
|
metadata: metadata as TMetadata,
|
|
1492
|
+
correlation,
|
|
1381
1493
|
restArgs: sendArgs,
|
|
1382
1494
|
intendedParams,
|
|
1383
1495
|
execute: (argsWithNonce) =>
|
|
@@ -1389,11 +1501,12 @@ function createAutoPopulateBuilder<TMetadata, TSource>(
|
|
|
1389
1501
|
async sendRawTransactionSync(
|
|
1390
1502
|
args: TrackedRawTransactionParameters<TMetadata>,
|
|
1391
1503
|
): Promise<TransactionReceipt> {
|
|
1392
|
-
const {metadata, serializedTransaction} = args;
|
|
1504
|
+
const {metadata, correlation, serializedTransaction} = args;
|
|
1393
1505
|
|
|
1394
1506
|
return executeTrackedRawTransaction({
|
|
1395
1507
|
serializedTransaction,
|
|
1396
1508
|
metadata: metadata as TMetadata,
|
|
1509
|
+
correlation,
|
|
1397
1510
|
execute: () =>
|
|
1398
1511
|
walletClient.sendRawTransactionSync({serializedTransaction}),
|
|
1399
1512
|
extractHash: (receipt) => receipt.transactionHash,
|