import { ethers } from 'ethers'; import { Interface } from 'ethers/lib/utils'; import config from '../config/config'; import { ChainId } from '../config/constants'; export abstract class ContractInitializer { abstract readonly className: string; protected contractAddress: ReturnType; private _instance?: ethers.Contract; public address: string = ''; private _provider: | ethers.providers.JsonRpcSigner | ethers.providers.Provider; private _chainConfig: ReturnType; get chainConfig(): NonNullable> { if (!this._chainConfig) { throw new Error('Chain config is not initialized'); } return this._chainConfig; } get provider() { return this._provider; } // TODO change string to some enum? constructor( private chainId: string, private iface: Interface, provider?: ethers.providers.JsonRpcSigner | ethers.providers.Provider ) { const chainConfig = config.getChainConfig(this.chainId as ChainId); if (!chainConfig) { throw new Error('Invalid chainId: ' + this.chainId); } this.contractAddress = config.getSystemData(chainId); this._chainConfig = chainConfig; const newProvider = provider || new ethers.providers.JsonRpcProvider(this.chainConfig.rpcUrl); if (!newProvider) { throw new Error('Cannot get provider for chainId ' + this.chainId); } this._provider = newProvider; } initialize() { if (!this.address) { throw new Error('Contract address is not set'); } this.contractInstance = new ethers.Contract( this.address, this.iface, this._provider ) as unknown as T; } get contractInstance(): T { if (!this._instance) { throw new Error('Contract is not initialized'); } return this._instance as unknown as T; } protected set contractInstance(instance: T) { this._instance = instance as unknown as ethers.Contract; } protected get signer(): ethers.providers.JsonRpcSigner { if (!this._provider) { throw new Error('Signer is not initialized'); } if (!(this._provider as ethers.providers.JsonRpcSigner)._isSigner) { throw new Error('Signer is not initialized'); } return this._provider as ethers.providers.JsonRpcSigner; } logCall(method: string, params: any) { ContractInitializer.logCall(this.className, method, params); } private static logCall(scope: string, method: string, params: any) { console.debug( `[${scope}] Calling ${method} with params: ${JSON.stringify( params, (key, value) => { if (typeof value === 'string') { if (value.startsWith('0x') && value.length > 42) { return value.slice(0, 42) + '...'; } } return value; } )}` ); } }