diff --git a/packages/web3-eth-contract/CHANGELOG.md b/packages/web3-eth-contract/CHANGELOG.md index ce09d2e910f..7c165a0eeb5 100644 --- a/packages/web3-eth-contract/CHANGELOG.md +++ b/packages/web3-eth-contract/CHANGELOG.md @@ -216,6 +216,10 @@ const transactionHash = receipt.transactionHash; ## [Unreleased] +### Fixed + +- Fix contract defaults (#5756) + ### Changed - Update imports statements for objects that was moved between web3 packages (#5771) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 8d98b118a42..c7081683107 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -15,7 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { Web3Context, Web3EventEmitter, Web3PromiEvent } from 'web3-core'; +import { Web3Context, Web3EventEmitter, Web3PromiEvent, Web3ConfigEvent } from 'web3-core'; import { ContractExecutionError, SubscriptionError, Web3ContractError } from 'web3-errors'; import { createAccessList, @@ -57,7 +57,6 @@ import { HexString, LogsInput, Mutable, - Common, } from 'web3-types'; import { DataFormat, @@ -213,69 +212,9 @@ export class Contract public readonly options: ContractOptions; /** - * Can be used to set {@link Contract.defaultAccount} for all contracts. + * Set to true if you want contracts' defaults to sync with global defaults. */ - public static defaultAccount?: HexString; - - /** - * Can be used to set {@link Contract.defaultBlock} for all contracts. - */ - public static defaultBlock?: BlockNumberOrTag; - - /** - * Can be used to set {@link Contract.defaultHardfork} for all contracts. - */ - public static defaultHardfork?: string; - - /** - * Can be used to set {@link Contract.defaultCommon} for all contracts. - */ - public static defaultCommon?: Common; - - /** - * Can be used to set {@link Contract.transactionSendTimeout} for all contracts. - */ - public static transactionSendTimeout?: number; - - /** - * Can be used to set {@link Contract.transactionBlockTimeout} for all contracts. - */ - public static transactionBlockTimeout?: number; - - /** - * Can be used to set {@link Contract.transactionConfirmationBlocks} for all contracts. - */ - public static transactionConfirmationBlocks?: number; - - /** - * Can be used to set {@link Contract.transactionPollingInterval} for all contracts. - */ - public static transactionPollingInterval?: number; - - /** - * Can be used to set {@link Contract.transactionPollingTimeout} for all contracts. - */ - public static transactionPollingTimeout?: number; - - /** - * Can be used to set {@link Contract.transactionReceiptPollingInterval} for all contracts. - */ - public static transactionReceiptPollingInterval?: number; - - /** - * Can be used to set {@link Contract.transactionConfirmationPollingInterval} for all contracts. - */ - public static transactionConfirmationPollingInterval?: number; - - /** - * Can be used to set {@link Contract.blockHeaderTimeout} for all contracts. - */ - public static blockHeaderTimeout?: number; - - /** - * Can be used to set {@link Contract.handleRevert} for all contracts. - */ - public static handleRevert?: boolean; + public syncWithContext = false; private _errorsInterface!: AbiErrorFragment[]; private _jsonInterface!: ContractAbiWithSignature; @@ -292,6 +231,7 @@ export class Contract private _methods!: ContractMethodsInterface; private _events!: ContractEventsInterface; + private context?: Web3Context; /** * Creates a new contract instance with all its methods and events defined in its {@doclink glossary/json_interface | json interface} object. * @@ -420,6 +360,8 @@ export class Contract data: options?.data, }; + this.syncWithContext = (options as ContractInitOptions)?.syncWithContext ?? false; + Object.defineProperty(this.options, 'address', { set: (value: Address) => this._parseAndSetAddress(value, returnDataFormat), get: () => this._address, @@ -431,131 +373,6 @@ export class Contract }); } - public get defaultAccount() { - return (this.constructor as typeof Contract).defaultAccount ?? super.defaultAccount; - } - - public set defaultAccount(value: Address | undefined) { - super.defaultAccount = value; - } - - public get defaultBlock() { - return (this.constructor as typeof Contract).defaultBlock ?? super.defaultBlock; - } - - public set defaultBlock(value: BlockNumberOrTag) { - super.defaultBlock = value; - } - - public get defaultHardfork() { - return (this.constructor as typeof Contract).defaultHardfork ?? super.defaultHardfork; - } - - public set defaultHardfork(value: string) { - super.defaultHardfork = value; - } - - public get defaultCommon(): Common | undefined { - return (this.constructor as typeof Contract).defaultCommon ?? super.defaultCommon; - } - - public set defaultCommon(value: Common | undefined) { - super.defaultCommon = value; - } - - public get transactionSendTimeout() { - return ( - (this.constructor as typeof Contract).transactionSendTimeout ?? - super.transactionSendTimeout - ); - } - - public set transactionSendTimeout(value: number) { - super.transactionSendTimeout = value; - } - - public get transactionBlockTimeout() { - return ( - (this.constructor as typeof Contract).transactionBlockTimeout ?? - super.transactionBlockTimeout - ); - } - - public set transactionBlockTimeout(value: number) { - super.transactionBlockTimeout = value; - } - - public get transactionConfirmationBlocks() { - return ( - (this.constructor as typeof Contract).transactionConfirmationBlocks ?? - super.transactionConfirmationBlocks - ); - } - - public set transactionConfirmationBlocks(value: number) { - super.transactionConfirmationBlocks = value; - } - - public get transactionPollingInterval() { - return ( - (this.constructor as typeof Contract).transactionPollingInterval ?? - super.transactionPollingInterval - ); - } - - public set transactionPollingInterval(value: number) { - super.transactionPollingInterval = value; - } - - public get transactionPollingTimeout() { - return ( - (this.constructor as typeof Contract).transactionPollingTimeout ?? - super.transactionPollingTimeout - ); - } - - public set transactionPollingTimeout(value: number) { - super.transactionPollingTimeout = value; - } - - public get transactionReceiptPollingInterval() { - return ( - (this.constructor as typeof Contract).transactionReceiptPollingInterval ?? - super.transactionReceiptPollingInterval - ); - } - - public set transactionReceiptPollingInterval(value: number | undefined) { - super.transactionReceiptPollingInterval = value; - } - - public get transactionConfirmationPollingInterval() { - return ( - (this.constructor as typeof Contract).transactionConfirmationPollingInterval ?? - super.transactionConfirmationPollingInterval - ); - } - - public set transactionConfirmationPollingInterval(value: number | undefined) { - super.transactionConfirmationPollingInterval = value; - } - - public get blockHeaderTimeout() { - return (this.constructor as typeof Contract).blockHeaderTimeout ?? super.blockHeaderTimeout; - } - - public set blockHeaderTimeout(value: number) { - super.blockHeaderTimeout = value; - } - - public get handleRevert() { - return (this.constructor as typeof Contract).handleRevert ?? super.handleRevert; - } - - public set handleRevert(value: boolean) { - super.handleRevert = value; - } - /** * Subscribe to an event. * @@ -633,8 +450,10 @@ export class Contract * ``` */ public clone() { + let newContract: Contract; + if (this.options.address) { - return new Contract( + newContract = new Contract( [...this._jsonInterface, ...this._errorsInterface] as unknown as Abi, this.options.address, { @@ -644,23 +463,28 @@ export class Contract from: this.options.from, data: this.options.data, provider: this.currentProvider, + syncWithContext: this.syncWithContext, + }, + this.getContextObject(), + ); + } else { + newContract = new Contract( + [...this._jsonInterface, ...this._errorsInterface] as unknown as Abi, + { + gas: this.options.gas, + gasPrice: this.options.gasPrice, + gasLimit: this.options.gasLimit, + from: this.options.from, + data: this.options.data, + provider: this.currentProvider, + syncWithContext: this.syncWithContext, }, this.getContextObject(), ); } + if (this.context) newContract.subscribeToContextEvents(this.context); - return new Contract( - [...this._jsonInterface, ...this._errorsInterface] as unknown as Abi, - { - gas: this.options.gas, - gasPrice: this.options.gasPrice, - gasLimit: this.options.gasLimit, - from: this.options.from, - data: this.options.data, - provider: this.currentProvider, - }, - this.getContextObject(), - ); + return newContract; } /** @@ -772,6 +596,7 @@ export class Contract // modifiedOptions.to = '0x0000000000000000000000000000000000000000'; delete modifiedOptions.to; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return this._contractMethodDeploySend( abi as AbiFunctionFragment, args as unknown[], @@ -1330,4 +1155,16 @@ export class Contract return sub; }; } + + protected subscribeToContextEvents(context: T): void { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const contractThis = this; + this.context = context; + + if (contractThis.syncWithContext) { + context.on(Web3ConfigEvent.CONFIG_CHANGE, event => { + contractThis.setConfig({ [event.name]: event.newValue }); + }); + } + } } diff --git a/packages/web3-eth-contract/src/types.ts b/packages/web3-eth-contract/src/types.ts index 2a7110ef2f7..6e43d3ce045 100644 --- a/packages/web3-eth-contract/src/types.ts +++ b/packages/web3-eth-contract/src/types.ts @@ -152,6 +152,10 @@ export interface ContractInitOptions { readonly data?: Bytes; readonly gasLimit?: Uint; readonly provider?: SupportedProviders | string; + /** + * If `true`, the defaults of the contract instance will be updated automatically based on the changes of the context used to instantiate the contract. + */ + readonly syncWithContext?: boolean; } export interface NonPayableCallOptions { diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 2e1073067c1..d07eafe8a61 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -30,6 +30,7 @@ import { PayableCallOptions, ContractOptions, Web3ContractContext, + ContractInitOptions, } from './types'; export const getSendTxParams = ({ @@ -138,12 +139,19 @@ export const getEstimateGasParams = ({ return txParams as TransactionWithSenderAPI; }; -export const isContractInitOptions = (options: unknown): options is ContractOptions => +export const isContractInitOptions = (options: unknown): options is ContractInitOptions => typeof options === 'object' && !isNullish(options) && - ['data', 'from', 'gas', 'gasPrice', 'gasLimit', 'address', 'jsonInterface'].some( - key => key in options, - ); + [ + 'data', + 'from', + 'gas', + 'gasPrice', + 'gasLimit', + 'address', + 'jsonInterface', + 'syncWithContext', + ].some(key => key in options); export const isWeb3ContractContext = (options: unknown): options is Web3ContractContext => typeof options === 'object' && !isNullish(options) && !isContractInitOptions(options); diff --git a/packages/web3-eth-contract/test/integration/contract_defaults.test.ts b/packages/web3-eth-contract/test/integration/contract_defaults.test.ts index 488058ef282..5e631e69ba9 100644 --- a/packages/web3-eth-contract/test/integration/contract_defaults.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_defaults.test.ts @@ -41,72 +41,37 @@ describe('contract', () => { sendOptions = { from: acc.address, gas: '1000000' }; }); - describe('defaultAccount', () => { - it('should use "defaultAccount" on "Contract" level instead of "from"', async () => { - // eslint-disable-next-line prefer-destructuring - Contract.defaultAccount = acc.address; - - const receiptHandler = jest.fn(); - - // We didn't specify "from" in this call - await contract - .deploy(deployOptions) - .send({ gas: '1000000' }) - .on('receipt', receiptHandler); - - // We didn't specify "from" in this call - // eslint-disable-next-line jest/no-standalone-expect - expect(receiptHandler).toHaveBeenCalledWith( - expect.objectContaining({ from: acc.address }), - ); - }); - - it('should use "defaultAccount" on "instance" level instead of "from"', async () => { - const deployedContract = await contract.deploy(deployOptions).send(sendOptions); - Contract.defaultAccount = undefined; - // eslint-disable-next-line prefer-destructuring - deployedContract.defaultAccount = acc.address; - // We didn't specify "from" in this call - const receipt = await deployedContract.methods - .setGreeting('New Greeting') - .send({ gas: '1000000' }); - expect(receipt.from).toEqual(acc.address); - }); - - it('should throw error when "from" is not set on any level', () => { - Contract.defaultAccount = undefined; - contract.defaultAccount = undefined; - - expect(() => contract.deploy(deployOptions).send({ gas: '1000000' })).toThrow( - 'Contract "from" address not specified', - ); - }); + it('should use "defaultAccount" on "instance" level instead of "from"', async () => { + const deployedContract = await contract.deploy(deployOptions).send(sendOptions); + // eslint-disable-next-line prefer-destructuring + deployedContract.defaultAccount = acc.address; + // We didn't specify "from" in this call + const receipt = await deployedContract.methods + .setGreeting('New Greeting') + .send({ gas: '1000000' }); + expect(receipt.from).toEqual(acc.address); }); - describe('defaultBlock', () => { - it('should use "defaultBlock" on "Contract" level', async () => { - contract = await contract.deploy(deployOptions).send(sendOptions); - - await contract.methods.setGreeting('New Greeting').send(sendOptions); + it('should throw error when "from" is not set on any level', () => { + contract.defaultAccount = undefined; - const requestSpy = jest.spyOn( - contract.currentProvider as Web3BaseProvider, - 'request', - ); - Contract.defaultBlock = 'pending'; + expect(() => contract.deploy(deployOptions).send({ gas: '1000000' })).toThrow( + 'Contract "from" address not specified', + ); + }); - // Forcefully delete this property from the contract instance - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - contract.defaultBlock = undefined; + it('should set syncWithContext from init options', async () => { + contract = new Contract(GreeterAbi, { + provider: getSystemTestProvider(), + syncWithContext: true, + }); - await contract.methods.greet().call(); + contract = await contract.deploy(deployOptions).send(sendOptions); - expect(requestSpy).toHaveBeenCalledWith( - expect.objectContaining({ params: [expect.any(Object), 'pending'] }), - ); - }); + expect(contract.syncWithContext).toBeTruthy(); + }); + describe('defaultBlock', () => { it('should use "defaultBlock" on "instance" level', async () => { contract = await contract.deploy(deployOptions).send(sendOptions); @@ -117,7 +82,6 @@ describe('contract', () => { 'request', ); contract.defaultBlock = 'pending'; - Contract.defaultBlock = undefined; await contract.methods.greet().call(); @@ -140,7 +104,6 @@ describe('contract', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error contract.defaultBlock = undefined; - Contract.defaultBlock = undefined; await contract.methods.greet().call(undefined, 'pending'); diff --git a/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts b/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts index 00b9f6d4cda..da5bbf143e8 100644 --- a/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts @@ -26,6 +26,7 @@ import { describeIf, isWs, isHttp, + closeOpenConnection, } from '../fixtures/system_test_utils'; type Resolve = (value?: unknown) => void; @@ -48,17 +49,6 @@ describe('contract defaults (extra)', () => { let acc: { address: string; privateKey: string }; beforeEach(async () => { - Contract.defaultCommon = undefined; - Contract.transactionBlockTimeout = undefined; - Contract.blockHeaderTimeout = undefined; - Contract.transactionConfirmationBlocks = undefined; - Contract.transactionPollingTimeout = undefined; - Contract.transactionPollingInterval = undefined; - Contract.handleRevert = undefined; - - contract = new Contract(GreeterAbi, undefined, { - provider: getSystemTestProvider(), - }); acc = await createTempAccount(); deployOptions = { @@ -69,66 +59,52 @@ describe('contract defaults (extra)', () => { sendOptions = { from: acc.address, gas: '1000000' }; }); - describe('defaultHardfork', () => { - it('should use "defaultHardfork" on "Contract" level', async () => { - const hardfork = 'berlin'; - - Contract.defaultHardfork = hardfork; - - // const sendTransactionSpy = jest.spyOn(Web3Eth, 'sendTransaction'); - - contract = await contract.deploy(deployOptions).send(sendOptions); - - expect(contract.defaultHardfork).toBe(hardfork); - - await contract.methods.greet().call(); + afterEach(async () => { + await closeOpenConnection(contract); + }); - await contract.methods.setGreeting('New Greeting').send(sendOptions); + it('should use "defaultHardfork" on "instance" level', async () => { + const hardfork = 'berlin'; - // todo investigate. this fails, too - // expect(sendTransactionSpy).toHaveBeenCalledWith( - // expect.objectContaining({ - // _config: expect.objectContaining({ defaultHardfork: hardfork }), - // }), - // expect.any(Object), - // expect.any(Object), - // ); + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), }); - it('should use "defaultHardfork" on "instance" level', async () => { - const hardfork = 'berlin'; - contract.defaultHardfork = hardfork; + contract = await contract.deploy(deployOptions).send(sendOptions); + contract.defaultHardfork = hardfork; - contract = await contract.deploy(deployOptions).send(sendOptions); - - await contract.methods.setGreeting('New Greeting').send(sendOptions); - await contract.methods.greet().send(sendOptions); + await contract.methods.setGreeting('New Greeting').send(sendOptions); + await contract.methods.greet().send(sendOptions); - expect(contract.defaultHardfork).toBe(hardfork); - const callSpy = jest.spyOn(Web3Eth, 'call'); + expect(contract.defaultHardfork).toBe(hardfork); + const callSpy = jest.spyOn(Web3Eth, 'call'); - await contract.methods.greet().call(); + await contract.methods.greet().call(); - expect(callSpy).toHaveBeenLastCalledWith( - expect.objectContaining({ - _config: expect.objectContaining({ defaultHardfork: hardfork }), - }), - expect.any(Object), - undefined, - expect.any(Object), - ); - }); + expect(callSpy).toHaveBeenLastCalledWith( + expect.objectContaining({ + _config: expect.objectContaining({ defaultHardfork: hardfork }), + }), + expect.any(Object), + undefined, + expect.any(Object), + ); }); describe('defaultChain', () => { it('should use "defaultChain" on "instance" level', async () => { + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + }); + + contract = await contract.deploy(deployOptions).send(sendOptions); + expect(contract.defaultChain).toBe('mainnet'); const defaultChain = 'ropsten'; contract.defaultChain = defaultChain; - expect(contract.defaultChain).toBe(defaultChain); - contract = await contract.deploy(deployOptions).send(sendOptions); + expect(contract.defaultChain).toBe(defaultChain); await contract.methods.setGreeting('New Greeting').send(sendOptions); @@ -156,14 +132,6 @@ describe('contract defaults (extra)', () => { }; beforeEach(async () => { - Contract.defaultCommon = undefined; - Contract.transactionBlockTimeout = undefined; - Contract.blockHeaderTimeout = undefined; - Contract.transactionConfirmationBlocks = undefined; - Contract.transactionPollingTimeout = undefined; - Contract.transactionPollingInterval = undefined; - Contract.handleRevert = undefined; - contract = new Contract(GreeterAbi, undefined, { provider: getSystemTestProvider(), }); @@ -179,25 +147,6 @@ describe('contract defaults (extra)', () => { contract = await contract.deploy(deployOptions).send(sendOptions); }); - // todo this test fails, seems like a bug. any thoughts? - // it('should use "defaultCommon" on "Contract" level', async () => { - // Contract.defaultCommon = common; - - // const sendTransactionSpy = jest.spyOn(Web3Eth, 'sendTransaction'); - - // expect(contract.defaultCommon).toMatchObject(common); - - // await contract.methods.setGreeting('New Greeting').send(sendOptions); - - // expect(sendTransactionSpy).toHaveBeenLastCalledWith( - // expect.objectContaining({ - // _config: expect.objectContaining({ defaultCommon: common }), - // }), - // expect.any(Object), - // expect.any(Object), - // ); - // }); - it('should use "defaultCommon" on "instance" level', async () => { contract.defaultCommon = common; const callSpy = jest.spyOn(Web3Eth, 'call'); @@ -214,10 +163,15 @@ describe('contract defaults (extra)', () => { ); }); }); + describeIf(isWs)('transactionBlockTimeout', () => { it('should use "transactionBlockTimeout" on "instance" level', async () => { + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + }); contract = await contract.deploy(deployOptions).send(sendOptions); + const sendTransactionSpy = jest.spyOn(Web3Eth, 'sendTransaction'); expect(contract.transactionBlockTimeout).toBe(50); contract.transactionBlockTimeout = 32; @@ -225,9 +179,20 @@ describe('contract defaults (extra)', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-call await contract.methods.setGreeting('New Greeting').send(sendOptions); + + expect(sendTransactionSpy).toHaveBeenLastCalledWith( + expect.objectContaining({ + _config: expect.objectContaining({ transactionBlockTimeout: 32 }), + }), + expect.any(Object), + expect.any(Object), + ); }); it('should fail if transaction was not mined within `transactionBlockTimeout` blocks', async () => { + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + }); contract = await contract.deploy(deployOptions).send(sendOptions); // Make the test run faster by casing the polling to start after 2 blocks @@ -275,18 +240,11 @@ describe('contract defaults (extra)', () => { }); describeIf(isWs)('blockHeaderTimeout', () => { - it('should use "blockHeaderTimeout" on "Contract" level', async () => { - expect(Contract.blockHeaderTimeout).toBeUndefined(); - const blockHeaderTimeout = 100; - Contract.blockHeaderTimeout = blockHeaderTimeout; - - expect(Contract.blockHeaderTimeout).toBe(blockHeaderTimeout); - contract = await contract.deploy(deployOptions).send(sendOptions); - - expect(contract.blockHeaderTimeout).toBe(blockHeaderTimeout); - }); - it('should use "blockHeaderTimout" on "instance" level', async () => { + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + }); + contract = await contract.deploy(deployOptions).send(sendOptions); expect(contract.blockHeaderTimeout).toBe(10); @@ -329,18 +287,11 @@ describe('contract defaults (extra)', () => { }); describeIf(isHttp)('transactionPollingInterval', () => { - it('should use "transactionPollingInterval" on "Contract" level', async () => { - contract = await contract.deploy(deployOptions).send(sendOptions); - - expect(Contract.transactionPollingInterval).toBeUndefined(); - - const transactionPollingInterval = 500; - Contract.transactionPollingInterval = transactionPollingInterval; - - expect(contract.transactionPollingInterval).toBe(transactionPollingInterval); - }); - it('should use "transactionPollingTimeout" on "instance" level', async () => { + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + }); + contract = await contract.deploy(deployOptions).send(sendOptions); const transactionPollingInterval = 500; @@ -350,41 +301,24 @@ describe('contract defaults (extra)', () => { }); }); - describe('handleRevert', () => { - it('should use "handleRevert" on "Contract" level', async () => { - contract = await contract.deploy(deployOptions).send(sendOptions); - - expect(Contract.handleRevert).toBeUndefined(); - - expect(contract.handleRevert).toBeFalsy(); - - const handleRevert = true; - Contract.handleRevert = handleRevert; - - expect(contract.handleRevert).toBe(handleRevert); - - const sendTransactionSpy = jest.spyOn(Web3Eth, 'sendTransaction'); - - await contract.methods.setGreeting('New Greeting').send(sendOptions); - - expect(sendTransactionSpy).toHaveBeenCalled(); + it('should use "handleRevert" on "instance" level', async () => { + contract = new Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), }); - it('should use "handleRevert" on "instance" level', async () => { - contract = await contract.deploy(deployOptions).send(sendOptions); + contract = await contract.deploy(deployOptions).send(sendOptions); - expect(contract.handleRevert).toBeFalsy(); + expect(contract.handleRevert).toBeFalsy(); - const handleRevert = true; - contract.handleRevert = handleRevert; + const handleRevert = true; + contract.handleRevert = handleRevert; - expect(contract.handleRevert).toBe(handleRevert); + expect(contract.handleRevert).toBe(handleRevert); - const sendTransactionSpy = jest.spyOn(Web3Eth, 'sendTransaction'); + const sendTransactionSpy = jest.spyOn(Web3Eth, 'sendTransaction'); - await contract.methods.setGreeting('New Greeting').send(sendOptions); + await contract.methods.setGreeting('New Greeting').send(sendOptions); - expect(sendTransactionSpy).toHaveBeenCalled(); - }); + expect(sendTransactionSpy).toHaveBeenCalled(); }); }); diff --git a/packages/web3/src/web3.ts b/packages/web3/src/web3.ts index 3a615910eb9..49371c9aebd 100644 --- a/packages/web3/src/web3.ts +++ b/packages/web3/src/web3.ts @@ -87,6 +87,8 @@ export class Web3 extends Web3Context { } else { super(jsonInterface, self.getContextObject()); } + + super.subscribeToContextEvents(self); } } diff --git a/packages/web3/test/integration/web3.test.ts b/packages/web3/test/integration/web3.test.ts index af4fef27a54..c831cbd164a 100644 --- a/packages/web3/test/integration/web3.test.ts +++ b/packages/web3/test/integration/web3.test.ts @@ -33,6 +33,7 @@ import { isWs, waitForOpenConnection, } from '../shared_fixtures/system_tests_utils'; +import { GreeterAbi, GreeterBytecode } from '../shared_fixtures/build/Greeter'; describe('Web3 instance', () => { let clientUrl: string; @@ -255,4 +256,54 @@ describe('Web3 instance', () => { ); }); }); + + describe('defaults', () => { + let contract: Contract; + let deployOptions: Record; + let sendOptions: Record; + let acc: { address: string; privateKey: string }; + + beforeAll(() => { + web3 = new Web3(clientUrl); + }); + + beforeEach(async () => { + acc = await createTempAccount(); + + // todo import GreeterBytecode + deployOptions = { + data: GreeterBytecode, + arguments: ['My Greeting'], + }; + + sendOptions = { from: acc.address, gas: '1000000' }; + }); + + it('should update defaults on contract instance', () => { + const hardfork = 'berlin'; + + contract = new web3.eth.Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + syncWithContext: true, + }); + + web3.defaultHardfork = hardfork; + + expect(contract.defaultHardfork).toBe(hardfork); + }); + + it('should update defaults on deployed contract instance', async () => { + const hardfork = 'berlin'; + + contract = new web3.eth.Contract(GreeterAbi, undefined, { + provider: getSystemTestProvider(), + syncWithContext: true, + }); + contract = await contract.deploy(deployOptions).send(sendOptions); + + web3.defaultHardfork = hardfork; + + expect(contract.defaultHardfork).toBe(hardfork); + }); + }); });