@etherkit/viem-tx-tracker 0.0.4 → 0.0.5
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/TrackedWalletClient.d.ts +34 -3
- package/dist/TrackedWalletClient.d.ts.map +1 -1
- package/dist/TrackedWalletClient.js +235 -24
- package/dist/TrackedWalletClient.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +154 -24
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrackedWalletClient.ts +497 -4
- package/src/index.ts +1 -0
- package/src/types.ts +286 -23
|
@@ -17,12 +17,15 @@ import {
|
|
|
17
17
|
import {Emitter} from 'radiate';
|
|
18
18
|
import type {
|
|
19
19
|
BlockTag,
|
|
20
|
-
|
|
20
|
+
CreateTrackedWalletClientOptions,
|
|
21
21
|
NonceOption,
|
|
22
|
+
PopulatedMetadata,
|
|
22
23
|
TrackedRawTransactionParameters,
|
|
23
24
|
TrackedSendTransactionParameters,
|
|
24
25
|
TrackedTransaction,
|
|
25
26
|
TrackedWalletClient,
|
|
27
|
+
TrackedWalletClientAutoPopulate,
|
|
28
|
+
TrackedWriteContractAutoPopulateParameters,
|
|
26
29
|
TrackedWriteContractParameters,
|
|
27
30
|
} from './types.js';
|
|
28
31
|
|
|
@@ -113,6 +116,31 @@ export interface TrackedWalletClientBuilder<TMetadata> {
|
|
|
113
116
|
>;
|
|
114
117
|
}
|
|
115
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Builder interface returned by createTrackedWalletClient with populateMetadata: true.
|
|
121
|
+
* This builder returns a TrackedWalletClientAutoPopulate that auto-populates operation, functionName and args.
|
|
122
|
+
* TMetadata must be a type where FunctionCallMetadata is assignable to it.
|
|
123
|
+
*/
|
|
124
|
+
export interface TrackedWalletClientAutoPopulateBuilder<TMetadata> {
|
|
125
|
+
/**
|
|
126
|
+
* Create the tracked wallet client using the provided wallet and public clients.
|
|
127
|
+
* writeContract and writeContractSync will automatically populate operation, functionName and args.
|
|
128
|
+
*
|
|
129
|
+
* @param walletClient - The underlying viem WalletClient
|
|
130
|
+
* @param publicClient - A PublicClient for nonce fetching and tx verification
|
|
131
|
+
* @returns A TrackedWalletClientAutoPopulate instance
|
|
132
|
+
*/
|
|
133
|
+
using<TClient extends WalletClient>(
|
|
134
|
+
walletClient: TClient,
|
|
135
|
+
publicClient: PublicClient,
|
|
136
|
+
): TrackedWalletClientAutoPopulate<
|
|
137
|
+
TMetadata,
|
|
138
|
+
InferTransport<TClient>,
|
|
139
|
+
InferChain<TClient>,
|
|
140
|
+
InferAccount<TClient>
|
|
141
|
+
>;
|
|
142
|
+
}
|
|
143
|
+
|
|
116
144
|
/**
|
|
117
145
|
* Create a tracked wallet client that wraps a viem WalletClient.
|
|
118
146
|
*
|
|
@@ -127,18 +155,51 @@ export interface TrackedWalletClientBuilder<TMetadata> {
|
|
|
127
155
|
*
|
|
128
156
|
* @example
|
|
129
157
|
* ```typescript
|
|
130
|
-
* //
|
|
158
|
+
* // Standard mode with required metadata
|
|
131
159
|
* const tracked = createTrackedWalletClient<{purpose: string}>()
|
|
132
160
|
* .using(walletClient, publicClient);
|
|
133
161
|
*
|
|
134
|
-
* //
|
|
162
|
+
* // Standard mode with optional metadata
|
|
135
163
|
* const tracked = createTrackedWalletClient<{purpose: string} | undefined>()
|
|
136
164
|
* .using(walletClient, publicClient);
|
|
165
|
+
*
|
|
166
|
+
* // Auto-populate mode - functionName and args are auto-populated
|
|
167
|
+
* const tracked = createTrackedWalletClient({ populateMetadata: true })
|
|
168
|
+
* .using(walletClient, publicClient);
|
|
169
|
+
*
|
|
170
|
+
* // Auto-populate mode with extended metadata
|
|
171
|
+
* type MyMetadata = OperationMetadata & { purpose: string };
|
|
172
|
+
* const tracked = createTrackedWalletClient<MyMetadata>({ populateMetadata: true })
|
|
173
|
+
* .using(walletClient, publicClient);
|
|
137
174
|
* ```
|
|
138
175
|
*/
|
|
176
|
+
// Overload 1: Standard mode, no options
|
|
139
177
|
export function createTrackedWalletClient<
|
|
140
178
|
TMetadata,
|
|
141
|
-
>(): TrackedWalletClientBuilder<TMetadata
|
|
179
|
+
>(): TrackedWalletClientBuilder<TMetadata>;
|
|
180
|
+
|
|
181
|
+
// Overload 2: Auto-populate mode with default PopulatedMetadata
|
|
182
|
+
export function createTrackedWalletClient(options: {
|
|
183
|
+
populateMetadata: true;
|
|
184
|
+
}): TrackedWalletClientAutoPopulateBuilder<PopulatedMetadata>;
|
|
185
|
+
|
|
186
|
+
// Overload 3: Auto-populate mode with custom metadata (must allow FunctionCallMetadata)
|
|
187
|
+
export function createTrackedWalletClient<TMetadata>(options: {
|
|
188
|
+
populateMetadata: true;
|
|
189
|
+
}): TrackedWalletClientAutoPopulateBuilder<TMetadata>;
|
|
190
|
+
|
|
191
|
+
// Implementation
|
|
192
|
+
export function createTrackedWalletClient<TMetadata>(
|
|
193
|
+
options?: CreateTrackedWalletClientOptions<boolean>,
|
|
194
|
+
):
|
|
195
|
+
| TrackedWalletClientBuilder<TMetadata>
|
|
196
|
+
| TrackedWalletClientAutoPopulateBuilder<TMetadata> {
|
|
197
|
+
const populateMetadata = options?.populateMetadata ?? false;
|
|
198
|
+
|
|
199
|
+
if (populateMetadata) {
|
|
200
|
+
return createAutoPopulateBuilder<TMetadata>() as TrackedWalletClientAutoPopulateBuilder<TMetadata>;
|
|
201
|
+
}
|
|
202
|
+
|
|
142
203
|
return {
|
|
143
204
|
using<TClient extends WalletClient>(
|
|
144
205
|
walletClient: TClient,
|
|
@@ -552,3 +613,435 @@ export function createTrackedWalletClient<
|
|
|
552
613
|
},
|
|
553
614
|
};
|
|
554
615
|
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Create an auto-populate builder for TrackedWalletClient.
|
|
619
|
+
* This builder auto-populates operation, functionName and args in writeContract metadata.
|
|
620
|
+
*/
|
|
621
|
+
function createAutoPopulateBuilder<
|
|
622
|
+
TMetadata,
|
|
623
|
+
>(): TrackedWalletClientAutoPopulateBuilder<TMetadata> {
|
|
624
|
+
return {
|
|
625
|
+
using<TClient extends WalletClient>(
|
|
626
|
+
walletClient: TClient,
|
|
627
|
+
publicClient: PublicClient,
|
|
628
|
+
): TrackedWalletClientAutoPopulate<
|
|
629
|
+
TMetadata,
|
|
630
|
+
InferTransport<TClient>,
|
|
631
|
+
InferChain<TClient>,
|
|
632
|
+
InferAccount<TClient>
|
|
633
|
+
> {
|
|
634
|
+
// Type aliases for internal use
|
|
635
|
+
type TTransport = InferTransport<TClient>;
|
|
636
|
+
type TChain = InferChain<TClient>;
|
|
637
|
+
type TAccount = InferAccount<TClient>;
|
|
638
|
+
|
|
639
|
+
// Create emitter for transaction broadcast events
|
|
640
|
+
const emitter = new Emitter<{
|
|
641
|
+
'transaction:broadcasted': TrackedTransaction<TMetadata>;
|
|
642
|
+
}>();
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Resolve the nonce to use for a transaction.
|
|
646
|
+
*/
|
|
647
|
+
async function resolveNonce(
|
|
648
|
+
nonceOption: NonceOption | undefined,
|
|
649
|
+
from: Address,
|
|
650
|
+
): Promise<number> {
|
|
651
|
+
if (typeof nonceOption === 'number') {
|
|
652
|
+
return nonceOption;
|
|
653
|
+
}
|
|
654
|
+
const blockTag = isBlockTag(nonceOption) ? nonceOption : 'pending';
|
|
655
|
+
return await publicClient.getTransactionCount({
|
|
656
|
+
address: from,
|
|
657
|
+
blockTag,
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Extract common transaction context (account, nonce) from request args.
|
|
663
|
+
*/
|
|
664
|
+
async function extractTransactionContext(args: {
|
|
665
|
+
account?: Account | Address;
|
|
666
|
+
nonce?: NonceOption;
|
|
667
|
+
}): Promise<TransactionContext> {
|
|
668
|
+
const account = args.account ?? walletClient.account;
|
|
669
|
+
const from = resolveAccountAddress(account);
|
|
670
|
+
|
|
671
|
+
if (!from) {
|
|
672
|
+
throw new Error(
|
|
673
|
+
'[TrackedWalletClient] No account available. ' +
|
|
674
|
+
'Provide an account in the request or configure the wallet client with an account.',
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const intendedNonce = await resolveNonce(args.nonce, from);
|
|
679
|
+
return {from, intendedNonce};
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Extract transaction context from a serialized (signed) transaction.
|
|
684
|
+
*/
|
|
685
|
+
async function extractRawTransactionContext(
|
|
686
|
+
serializedTransaction: TransactionSerialized,
|
|
687
|
+
): Promise<TransactionContext> {
|
|
688
|
+
const parsedTx = parseTransaction(serializedTransaction);
|
|
689
|
+
|
|
690
|
+
if (parsedTx.nonce === undefined) {
|
|
691
|
+
throw new Error(
|
|
692
|
+
'[TrackedWalletClient] Could not extract nonce from serialized transaction.',
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const from = await recoverTransactionAddress({
|
|
697
|
+
serializedTransaction,
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
return {
|
|
701
|
+
from,
|
|
702
|
+
intendedNonce: parsedTx.nonce,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Fetch the transaction after broadcast to verify nonce.
|
|
708
|
+
*/
|
|
709
|
+
async function verifyTransactionNonce(
|
|
710
|
+
hash: Hash,
|
|
711
|
+
intendedNonce: number,
|
|
712
|
+
): Promise<number> {
|
|
713
|
+
try {
|
|
714
|
+
const tx = await publicClient.getTransaction({hash});
|
|
715
|
+
const actualNonce = tx.nonce;
|
|
716
|
+
|
|
717
|
+
if (actualNonce !== intendedNonce) {
|
|
718
|
+
console.warn(
|
|
719
|
+
`[TrackedWalletClient] Nonce mismatch: intended ${intendedNonce}, actual ${actualNonce}. ` +
|
|
720
|
+
`Wallet may have overridden the nonce.`,
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return actualNonce;
|
|
725
|
+
} catch (fetchError) {
|
|
726
|
+
console.warn(
|
|
727
|
+
`[TrackedWalletClient] Could not fetch tx ${hash} after broadcast. ` +
|
|
728
|
+
`It may not be in the mempool yet.`,
|
|
729
|
+
);
|
|
730
|
+
return intendedNonce;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Create a tracked transaction record.
|
|
736
|
+
*/
|
|
737
|
+
function createTrackedTransactionRecord(
|
|
738
|
+
txHash: Hash,
|
|
739
|
+
from: Address,
|
|
740
|
+
nonce: number,
|
|
741
|
+
metadata: TMetadata,
|
|
742
|
+
): TrackedTransaction<TMetadata> {
|
|
743
|
+
return {
|
|
744
|
+
hash: txHash,
|
|
745
|
+
from,
|
|
746
|
+
nonce,
|
|
747
|
+
chainId: walletClient.chain?.id,
|
|
748
|
+
metadata,
|
|
749
|
+
broadcastTimestampMs: Date.now(),
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Validate that user didn't provide operation, functionName or args in metadata
|
|
755
|
+
* when populateMetadata is enabled.
|
|
756
|
+
*/
|
|
757
|
+
function validateNoAutoPopulatedFieldsInMetadata(
|
|
758
|
+
userMetadata: unknown,
|
|
759
|
+
): void {
|
|
760
|
+
if (userMetadata && typeof userMetadata === 'object') {
|
|
761
|
+
if ('type' in userMetadata) {
|
|
762
|
+
throw new Error(
|
|
763
|
+
'[TrackedWalletClient] Cannot specify type in metadata when populateMetadata is enabled. ' +
|
|
764
|
+
'The type is automatically populated from the contract call.',
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
if ('functionName' in userMetadata) {
|
|
768
|
+
throw new Error(
|
|
769
|
+
'[TrackedWalletClient] Cannot specify functionName in metadata when populateMetadata is enabled. ' +
|
|
770
|
+
'The functionName is automatically populated from the contract call.',
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
if ('args' in userMetadata) {
|
|
774
|
+
throw new Error(
|
|
775
|
+
'[TrackedWalletClient] Cannot specify args in metadata when populateMetadata is enabled. ' +
|
|
776
|
+
'The args are automatically populated from the contract call.',
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Common wrapper for transaction methods that broadcast.
|
|
784
|
+
*/
|
|
785
|
+
async function executeTrackedTransaction<T, R>(args: {
|
|
786
|
+
account?: Account | Address;
|
|
787
|
+
nonce?: NonceOption;
|
|
788
|
+
metadata: TMetadata;
|
|
789
|
+
restArgs: T;
|
|
790
|
+
execute: (argsWithNonce: T & {nonce: number}) => Promise<R>;
|
|
791
|
+
extractHash: (result: R) => Hash;
|
|
792
|
+
}): Promise<R> {
|
|
793
|
+
const {metadata, restArgs, execute, extractHash} = args;
|
|
794
|
+
|
|
795
|
+
const {from, intendedNonce} = await extractTransactionContext(args);
|
|
796
|
+
|
|
797
|
+
const result = await execute({
|
|
798
|
+
...restArgs,
|
|
799
|
+
nonce: intendedNonce,
|
|
800
|
+
} as T & {
|
|
801
|
+
nonce: number;
|
|
802
|
+
});
|
|
803
|
+
const hash = extractHash(result);
|
|
804
|
+
|
|
805
|
+
const actualNonce = await verifyTransactionNonce(hash, intendedNonce);
|
|
806
|
+
|
|
807
|
+
const trackedTx = createTrackedTransactionRecord(
|
|
808
|
+
hash,
|
|
809
|
+
from,
|
|
810
|
+
actualNonce,
|
|
811
|
+
metadata,
|
|
812
|
+
);
|
|
813
|
+
|
|
814
|
+
emitter.emit('transaction:broadcasted', trackedTx);
|
|
815
|
+
|
|
816
|
+
return result;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Common wrapper for raw transaction broadcasts.
|
|
821
|
+
*/
|
|
822
|
+
async function executeTrackedRawTransaction<R>(args: {
|
|
823
|
+
serializedTransaction: TransactionSerialized;
|
|
824
|
+
metadata: TMetadata;
|
|
825
|
+
execute: () => Promise<R>;
|
|
826
|
+
extractHash: (result: R) => Hash;
|
|
827
|
+
}): Promise<R> {
|
|
828
|
+
const {serializedTransaction, metadata, execute, extractHash} = args;
|
|
829
|
+
|
|
830
|
+
const {from, intendedNonce} = await extractRawTransactionContext(
|
|
831
|
+
serializedTransaction,
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
const result = await execute();
|
|
835
|
+
const hash = extractHash(result);
|
|
836
|
+
|
|
837
|
+
const trackedTx = createTrackedTransactionRecord(
|
|
838
|
+
hash,
|
|
839
|
+
from,
|
|
840
|
+
intendedNonce,
|
|
841
|
+
metadata,
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
emitter.emit('transaction:broadcasted', trackedTx);
|
|
845
|
+
|
|
846
|
+
return result;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
return {
|
|
850
|
+
walletClient: walletClient as unknown as WalletClient<
|
|
851
|
+
TTransport,
|
|
852
|
+
TChain,
|
|
853
|
+
TAccount
|
|
854
|
+
>,
|
|
855
|
+
publicClient,
|
|
856
|
+
|
|
857
|
+
// ============================================
|
|
858
|
+
// Async methods (return hash)
|
|
859
|
+
// ============================================
|
|
860
|
+
|
|
861
|
+
async writeContract<
|
|
862
|
+
const TAbi extends Abi | readonly unknown[],
|
|
863
|
+
TFunctionName extends ContractFunctionName<
|
|
864
|
+
TAbi,
|
|
865
|
+
'nonpayable' | 'payable'
|
|
866
|
+
>,
|
|
867
|
+
TArgs extends ContractFunctionArgs<
|
|
868
|
+
TAbi,
|
|
869
|
+
'nonpayable' | 'payable',
|
|
870
|
+
TFunctionName
|
|
871
|
+
>,
|
|
872
|
+
TChainOverride extends Chain | undefined = undefined,
|
|
873
|
+
>(
|
|
874
|
+
args: TrackedWriteContractAutoPopulateParameters<
|
|
875
|
+
TMetadata,
|
|
876
|
+
TAbi,
|
|
877
|
+
TFunctionName,
|
|
878
|
+
TArgs,
|
|
879
|
+
TChain,
|
|
880
|
+
TAccount,
|
|
881
|
+
TChainOverride
|
|
882
|
+
>,
|
|
883
|
+
): Promise<Hash> {
|
|
884
|
+
const {metadata: userMetadata, nonce, ...writeArgs} = args;
|
|
885
|
+
|
|
886
|
+
// Validate that user didn't provide operation, functionName or args
|
|
887
|
+
validateNoAutoPopulatedFieldsInMetadata(userMetadata);
|
|
888
|
+
|
|
889
|
+
// Auto-populate type, functionName and args
|
|
890
|
+
const finalMetadata = {
|
|
891
|
+
...(userMetadata ?? {}),
|
|
892
|
+
type: 'functionCall' as const,
|
|
893
|
+
functionName: args.functionName as string,
|
|
894
|
+
args: args.args as readonly unknown[],
|
|
895
|
+
} as TMetadata;
|
|
896
|
+
|
|
897
|
+
return executeTrackedTransaction({
|
|
898
|
+
account: normalizeAccount(args.account),
|
|
899
|
+
nonce,
|
|
900
|
+
metadata: finalMetadata,
|
|
901
|
+
restArgs: writeArgs,
|
|
902
|
+
execute: (argsWithNonce) =>
|
|
903
|
+
walletClient.writeContract(argsWithNonce as any),
|
|
904
|
+
extractHash: (hash) => hash,
|
|
905
|
+
});
|
|
906
|
+
},
|
|
907
|
+
|
|
908
|
+
async sendTransaction<
|
|
909
|
+
TChainOverride extends Chain | undefined = undefined,
|
|
910
|
+
>(
|
|
911
|
+
args: TrackedSendTransactionParameters<
|
|
912
|
+
TMetadata,
|
|
913
|
+
TChain,
|
|
914
|
+
TAccount,
|
|
915
|
+
TChainOverride
|
|
916
|
+
>,
|
|
917
|
+
): Promise<Hash> {
|
|
918
|
+
const {metadata, nonce, ...sendArgs} = args;
|
|
919
|
+
|
|
920
|
+
return executeTrackedTransaction({
|
|
921
|
+
account: normalizeAccount(args.account),
|
|
922
|
+
nonce,
|
|
923
|
+
metadata: metadata as TMetadata,
|
|
924
|
+
restArgs: sendArgs,
|
|
925
|
+
execute: (argsWithNonce) =>
|
|
926
|
+
walletClient.sendTransaction(argsWithNonce as any),
|
|
927
|
+
extractHash: (hash) => hash,
|
|
928
|
+
});
|
|
929
|
+
},
|
|
930
|
+
|
|
931
|
+
async sendRawTransaction(
|
|
932
|
+
args: TrackedRawTransactionParameters<TMetadata>,
|
|
933
|
+
): Promise<Hash> {
|
|
934
|
+
const {metadata, serializedTransaction} = args;
|
|
935
|
+
|
|
936
|
+
return executeTrackedRawTransaction({
|
|
937
|
+
serializedTransaction,
|
|
938
|
+
metadata: metadata as TMetadata,
|
|
939
|
+
execute: () =>
|
|
940
|
+
walletClient.sendRawTransaction({serializedTransaction}),
|
|
941
|
+
extractHash: (hash) => hash,
|
|
942
|
+
});
|
|
943
|
+
},
|
|
944
|
+
|
|
945
|
+
// ============================================
|
|
946
|
+
// Sync methods (return receipt, wait for confirmation)
|
|
947
|
+
// ============================================
|
|
948
|
+
|
|
949
|
+
async writeContractSync<
|
|
950
|
+
const TAbi extends Abi | readonly unknown[],
|
|
951
|
+
TFunctionName extends ContractFunctionName<
|
|
952
|
+
TAbi,
|
|
953
|
+
'nonpayable' | 'payable'
|
|
954
|
+
>,
|
|
955
|
+
TArgs extends ContractFunctionArgs<
|
|
956
|
+
TAbi,
|
|
957
|
+
'nonpayable' | 'payable',
|
|
958
|
+
TFunctionName
|
|
959
|
+
>,
|
|
960
|
+
TChainOverride extends Chain | undefined = undefined,
|
|
961
|
+
>(
|
|
962
|
+
args: TrackedWriteContractAutoPopulateParameters<
|
|
963
|
+
TMetadata,
|
|
964
|
+
TAbi,
|
|
965
|
+
TFunctionName,
|
|
966
|
+
TArgs,
|
|
967
|
+
TChain,
|
|
968
|
+
TAccount,
|
|
969
|
+
TChainOverride
|
|
970
|
+
>,
|
|
971
|
+
): Promise<TransactionReceipt> {
|
|
972
|
+
const {metadata: userMetadata, nonce, ...writeArgs} = args;
|
|
973
|
+
|
|
974
|
+
// Validate that user didn't provide operation, functionName or args
|
|
975
|
+
validateNoAutoPopulatedFieldsInMetadata(userMetadata);
|
|
976
|
+
|
|
977
|
+
// Auto-populate type, functionName and args
|
|
978
|
+
const finalMetadata = {
|
|
979
|
+
...(userMetadata ?? {}),
|
|
980
|
+
type: 'functionCall' as const,
|
|
981
|
+
functionName: args.functionName as string,
|
|
982
|
+
args: args.args as readonly unknown[],
|
|
983
|
+
} as TMetadata;
|
|
984
|
+
|
|
985
|
+
return executeTrackedTransaction({
|
|
986
|
+
account: normalizeAccount(args.account),
|
|
987
|
+
nonce,
|
|
988
|
+
metadata: finalMetadata,
|
|
989
|
+
restArgs: writeArgs,
|
|
990
|
+
execute: (argsWithNonce) =>
|
|
991
|
+
walletClient.writeContractSync(argsWithNonce as any),
|
|
992
|
+
extractHash: (receipt) => receipt.transactionHash,
|
|
993
|
+
});
|
|
994
|
+
},
|
|
995
|
+
|
|
996
|
+
async sendTransactionSync<
|
|
997
|
+
TChainOverride extends Chain | undefined = undefined,
|
|
998
|
+
>(
|
|
999
|
+
args: TrackedSendTransactionParameters<
|
|
1000
|
+
TMetadata,
|
|
1001
|
+
TChain,
|
|
1002
|
+
TAccount,
|
|
1003
|
+
TChainOverride
|
|
1004
|
+
>,
|
|
1005
|
+
): Promise<TransactionReceipt> {
|
|
1006
|
+
const {metadata, nonce, ...sendArgs} = args;
|
|
1007
|
+
|
|
1008
|
+
return executeTrackedTransaction({
|
|
1009
|
+
account: normalizeAccount(args.account),
|
|
1010
|
+
nonce,
|
|
1011
|
+
metadata: metadata as TMetadata,
|
|
1012
|
+
restArgs: sendArgs,
|
|
1013
|
+
execute: (argsWithNonce) =>
|
|
1014
|
+
walletClient.sendTransactionSync(argsWithNonce as any),
|
|
1015
|
+
extractHash: (receipt) => receipt.transactionHash,
|
|
1016
|
+
});
|
|
1017
|
+
},
|
|
1018
|
+
|
|
1019
|
+
async sendRawTransactionSync(
|
|
1020
|
+
args: TrackedRawTransactionParameters<TMetadata>,
|
|
1021
|
+
): Promise<TransactionReceipt> {
|
|
1022
|
+
const {metadata, serializedTransaction} = args;
|
|
1023
|
+
|
|
1024
|
+
return executeTrackedRawTransaction({
|
|
1025
|
+
serializedTransaction,
|
|
1026
|
+
metadata: metadata as TMetadata,
|
|
1027
|
+
execute: () =>
|
|
1028
|
+
walletClient.sendRawTransactionSync({serializedTransaction}),
|
|
1029
|
+
extractHash: (receipt) => receipt.transactionHash,
|
|
1030
|
+
});
|
|
1031
|
+
},
|
|
1032
|
+
|
|
1033
|
+
// ============================================
|
|
1034
|
+
// Event subscription methods
|
|
1035
|
+
// ============================================
|
|
1036
|
+
|
|
1037
|
+
onTransactionBroadcasted: (
|
|
1038
|
+
listener: (event: TrackedTransaction<TMetadata>) => void,
|
|
1039
|
+
) => emitter.on('transaction:broadcasted', listener),
|
|
1040
|
+
|
|
1041
|
+
offTransactionBroadcasted: (
|
|
1042
|
+
listener: (event: TrackedTransaction<TMetadata>) => void,
|
|
1043
|
+
) => emitter.off('transaction:broadcasted', listener),
|
|
1044
|
+
};
|
|
1045
|
+
},
|
|
1046
|
+
};
|
|
1047
|
+
}
|