@@ -2,40 +2,75 @@ import {
22 Contract ,
33 ContractRunner ,
44 Interface ,
5- InterfaceAbi ,
65 Provider ,
76 Signer ,
87 TransactionRequest ,
98 TransactionResponse ,
9+ assertArgument ,
1010} from 'ethers'
11+ import { SilentDataRollupContractConfig } from './types'
1112
1213/**
1314 * Custom contract runner that handles transaction submission
1415 * with proper nonce management. This ensures transactions are sent with
1516 * the latest nonce value to prevent transaction ordering issues.
1617 */
1718class CustomContractRunner implements ContractRunner {
18- provider : Provider | null
19+ provider : Provider
1920 private signer : Signer
2021
21- constructor ( signer : Signer ) {
22- this . provider = signer . provider
22+ constructor ( provider : Provider , signer : Signer ) {
23+ this . provider = provider
2324 this . signer = signer
2425 }
2526
2627 async sendTransaction ( tx : TransactionRequest ) : Promise < TransactionResponse > {
27- tx . nonce = await this . signer . getNonce ( )
28+ const signerAddress = await this . signer . getAddress ( )
29+ const latestNonce = await this . provider . getTransactionCount (
30+ signerAddress ,
31+ 'latest' ,
32+ )
33+ tx . nonce = latestNonce
2834 return this . signer . sendTransaction ( tx )
2935 }
3036}
3137
38+ function getContractRunner (
39+ runner : SilentDataRollupContractConfig [ 'runner' ] ,
40+ provider : SilentDataRollupContractConfig [ 'provider' ] ,
41+ ) : SilentDataRollupContractConfig [ 'runner' ] | CustomContractRunner {
42+ const runnerIsSigner = typeof runner . sendTransaction === 'function'
43+
44+ // If the runner is not a Signer return the runner as is
45+ if ( ! runnerIsSigner ) {
46+ return runner
47+ }
48+
49+ // Get the runner provider constructor name
50+ const runnerProviderConstructor = runner . provider ?. constructor . name ?? ''
51+
52+ /**
53+ * If the runner provider is not part of the Silent Data Rollup providers
54+ * we check if the provider is provided and create a new CustomContractRunner
55+ * with the provider and signer
56+ */
57+ if ( ! runnerProviderConstructor . includes ( 'SilentDataRollupProvider' ) ) {
58+ assertArgument ( provider , 'provider is mandatory' , 'provider' , provider )
59+
60+ return new CustomContractRunner ( provider , runner as Signer )
61+ }
62+
63+ /**
64+ * If the runner provider is part of the Silent Data Rollup providers
65+ * we create a new CustomContractRunner with the runner provider and signer
66+ */
67+ return new CustomContractRunner ( runner . provider as Provider , runner as Signer )
68+ }
69+
3270export class SilentDataRollupContract extends Contract {
33- constructor (
34- address : string ,
35- abi : InterfaceAbi ,
36- runner : ContractRunner ,
37- contractMethodsToSign : string [ ] ,
38- ) {
71+ constructor ( config : SilentDataRollupContractConfig ) {
72+ const { address, abi, runner, contractMethodsToSign, provider } = config
73+
3974 /**
4075 * Validates that all methods specified for signing exist in the contract ABI.
4176 * This check ensures that only legitimate contract functions are marked for signing,
@@ -50,20 +85,12 @@ export class SilentDataRollupContract extends Contract {
5085 }
5186 } )
5287
53- const baseProvider =
54- ( runner as any ) . baseProvider || ( runner as any ) . provider ?. baseProvider
88+ const contractRunner = getContractRunner ( runner , provider )
5589
56- /**
57- * If the runner is a Signer, create a CustomContractRunner to handle
58- * transaction submission with proper nonce management.
59- */
60- const runnerIsSigner = typeof ( runner as any ) . sendTransaction === 'function'
61- if ( runnerIsSigner ) {
62- runner = new CustomContractRunner ( runner as Signer )
63- }
64-
65- super ( address , abi , runner )
90+ super ( address , abi , contractRunner )
6691
92+ const baseProvider =
93+ ( runner as any ) . baseProvider || ( runner as any ) . provider ?. baseProvider
6794 if ( typeof baseProvider ?. setContract === 'function' ) {
6895 baseProvider . setContract ( this , contractMethodsToSign )
6996 }
0 commit comments