diff --git a/package.json b/package.json index 23c2ee1..8a81189 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "web3-plugin-zksync", - "version": "1.0.7", + "version": "1.0.8", "description": "web3.js plugin for ZkSync", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/contract-factory.ts b/src/contract-factory.ts index f200543..f430f1c 100644 --- a/src/contract-factory.ts +++ b/src/contract-factory.ts @@ -14,6 +14,7 @@ import { import type { DeploymentType, TransactionRequest } from './types'; import { AccountAbstractionVersion } from './types'; import type { ZKsyncWallet } from './zksync-wallet'; +import { SmartAccount } from './smart-account'; interface CustomData { factoryDeps?: (string | { object: string })[]; @@ -38,7 +39,7 @@ export class ContractFactory extends Web3Context { */ readonly bytecode!: string; - readonly zkWallet: ZKsyncWallet; + readonly zkWallet: ZKsyncWallet | SmartAccount; /** The deployment type that is currently in use. */ readonly deploymentType: DeploymentType; @@ -55,7 +56,7 @@ export class ContractFactory extends Web3Context { constructor( abi: Abi, bytecode: web3Types.Bytes, - zkWallet: ZKsyncWallet, + zkWallet: ZKsyncWallet | SmartAccount, deploymentType?: DeploymentType, ) { super(zkWallet.provider); @@ -89,16 +90,29 @@ export class ContractFactory extends Web3Context { bytecodeHash: web3Types.Bytes, constructorCalldata: web3Types.Bytes, ): string { - const contractDeploymentArgs = [salt, web3Utils.bytesToHex(bytecodeHash), constructorCalldata]; - const accountDeploymentArgs = [...contractDeploymentArgs, AccountAbstractionVersion.Version1]; + const contractDeploymentArgs = [ + salt, + web3Utils.bytesToHex(bytecodeHash), + constructorCalldata, + ]; + const accountDeploymentArgs = [ + ...contractDeploymentArgs, + AccountAbstractionVersion.Version1, + ]; switch (this.deploymentType) { case 'create': - return ContractDeployerContract.methods.create(...contractDeploymentArgs).encodeABI(); + return ContractDeployerContract.methods + .create(...contractDeploymentArgs) + .encodeABI(); case 'createAccount': - return ContractDeployerContract.methods.createAccount(...accountDeploymentArgs).encodeABI(); + return ContractDeployerContract.methods + .createAccount(...accountDeploymentArgs) + .encodeABI(); case 'create2': - return ContractDeployerContract.methods.create2(...contractDeploymentArgs).encodeABI(); + return ContractDeployerContract.methods + .create2(...contractDeploymentArgs) + .encodeABI(); case 'create2Account': return ContractDeployerContract.methods .create2Account(...accountDeploymentArgs) @@ -123,7 +137,10 @@ export class ContractFactory extends Web3Context { throw new Error('Salt is required for CREATE2 deployment!'); } - if (!overrides.customData.salt.startsWith('0x') || overrides.customData.salt.length !== 66) { + if ( + !overrides.customData.salt.startsWith('0x') || + overrides.customData.salt.length !== 66 + ) { throw new Error('Invalid salt provided!'); } } @@ -146,14 +163,15 @@ export class ContractFactory extends Web3Context { let constructorArgs: any[]; // The overrides will be popped out in this call: - const txRequest: web3Types.TransactionCall & { customData?: any } = this.contractToBeDeployed - .deploy({ - data: this.bytecode, - arguments: args, - }) - .populateTransaction({ - from: this.zkWallet.getAddress() ?? this.defaultAccount ?? undefined, - }); + const txRequest: web3Types.TransactionCall & { customData?: any } = + this.contractToBeDeployed + .deploy({ + data: this.bytecode, + arguments: args, + }) + .populateTransaction({ + from: this.zkWallet.getAddress() ?? this.defaultAccount ?? undefined, + }); this.checkOverrides(overrides); let overridesCopy: Overrides = overrides ?? { diff --git a/src/plugin.ts b/src/plugin.ts index 5ddfd24..f186307 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -23,6 +23,7 @@ import { ECDSASmartAccount, MultisigECDSASmartAccount, SmartAccount } from './sm interface ZKsyncWalletConstructor { new (privateKey: string): ZKsyncWallet; + createRandom: () => ZKsyncWallet; } interface ZKsyncAccountConstructor { new (signer: SmartAccountSigner): SmartAccount; @@ -90,10 +91,14 @@ export class ZKsyncPlugin extends Web3PluginBase { * const PRIVATE_KEY = ""; * const zkWallet = new web3.ZKsync.ZkWallet(PRIVATE_KEY); */ - // the wallet type in this class is different from the parent class. So, they should have different names. + + // @ts-ignore - Initialized in the initWallet method which called in the constructor Wallet: ZKsyncWalletConstructor; + // @ts-ignore - Initialized in the initWallet method which called in the constructor SmartAccount: ZKsyncAccountConstructor; + // @ts-ignore - Initialized in the initWallet method which called in the constructor ECDSASmartAccount: ZKsyncECDSASmartAccountConstructor; + // @ts-ignore - Initialized in the initWallet method which called in the constructor MultisigECDSASmartAccount: ZKsyncMultisigECDSASmartAccountConstructor; /** * Create a new ZKsync plugin for the provided L2 network @@ -107,7 +112,10 @@ export class ZKsyncPlugin extends Web3PluginBase { | Web3ZKsyncL2, ) { super( - providerOrContextL2 as string | web3Types.SupportedProviders | Web3ContextInitOptions, + providerOrContextL2 as + | string + | web3Types.SupportedProviders + | Web3ContextInitOptions, ); if (providerOrContextL2 instanceof Web3ZKsyncL2) { this.L2 = providerOrContextL2; @@ -118,32 +126,6 @@ export class ZKsyncPlugin extends Web3PluginBase { this._l2BridgeContracts = {}; this._erc20Contracts = {}; - const self = this; - class ZKsyncWalletWithFullContext extends ZKsyncWallet { - constructor(privateKey: string) { - super(privateKey, self.L2, self.L1); - } - } - class ZKsyncAccountWithFullContext extends SmartAccount { - constructor(signer: SmartAccountSigner) { - super(signer, self.L2); - } - } - class ZKsyncECDSASmartAccountWithFullContext { - static create(address: string, secret: string): SmartAccount { - return ECDSASmartAccount.create(address, secret, self.L2); - } - } - class ZKsyncMultisigECDSASmartAccountWithFullContext extends MultisigECDSASmartAccount { - static create(address: string, secret: string[]): SmartAccount { - return MultisigECDSASmartAccount.create(address, secret, self.L2); - } - } - - this.Wallet = ZKsyncWalletWithFullContext; - this.SmartAccount = ZKsyncAccountWithFullContext; - this.ECDSASmartAccount = ZKsyncECDSASmartAccountWithFullContext; - this.MultisigECDSASmartAccount = ZKsyncMultisigECDSASmartAccountWithFullContext; this.initWallet(); } @@ -158,8 +140,12 @@ export class ZKsyncPlugin extends Web3PluginBase { ); } - const { mainContract, bridgehubContractAddress, l1SharedDefaultBridge, l2SharedDefaultBridge } = - await this.ContractsAddresses; + const { + mainContract, + bridgehubContractAddress, + l1SharedDefaultBridge, + l2SharedDefaultBridge, + } = await this.ContractsAddresses; const contractsCollection: ZKSyncContractsCollection = { Generic: { @@ -177,8 +163,16 @@ export class ZKsyncPlugin extends Web3PluginBase { constants.CONTRACT_DEPLOYER_ADDRESS, this.L2, ), - L1MessengerContract: new Contract(IL1MessengerABI, constants.L1_MESSENGER_ADDRESS, this.L2), - NonceHolderContract: new Contract(INonceHolderABI, constants.NONCE_HOLDER_ADDRESS, this.L2), + L1MessengerContract: new Contract( + IL1MessengerABI, + constants.L1_MESSENGER_ADDRESS, + this.L2, + ), + NonceHolderContract: new Contract( + INonceHolderABI, + constants.NONCE_HOLDER_ADDRESS, + this.L2, + ), L2BridgeContract: new Contract(IL2BridgeABI, l2SharedDefaultBridge, this.L2), }, }; @@ -217,13 +211,34 @@ export class ZKsyncPlugin extends Web3PluginBase { private initWallet() { const self = this; - class ZKSyncWalletWithFullContext extends ZKsyncWallet { + class ZKsyncWalletWithFullContext extends ZKsyncWallet { constructor(privateKey: string) { super(privateKey, self.L2, self.L1); } + static override createRandom() { + return ZKsyncWallet.createRandom(self.L2, self.L1); + } + } + class ZKsyncAccountWithFullContext extends SmartAccount { + constructor(signer: SmartAccountSigner) { + super(signer, self.L2); + } + } + class ZKsyncECDSASmartAccountWithFullContext { + static create(address: string, secret: string): SmartAccount { + return ECDSASmartAccount.create(address, secret, self.L2); + } + } + class ZKsyncMultisigECDSASmartAccountWithFullContext extends MultisigECDSASmartAccount { + static create(address: string, secret: string[]): SmartAccount { + return MultisigECDSASmartAccount.create(address, secret, self.L2); + } } - this.Wallet = ZKSyncWalletWithFullContext; + this.SmartAccount = ZKsyncAccountWithFullContext; + this.ECDSASmartAccount = ZKsyncECDSASmartAccountWithFullContext; + this.MultisigECDSASmartAccount = ZKsyncMultisigECDSASmartAccountWithFullContext; + this.Wallet = ZKsyncWalletWithFullContext; } /** @@ -231,7 +246,9 @@ export class ZKsyncPlugin extends Web3PluginBase { */ get rpc(): RpcMethods { if (!this._rpc) { - this._rpc = new RpcMethods(this.L2.requestManager as unknown as Web3RequestManager); + this._rpc = new RpcMethods( + this.L2.requestManager as unknown as Web3RequestManager, + ); } return this._rpc; } @@ -246,8 +263,16 @@ export class ZKsyncPlugin extends Web3PluginBase { * For example, if the L1 or L2 providers were changed from testnet to mainnet, this method should be called. */ public updateProviders( - contextL1: Web3ZKsyncL1 | web3Types.SupportedProviders | Web3ContextInitOptions | string, - contextL2: Web3ZKsyncL2 | web3Types.SupportedProviders | Web3ContextInitOptions | string, + contextL1: + | Web3ZKsyncL1 + | web3Types.SupportedProviders + | Web3ContextInitOptions + | string, + contextL2: + | Web3ZKsyncL2 + | web3Types.SupportedProviders + | Web3ContextInitOptions + | string, ) { this.L1 = contextL1 instanceof Web3ZKsyncL1 ? contextL1 : new Web3ZKsyncL1(contextL1); this.L2 = contextL2 instanceof Web3ZKsyncL2 ? contextL2 : new Web3ZKsyncL2(contextL2); @@ -294,7 +319,9 @@ export class ZKsyncPlugin extends Web3PluginBase { return l1Token; } } catch (e) { - throw new Error(`Error getting L1 address for token ${token}. ${JSON.stringify(e)}`); + throw new Error( + `Error getting L1 address for token ${token}. ${JSON.stringify(e)}`, + ); } } @@ -320,7 +347,9 @@ export class ZKsyncPlugin extends Web3PluginBase { return l2WethToken; } } catch (e) { - throw new Error(`Error getting L2 address for token ${token}. ${JSON.stringify(e)}`); + throw new Error( + `Error getting L2 address for token ${token}. ${JSON.stringify(e)}`, + ); } } diff --git a/src/web3zksync.ts b/src/web3zksync.ts index 31d288f..41b1e53 100644 --- a/src/web3zksync.ts +++ b/src/web3zksync.ts @@ -241,4 +241,7 @@ export class Web3ZkSync extends Web3.Web3 { async sendRawTransaction(signedTx: string) { return ethRpcMethods.sendRawTransaction(this.requestManager, signedTx); } + async sendTransaction(tx: TransactionRequest) { + return this.eth.sendTransaction(tx as Transaction); + } } diff --git a/src/zksync-wallet.ts b/src/zksync-wallet.ts index df1490c..220a30f 100644 --- a/src/zksync-wallet.ts +++ b/src/zksync-wallet.ts @@ -1,7 +1,7 @@ import type { Web3Account } from 'web3-eth-accounts'; import { privateKeyToAccount, create as createAccount } from 'web3-eth-accounts'; import type * as web3Types from 'web3-types'; -import type { Web3ZKsyncL2 } from './web3zksync-l2'; +import { Web3ZKsyncL2 } from './web3zksync-l2'; import type { Web3ZKsyncL1 } from './web3zksync-l1'; import { AdapterL1, AdapterL2 } from './adapters'; import { @@ -58,7 +58,8 @@ class Adapters extends AdapterL1 { * Capabilities for integrating, creating, and managing ZKsync wallets. */ export class ZKsyncWallet extends Adapters { - provider?: Web3ZKsyncL2; + // @ts-ignore - Property 'provider' assigned in the connect method which called in the constructor. + provider: Web3ZKsyncL2; providerL1?: Web3ZKsyncL1; public account: Web3Account; /** @@ -92,9 +93,7 @@ export class ZKsyncWallet extends Adapters { super(); this.account = privateKeyToAccount(privateKey); - if (providerL2) { - this.connect(providerL2); - } + this.connect(providerL2 ?? new Web3ZKsyncL2()); if (providerL1) { this.connectToL1(providerL1); } diff --git a/test/local/wallet.test.ts b/test/local/wallet.test.ts index 1ff79cc..b0defe8 100644 --- a/test/local/wallet.test.ts +++ b/test/local/wallet.test.ts @@ -1002,7 +1002,7 @@ describe('Wallet', () => { try { await wallet.signTransaction({ type: EIP712_TX_TYPE, - from: ADDRESS2, + from: accounts[4].address, to: ADDRESS2, value: 1, });