diff --git a/docs/docs/guides/basics/sign_and_send_tx/local_wallet.md b/docs/docs/guides/basics/sign_and_send_tx/local_wallet.md index 59b93c8b638..ec1410dd46d 100644 --- a/docs/docs/guides/basics/sign_and_send_tx/local_wallet.md +++ b/docs/docs/guides/basics/sign_and_send_tx/local_wallet.md @@ -23,8 +23,7 @@ const { Web3 } = require('web3'); const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to wallet -const privateKeyString = '0x1f953dc9b6437fb94fcafa5dabe3faa0c34315b954dd66f41bf53273339c6d26'; -const account = web3.eth.accounts.wallet.add(privateKeyString).get(0); +const account = web3.eth.accounts.wallet.add("privateKey").get(0); // Make sure the account has enough eth on balance to send the transaction @@ -62,7 +61,7 @@ import { Web3 } from 'web3'; const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to wallet -const privateKeyString = '0x1f953dc9b6437fb94fcafa5dabe3faa0c34315b954dd66f41bf53273339c6d26'; +const privateKeyString = 'privateKey'; const account = web3.eth.accounts.wallet.add(privateKeyString).get(0); // Make sure the account has enough eth on balance to send the transaction @@ -111,7 +110,7 @@ const { Web3 } = require('web3'); const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to wallet -const privateKeyString = '0x1f953dc9b6437fb94fcafa5dabe3faa0c34315b954dd66f41bf53273339c6d26'; +const privateKeyString = 'privateKey'; const account = web3.eth.accounts.wallet.add(privateKeyString).get(0); // Make sure the account has enough eth on balance to send the transaction @@ -160,13 +159,19 @@ async function deploy() { + ```typescript + +:::warning +Using `web3.eth.personal` web3.eth.personal is not considered secure and is strongly discouraged. The personal RPC endpoints have been deprecated due to significant security issues. +::: + // First step: initialize `web3` instance import { Web3 } from 'web3'; const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to wallet -const privateKeyString = '0x1f953dc9b6437fb94fcafa5dabe3faa0c34315b954dd66f41bf53273339c6d26'; +const privateKeyString = 'privateKey'; const account = web3.eth.accounts.wallet.add(privateKeyString).get(0); // Make sure the account has enough eth on balance to send the transaction diff --git a/docs/docs/guides/basics/sign_and_send_tx/promi_event.md b/docs/docs/guides/basics/sign_and_send_tx/promi_event.md index 3d2403b4c46..b1372bb315f 100644 --- a/docs/docs/guides/basics/sign_and_send_tx/promi_event.md +++ b/docs/docs/guides/basics/sign_and_send_tx/promi_event.md @@ -71,7 +71,7 @@ web3.eth.sendTransaction({...}) // at Generator.next () // at fulfilled (.../web3_request_manager.js:5:58) // at processTicksAndRejections (node:internal/process/task_queues:96:5) { - // innerError: { code: -32000, message: 'exceeds block gas limit' }, + // cause: { code: -32000, message: 'exceeds block gas limit' }, // code: 101, // data: undefined, // request: { diff --git a/docs/docs/guides/basics/sign_and_send_tx/wallet_of_eth_node.md b/docs/docs/guides/basics/sign_and_send_tx/wallet_of_eth_node.md index 7a1905b4bc4..fa2e89a3c8e 100644 --- a/docs/docs/guides/basics/sign_and_send_tx/wallet_of_eth_node.md +++ b/docs/docs/guides/basics/sign_and_send_tx/wallet_of_eth_node.md @@ -24,7 +24,7 @@ const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to the Ethereum node and unlock it const account = { - privateKey: '0xb45b02f408a0dd0996aab2b55a54f4ed7735f82b133c0786a9ff372ffaaf11bd', + privateKey: 'privateKey', address: '0xe4beef667408b99053dc147ed19592ada0d77f59', }; @@ -64,7 +64,7 @@ const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to the Ethereum node and unlock it const account = { - privateKey: '0xb45b02f408a0dd0996aab2b55a54f4ed7735f82b133c0786a9ff372ffaaf11bd', + privateKey: 'privateKey', address: '0xe4beef667408b99053dc147ed19592ada0d77f59', }; @@ -116,7 +116,7 @@ const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to the Ethereum node and unlock it const account = { - privateKey: '0xb45b02f408a0dd0996aab2b55a54f4ed7735f82b133c0786a9ff372ffaaf11bd', + privateKey: 'privateKey', address: '0xe4beef667408b99053dc147ed19592ada0d77f59', }; @@ -170,7 +170,7 @@ const web3 = new Web3(/* PROVIDER*/); // Second step: add an account to the Ethereum node and unlock it const account = { - privateKey: '0xb45b02f408a0dd0996aab2b55a54f4ed7735f82b133c0786a9ff372ffaaf11bd', + privateKey: 'privateKey', address: '0xe4beef667408b99053dc147ed19592ada0d77f59', }; diff --git a/docs/docs/guides/wallet/index.md b/docs/docs/guides/wallet/index.md new file mode 100644 index 00000000000..d83af238a72 --- /dev/null +++ b/docs/docs/guides/wallet/index.md @@ -0,0 +1,266 @@ +--- +sidebar_position: 6 +sidebar_label: 'Web3 Wallet' +--- + +# web3.js Wallet Guide + +## Introduction + +The web3-eth-accounts package contains functions to generate Ethereum accounts and sign transactions and data. + +:::tip +In Ethereum, a private key is a crucial component of the cryptographic key pair used for securing and controlling ownership of Ethereum addresses. Ethereum uses a public-key cryptography system, where each Ethereum address has a corresponding pair of public and private keys. This key pair will allow you to have ownership associated with the ethereum address, store and access funds and send transactions. + +Be sure to have your private key stored and encrypted in a safe place, as losing or sharing it may result in permament loss of access to the asscoiated Ethereum address and funds. + +To generate a private key: `const privateKey = web3.eth.accounts.create().privateKey;` + +Learn more about wallets [here](https://ethereum.org/en/wallets/) +::: + + +## web3-eth-accounts + +### Methods + +The following is a list of web3-eth-account [methods]( /api/web3-eth-accounts/class/Wallet#Methods) with descriptions and examples of usage: + +- [create](https://docs.web3js.org/libdocs/Accounts#create) +- [privateKeytoAccount](https://docs.web3js.org/libdocs/Accounts#privatekeytoaccount) +- [privateKeytoAddress](https://docs.web3js.org/libdocs/Accounts#privatekeytoaddress) +- [privateKeytoPublicKey](https://docs.web3js.org/libdocs/Accounts#privatekeytopublickey) +- [parseAndValidatePrivateKey](https://docs.web3js.org/libdocs/Accounts#parseandvalidateprivatekey) +- [sign](https://docs.web3js.org/libdocs/Accounts#sign) +- [signTransaction](https://docs.web3js.org/libdocs/Accounts#signtransaction) +- [recoverTransaction](https://docs.web3js.org/libdocs/Accounts#recovertransaction) +- [hashMessage](https://docs.web3js.org/libdocs/Accounts#hashmessage) +- [recover](https://docs.web3js.org/libdocs/Accounts#recover) +- [encrypt](https://docs.web3js.org/libdocs/Accounts#encrypt) +- [decrypt](https://docs.web3js.org/libdocs/Accounts#decrypt) + + +### Creating a Web3Account with the web3-eth-accounts package and signing a message + + +``` ts +import { create } from 'web3-eth-accounts'; + + +// the create method returns a Web3Account object. It contains an address and private key and allows you to be able to encrypt, sign and signTransaction. +const account = create(); +{ +address: '0xbD504f977021b5E5DdccD8741A368b147B3B38bB', +privateKey: 'privateKey', +signTransaction: [Function: signTransaction], +sign: [Function: sign], +encrypt: [AsyncFunction: encrypt] +} + +account.sign("hello world"); +{ + message: 'hello world', + messageHash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', + v: '0x1b', + r: '0xe4fce466ef18f6cd8b4f4175a9a04cd2872a1a6a8cfc2ff67fb0cfd6d78ec758', + s: '0x37ca3a789976f1854d16e50a04caf2e06ee14b0ac4a5878b43929767f2008288', + signature: '0xe4fce466ef18f6cd8b4f4175a9a04cd2872a1a6a8cfc2ff67fb0cfd6d78ec75837ca3a789976f1854d16e50a04caf2e06ee14b0ac4a5878b43929767f20082881b' +} + +``` +### Import a private key and sign a transaction with the web3 package + +``` ts +import Web3 from 'web3'; + +const web3 = new Web3("provider"); + +const account = web3.eth.accounts.privateKeyToAccount("privateKey"); + +signedTransaction = await account.signTransaction({ + from: a.address, + to: '0xe4beef667408b99053dc147ed19592ada0d77f59', + value: '0x1', + gas: '300000', + gasPrice: await web3.eth.getGasPrice() + }) +> { + messageHash: '0xfad22c3ab5ecbb6eec934a21243ee1866fbbd3786f4e8e8ec631b917ef65174d', + v: '0xf4f6', + r: '0xc0035636d9417f63fdd418bc545190e59b58a4ff921bbf4efebf352dac211f11', + s: '0x4944d746ff12c7bca41f77c8f7d75301cea8b205e021dfde34d09d5bdccc713d', + rawTransaction: '0xf866808477359400830493e094e4beef667408b99053dc147ed19592ada0d77f59018082f4f6a0c0035636d9417f63fdd418bc545190e59b58a4ff921bbf4efebf352dac211f11a04944d746ff12c7bca41f77c8f7d75301cea8b205e021dfde34d09d5bdccc713d', + transactionHash: '0xa3fed275c97abc4a160cd9bef3ec90206686f32821a8fd4e01a04130bff35c1a' +} + +``` +### Local wallets + +Local wallets are an in-memory [wallet](/api/web3-eth-accounts/class/Wallet/) that can hold multiple accounts. +Wallets are a convenient way to sign and send transactions in web3.js. + +:::warning + +If used within the browser, wallets are not saved anywhere and disappear when the page is refreshed. +If used within your application, wallets will disappear after the program is completed. + +::: + +### Methods + +The following is a list of Wallet [methods]( /api/web3-eth-accounts/class/Wallet#Methods) in the web3-eth-accounts package with description and example usage: + +- [add]( /api/web3-eth-accounts/class/Wallet/#add) +- [clear]( /api/web3-eth-accounts/class/Wallet/#clear) +- [create]( /api/web3-eth-accounts/class/Wallet/#create) +- [decrypt]( /api/web3-eth-accounts/class/Wallet/#decrypt) +- [encrypt]( /api/web3-eth-accounts/class/Wallet/#encrypt) +- [get]( /api/web3-eth-accounts/class/Wallet/#get) +- [load]( /api/web3-eth-accounts/class/Wallet/#load) +- [remove]( /api/web3-eth-accounts/class/Wallet/#remove) +- [save]( /api/web3-eth-accounts/class/Wallet/#save) +- [getStorage]( /api/web3-eth-accounts/class/Wallet/#getStorage) + + +## Creating a local wallet + +```ts + +// creating a new wallet +web3.eth.accounts.create() +> Wallet(0) [ + _accountProvider: { + create: [Function: createWithContext], + privateKeyToAccount: [Function: privateKeyToAccountWithContext], + decrypt: [Function: decryptWithContext] + }, + _addressMap: Map(0) {}, + _defaultKeyName: 'web3js_wallet' +] + +// add a wallet using a private key +web3.eth.accounts.wallet.add("PrivateKey"); +``` + +## Signing a message using a wallet + +``` ts + +import Web3 from 'web3'; + +web3.eth.accounts.wallet.create(1); + +const message = web3.utils.utf8ToHex('Hello world'); // sign only takes hexstrings, so turn message to hexstring +web3.eth.sign(message, 0).then(console.log); // 0 refers to using the first index of the wallet to sign the message +> { + message: '0x48656c6c6f20776f726c64', + messageHash: '0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede', + v: '0x1c', + r: '0x3a420906f331896cb5db1366cdaeef1f0b14f9f71d72c178e87b76f8b31f3f36', + s: '0x32ffccc78638c1d7e46dbf16041ddaef90ab50a85eeeaa46f8c496a39237831a', + signature: '0x3a420906f331896cb5db1366cdaeef1f0b14f9f71d72c178e87b76f8b31f3f3632ffccc78638c1d7e46dbf16041ddaef90ab50a85eeeaa46f8c496a39237831a1c' +} +``` + +## Browser injection - Sending a transaction with Metamask + +This is an example html file that will send a transaction when the button element is clicked. + +To run this example you'll need Metamask, the `index.html` file below in your folder and you'll need a local server: + +`npm i http-server` + +`npx http-server` + +Afterwards your file will be served on a local port, which will usually be on `http://127.0.0.1:8080` + +### index.html +``` html + + + + + + + + Send Transaction Example + + + + + + + + + + +``` + +## Sending a transaction using a local wallet with contract methods + +``` ts +// First step: initialize `web3` instance +import { Web3 } from 'web3'; +const web3 = new Web3(/* PROVIDER*/); + +// Second step: add an account to wallet +const privateKeyString = 'Private key'; +const account = web3.eth.accounts.wallet.add(privateKeyString).get(0); + +// Make sure the account has enough eth on balance to send the transaction + +// fill ContractAbi and ContractBytecode with your contract's abi and bytecode + +async function contractMethod() { + try { + + // add the contract details of which method you want to call, using the contract abi and contract address + const contract = new web3.eth.Contract(ContractAbi, "contract address"); + + // call contract method and send + await contractDeployed.methods + .method('0xe2597eb05cf9a87eb1309e86750c903ec38e527e') + .send({ + from: account?.address, + gas: '1000000', + // other transaction's params + }); + } catch (error) { + // catch transaction error + console.error(error); + } +} + +(async () => { + await contractMethod(); +})(); + +``` \ No newline at end of file diff --git a/packages/web3-core/src/web3_context.ts b/packages/web3-core/src/web3_context.ts index f4c72f9ab61..76afcaf8875 100644 --- a/packages/web3-core/src/web3_context.ts +++ b/packages/web3-core/src/web3_context.ts @@ -103,7 +103,7 @@ export class Web3Context< | Web3ContextInitOptions, ) { super(); - + // If "providerOrContext" is provided as "string" or an objects matching "SupportedProviders" interface if ( isNullish(providerOrContext) || @@ -364,7 +364,7 @@ export class Web3Context< /** * This method allows extending the web3 modules. - * Note: This method is only for backward compatibility, and It is recommended to use Web3 v4 Plugin feature for extending web3.js functionality if you are developing some thing new. + * Note: This method is only for backward compatibility, and It is recommended to use Web3 v4 Plugin feature for extending web3.js functionality if you are developing something new. */ public extend(extendObj: ExtensionObject) { // @ts-expect-error No index signature with a parameter of type 'string' was found on type 'Web3Context' @@ -407,36 +407,39 @@ export class Web3Context< * class CustomPlugin extends Web3PluginBase {...} * ``` */ - export abstract class Web3PluginBase< - API extends Web3APISpec = Web3APISpec, +export abstract class Web3PluginBase< + API extends Web3APISpec = Web3APISpec, > extends Web3Context { - public abstract pluginNamespace: string; + public abstract pluginNamespace: string; - // eslint-disable-next-line class-methods-use-this - protected registerNewTransactionType>(type: Numbers, txClass: NewTxTypeClass): void { - TransactionFactory.registerTransactionType(type, txClass); - } + // eslint-disable-next-line class-methods-use-this + protected registerNewTransactionType>( + type: Numbers, + txClass: NewTxTypeClass, + ): void { + TransactionFactory.registerTransactionType(type, txClass); + } } /** -* Extend this class when creating a plugin that makes use of {@link EthExecutionAPI}, -* or depends on other Web3 packages (such as `web3-eth-contract`) that depend on {@link EthExecutionAPI}. -* -* To add type support for RPC methods to the {@link Web3RequestManager} (in addition to {@link EthExecutionAPI}), -* define a {@link Web3APISpec} and pass it as a generic to Web3PluginBase like so: -* -* @example -* ```ts -* type CustomRpcApi = { -* custom_rpc_method: () => string; -* custom_rpc_method_with_parameters: (parameter1: string, parameter2: number) => string; -* }; -* -* class CustomPlugin extends Web3PluginBase {...} -* ``` -*/ + * Extend this class when creating a plugin that makes use of {@link EthExecutionAPI}, + * or depends on other Web3 packages (such as `web3-eth-contract`) that depend on {@link EthExecutionAPI}. + * + * To add type support for RPC methods to the {@link Web3RequestManager} (in addition to {@link EthExecutionAPI}), + * define a {@link Web3APISpec} and pass it as a generic to Web3PluginBase like so: + * + * @example + * ```ts + * type CustomRpcApi = { + * custom_rpc_method: () => string; + * custom_rpc_method_with_parameters: (parameter1: string, parameter2: number) => string; + * }; + * + * class CustomPlugin extends Web3PluginBase {...} + * ``` + */ export abstract class Web3EthPluginBase extends Web3PluginBase< - API & EthExecutionAPI + API & EthExecutionAPI > {} // To avoid cycle dependency declare this type in this file diff --git a/packages/web3-core/test/unit/web3_request_manager.test.ts b/packages/web3-core/test/unit/web3_request_manager.test.ts index 21483ef13a2..375e27a5d1e 100644 --- a/packages/web3-core/test/unit/web3_request_manager.test.ts +++ b/packages/web3-core/test/unit/web3_request_manager.test.ts @@ -688,7 +688,7 @@ describe('Web3RequestManager', () => { err = error; } finally { expect(err).toBeInstanceOf(ResponseError); - expect(err.innerError).toEqual(rpcErrorResponse.error); + expect(err.cause).toEqual(rpcErrorResponse.error); } }); }); diff --git a/packages/web3-errors/src/error_codes.ts b/packages/web3-errors/src/error_codes.ts index c9ff68f6d7f..1db99b30ea7 100644 --- a/packages/web3-errors/src/error_codes.ts +++ b/packages/web3-errors/src/error_codes.ts @@ -28,6 +28,7 @@ export const ERR_OPERATION_ABORT = 204; export const ERR_ABI_ENCODING = 205; export const ERR_EXISTING_PLUGIN_NAMESPACE = 206; export const ERR_INVALID_METHOD_PARAMS = 207; +export const ERR_MULTIPLE_ERRORS = 208; // Contract error codes export const ERR_CONTRACT = 300; diff --git a/packages/web3-errors/src/errors/contract_errors.ts b/packages/web3-errors/src/errors/contract_errors.ts index 98a38245da6..3710d9f60f0 100644 --- a/packages/web3-errors/src/errors/contract_errors.ts +++ b/packages/web3-errors/src/errors/contract_errors.ts @@ -132,7 +132,7 @@ export type ProviderErrorData = | { originalError: { data: HexString } }; /** - * This class is expected to be set as an `innerError` inside ContractExecutionError + * This class is expected to be set as an `cause` inside ContractExecutionError * The properties would be typically decoded from the `data` if it was encoded according to EIP-838 */ export class Eip838ExecutionError extends Web3ContractError { @@ -144,7 +144,7 @@ export class Eip838ExecutionError extends Web3ContractError { public errorArgs?: { [K in string]: unknown }; // eslint-disable-next-line no-use-before-define - public innerError: Eip838ExecutionError | undefined; + public cause: Eip838ExecutionError | undefined; public constructor(error: JsonRpcError | Eip838ExecutionError) { super(error.message || 'Error'); @@ -166,9 +166,7 @@ export class Eip838ExecutionError extends Web3ContractError { originalError = error.data; } this.data = originalError.data; - this.innerError = new Eip838ExecutionError( - originalError as JsonRpcError, - ); + this.cause = new Eip838ExecutionError(originalError as JsonRpcError); } else { this.data = error.data; } @@ -192,7 +190,8 @@ export class Eip838ExecutionError extends Web3ContractError { name: string; code: number; message: string; - innerError: Error | Error[] | undefined; + innerError: Eip838ExecutionError | undefined; + cause: Eip838ExecutionError | undefined; data: string; errorName?: string; errorSignature?: string; @@ -216,12 +215,12 @@ export class Eip838ExecutionError extends Web3ContractError { * The data is expected to be encoded according to EIP-848. */ export class ContractExecutionError extends Web3ContractError { - public innerError: Eip838ExecutionError; + public cause: Eip838ExecutionError; public constructor(rpcError: JsonRpcError) { super('Error happened while trying to execute a function inside a smart contract'); this.code = ERR_CONTRACT_EXECUTION_REVERTED; - this.innerError = new Eip838ExecutionError(rpcError as JsonRpcError); + this.cause = new Eip838ExecutionError(rpcError as JsonRpcError); } } diff --git a/packages/web3-errors/src/errors/response_errors.ts b/packages/web3-errors/src/errors/response_errors.ts index 95d08b91ad6..9fb1f09e172 100644 --- a/packages/web3-errors/src/errors/response_errors.ts +++ b/packages/web3-errors/src/errors/response_errors.ts @@ -22,7 +22,7 @@ import { JsonRpcResponse, JsonRpcResponseWithError, } from 'web3-types'; -import { BaseWeb3Error } from '../web3_error_base.js'; +import { BaseWeb3Error, MultipleErrors } from '../web3_error_base.js'; import { ERR_INVALID_RESPONSE, ERR_RESPONSE } from '../error_codes.js'; // To avoid circular package dependency, copied to code here. If you update this please update same function in `json_rpc.ts` @@ -71,10 +71,14 @@ export class ResponseError extends B if (`error` in response) { errorOrErrors = response.error as JsonRpcError; } else if (response instanceof Array) { - errorOrErrors = response.map(r => r.error) as JsonRpcError[]; + errorOrErrors = response.filter(r => r.error).map(r => r.error) as JsonRpcError[]; } - this.innerError = errorOrErrors as Error | Error[] | undefined; + if (Array.isArray(errorOrErrors) && errorOrErrors.length > 0) { + this.cause = new MultipleErrors(errorOrErrors as unknown as Error[]); + } else { + this.cause = errorOrErrors as Error | undefined; + } } public toJSON() { @@ -98,7 +102,10 @@ export class InvalidResponseError ex } else if (result instanceof Array) { errorOrErrors = result.map(r => r.error) as JsonRpcError[]; } - - this.innerError = errorOrErrors as Error | Error[] | undefined; + if (Array.isArray(errorOrErrors)) { + this.cause = new MultipleErrors(errorOrErrors as unknown as Error[]); + } else { + this.cause = errorOrErrors as Error | undefined; + } } -} +} \ No newline at end of file diff --git a/packages/web3-errors/src/errors/transaction_errors.ts b/packages/web3-errors/src/errors/transaction_errors.ts index 69c56378724..9a62750142f 100644 --- a/packages/web3-errors/src/errors/transaction_errors.ts +++ b/packages/web3-errors/src/errors/transaction_errors.ts @@ -341,7 +341,7 @@ export class MissingGasError extends InvalidValueError { }`, '"gas" is missing', ); - this.innerError = new MissingGasInnerError(); + this.cause = new MissingGasInnerError(); } } @@ -372,7 +372,7 @@ export class TransactionGasMismatchError extends InvalidValueError { }`, 'transaction must specify legacy or fee market gas properties, not both', ); - this.innerError = new TransactionGasMismatchInnerError(); + this.cause = new TransactionGasMismatchInnerError(); } } diff --git a/packages/web3-errors/src/web3_error_base.ts b/packages/web3-errors/src/web3_error_base.ts index 72a6fd01731..40e96c3eda6 100644 --- a/packages/web3-errors/src/web3_error_base.ts +++ b/packages/web3-errors/src/web3_error_base.ts @@ -18,16 +18,50 @@ along with web3.js. If not, see . /* eslint-disable max-classes-per-file */ import { Web3Error } from 'web3-types'; +import { ERR_MULTIPLE_ERRORS } from './error_codes.js'; +/** + * Base class for Web3 errors. + */ export abstract class BaseWeb3Error extends Error implements Web3Error { public readonly name: string; public abstract readonly code: number; public stack: string | undefined; - public innerError: Error | Error[] | undefined; - public constructor(msg?: string, innerError?: Error | Error[]) { + public cause: Error | undefined; + + /** + * @deprecated Use the `cause` property instead. + */ + public get innerError(): Error | Error[] | undefined { + // eslint-disable-next-line no-use-before-define + if (this.cause instanceof MultipleErrors) { + return this.cause.errors; + } + return this.cause; + } + /** + * @deprecated Use the `cause` property instead. + */ + public set innerError(cause: Error | Error[] | undefined) { + if (Array.isArray(cause)) { + // eslint-disable-next-line no-use-before-define + this.cause = new MultipleErrors(cause); + } else { + this.cause = cause; + } + } + + public constructor(msg?: string, cause?: Error | Error[]) { super(msg); - this.innerError = innerError; + + if (Array.isArray(cause)) { + // eslint-disable-next-line no-use-before-define + this.cause = new MultipleErrors(cause); + } else { + this.cause = cause; + } + this.name = this.constructor.name; if (typeof Error.captureStackTrace === 'function') { @@ -57,11 +91,23 @@ export abstract class BaseWeb3Error extends Error implements Web3Error { name: this.name, code: this.code, message: this.message, - innerError: this.innerError, + cause: this.cause, + // deprecated + innerError: this.cause, }; } } +export class MultipleErrors extends BaseWeb3Error { + public code = ERR_MULTIPLE_ERRORS; + public errors: Error[]; + + public constructor(errors: Error[]) { + super(`Multiple errors occurred: [${errors.map(e => e.message).join('], [')}]`); + this.errors = errors; + } +} + export abstract class InvalidValueError extends BaseWeb3Error { public readonly name: string; diff --git a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap index ab49d6aaa0a..5cfb35158c7 100644 --- a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap +++ b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap @@ -2,6 +2,7 @@ exports[`errors ConnectionCloseError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 504, "errorCode": 10, "errorReason": "reason", @@ -13,6 +14,7 @@ Object { exports[`errors ConnectionError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 500, "errorCode": 10, "errorReason": "reason", @@ -24,6 +26,7 @@ Object { exports[`errors ConnectionNotOpenError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 503, "errorCode": 10, "errorReason": "reason", @@ -35,6 +38,7 @@ Object { exports[`errors ConnectionTimeoutError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 502, "duration": 5000, "errorCode": undefined, @@ -47,6 +51,7 @@ Object { exports[`errors ContractCodeNotStoredError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 404, "innerError": undefined, "message": "The contract code couldn't be stored, please check your gas limit.", @@ -59,6 +64,7 @@ Object { exports[`errors ContractEventDoesNotExistError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 304, "eventName": "eventName", "innerError": undefined, @@ -69,6 +75,7 @@ Object { exports[`errors ContractMissingABIError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 302, "innerError": undefined, "message": "You must provide the json interface of the contract when instantiating a contract object.", @@ -78,6 +85,7 @@ Object { exports[`errors ContractMissingDeployDataError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 306, "innerError": undefined, "message": "No \\"data\\" specified in neither the given options, nor the default options.", @@ -87,6 +95,7 @@ Object { exports[`errors ContractNoAddressDefinedError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 307, "innerError": undefined, "message": "This contract object doesn't have address set yet, please set an address first.", @@ -96,6 +105,7 @@ Object { exports[`errors ContractNoFromAddressDefinedError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 308, "innerError": undefined, "message": "No \\"from\\" address specified in neither the given options, nor the default options.", @@ -105,6 +115,7 @@ Object { exports[`errors ContractOnceRequiresCallbackError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 303, "innerError": undefined, "message": "Once requires a callback as the second parameter.", @@ -114,6 +125,7 @@ Object { exports[`errors ContractReservedEventError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 305, "innerError": undefined, "message": "Event \\"type\\" doesn't exist in this contract.", @@ -124,6 +136,7 @@ Object { exports[`errors Eip838ExecutionError should get the data from error.data.data 1`] = ` Object { + "cause": [Eip838ExecutionError: Error], "code": undefined, "data": "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000", "innerError": [Eip838ExecutionError: Error], @@ -134,6 +147,7 @@ Object { exports[`errors Eip838ExecutionError should get the data from error.data.originalError.data 1`] = ` Object { + "cause": [Eip838ExecutionError: Error], "code": undefined, "data": "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000", "innerError": [Eip838ExecutionError: Error], @@ -144,6 +158,7 @@ Object { exports[`errors InvalidConnectionError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 501, "errorCode": 10, "errorReason": "reason", @@ -156,6 +171,7 @@ Object { exports[`errors InvalidNumberOfParamsError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 200, "expected": 20, "got": 10, @@ -168,6 +184,7 @@ Object { exports[`errors InvalidPropertiesForTransactionTypeError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 439, "innerError": undefined, "message": "The following properties are invalid for the transaction type 0x0: property", @@ -177,6 +194,7 @@ Object { exports[`errors InvalidProviderError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 601, "innerError": undefined, "message": "Provider with url \\"my url\\" is not set or invalid", @@ -186,6 +204,14 @@ Object { exports[`errors InvalidResponseError should have valid json structure 1`] = ` Object { + "cause": Object { + "code": 123, + "data": Object { + "a": "10", + "b": "20", + }, + "message": "error message", + }, "code": 101, "data": Object { "a": "10", @@ -207,6 +233,7 @@ Object { exports[`errors MaxAttemptsReachedOnReconnectingError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 505, "errorCode": undefined, "errorReason": undefined, @@ -218,6 +245,7 @@ Object { exports[`errors NoContractAddressFoundError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 403, "innerError": undefined, "message": "The transaction receipt didn't contain a contract address.", @@ -230,6 +258,7 @@ Object { exports[`errors PendingRequestsOnReconnectingError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 506, "errorCode": undefined, "errorReason": undefined, @@ -242,6 +271,7 @@ Object { exports[`errors ResolverMethodMissingError should have valid json structure 1`] = ` Object { "address": "address", + "cause": undefined, "code": 301, "innerError": undefined, "message": "The resolver at address does not implement requested method: \\"name\\".", @@ -251,6 +281,14 @@ Object { exports[`errors ResponseError should have valid json structure with data 1`] = ` Object { + "cause": Object { + "code": 123, + "data": Object { + "a": "10", + "b": "20", + }, + "message": "error message", + }, "code": 100, "data": Object { "a": "10", @@ -272,6 +310,11 @@ Object { exports[`errors ResponseError should have valid json structure without data 1`] = ` Object { + "cause": Object { + "code": 123, + "data": undefined, + "message": "error message", + }, "code": 100, "data": undefined, "innerError": Object { @@ -287,6 +330,7 @@ Object { exports[`errors ResponseError should include the array of inner errors 1`] = ` Object { + "cause": [MultipleErrors: Multiple errors occurred: [error message], [error message]], "code": 100, "data": Array [ Object { @@ -298,24 +342,7 @@ Object { "d": "40", }, ], - "innerError": Array [ - Object { - "code": 123, - "data": Object { - "a": "10", - "b": "20", - }, - "message": "error message", - }, - Object { - "code": 124, - "data": Object { - "c": "30", - "d": "40", - }, - "message": "error message", - }, - ], + "innerError": [MultipleErrors: Multiple errors occurred: [error message], [error message]], "message": "Returned error: error message,error message", "name": "ResponseError", "request": undefined, @@ -324,6 +351,7 @@ Object { exports[`errors RevertInstructionError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 401, "innerError": undefined, "message": "Your request got reverted with the following reason string: message", @@ -335,6 +363,7 @@ Object { exports[`errors SchemaFormatError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 1200, "innerError": undefined, "message": "Format for the type unsupported is unsupported", @@ -345,6 +374,7 @@ Object { exports[`errors TransactionError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 400, "innerError": undefined, "message": "message", @@ -357,6 +387,7 @@ Object { exports[`errors TransactionOutOfGasError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 406, "innerError": undefined, "message": "Transaction ran out of gas. Please provide more gas: @@ -372,6 +403,7 @@ Object { exports[`errors TransactionRevertInstructionError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 402, "data": undefined, "innerError": undefined, @@ -388,6 +420,7 @@ Object { exports[`errors TransactionRevertWithCustomError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 438, "customErrorArguments": Object { "customErrorArgument": "customErrorArgument", @@ -408,6 +441,7 @@ Object { exports[`errors TransactionRevertedWithoutReasonError should have valid json structure 1`] = ` Object { + "cause": undefined, "code": 405, "innerError": undefined, "message": "Transaction has been reverted by the EVM: diff --git a/packages/web3-errors/test/unit/__snapshots__/rpc-errors.test.ts.snap b/packages/web3-errors/test/unit/__snapshots__/rpc-errors.test.ts.snap index 93330d6576f..687b9888aab 100644 --- a/packages/web3-errors/test/unit/__snapshots__/rpc-errors.test.ts.snap +++ b/packages/web3-errors/test/unit/__snapshots__/rpc-errors.test.ts.snap @@ -2,6 +2,7 @@ exports[`rpc errors EIP1193ProviderRpcError test constructor with a known code (1000) 1`] = ` Object { + "cause": undefined, "code": 1000, "innerError": undefined, "message": "The connection successfully completed the purpose for which it was created.", @@ -11,6 +12,7 @@ Object { exports[`rpc errors EIP1193ProviderRpcError test constructor with no code 1`] = ` Object { + "cause": undefined, "code": undefined, "innerError": undefined, "message": "", @@ -20,6 +22,7 @@ Object { exports[`rpc errors EIP1193ProviderRpcError test constructor with un registered code 1`] = ` Object { + "cause": undefined, "code": 99999, "innerError": undefined, "message": "An Rpc error has occured with a code of 99999", @@ -29,6 +32,7 @@ Object { exports[`rpc errors InternalError test constructor 1`] = ` Object { + "cause": undefined, "code": -32603, "error": Object { "code": 123, @@ -48,6 +52,7 @@ Object { exports[`rpc errors InvalidInputError test constructor 1`] = ` Object { + "cause": undefined, "code": -32000, "error": Object { "code": 123, @@ -67,6 +72,7 @@ Object { exports[`rpc errors InvalidParamsError test constructor 1`] = ` Object { + "cause": undefined, "code": -32602, "error": Object { "code": 123, @@ -86,6 +92,7 @@ Object { exports[`rpc errors InvalidRequestError test constructor 1`] = ` Object { + "cause": undefined, "code": -32600, "error": Object { "code": 123, @@ -105,6 +112,7 @@ Object { exports[`rpc errors LimitExceededError test constructor 1`] = ` Object { + "cause": undefined, "code": -32005, "error": Object { "code": 123, @@ -124,6 +132,7 @@ Object { exports[`rpc errors MethodNotFoundError test constructor 1`] = ` Object { + "cause": undefined, "code": -32601, "error": Object { "code": 123, @@ -143,6 +152,7 @@ Object { exports[`rpc errors MethodNotSupported test constructor 1`] = ` Object { + "cause": undefined, "code": -32004, "error": Object { "code": 123, @@ -162,6 +172,7 @@ Object { exports[`rpc errors ParseError test constructor 1`] = ` Object { + "cause": undefined, "code": -32700, "error": Object { "code": 123, @@ -181,6 +192,7 @@ Object { exports[`rpc errors ResourceUnavailableError test constructor 1`] = ` Object { + "cause": undefined, "code": -32002, "error": Object { "code": 123, @@ -200,6 +212,7 @@ Object { exports[`rpc errors ResourcesNotFoundError test constructor 1`] = ` Object { + "cause": undefined, "code": -32001, "error": Object { "code": 123, @@ -219,6 +232,7 @@ Object { exports[`rpc errors TransactionRejectedError test constructor 1`] = ` Object { + "cause": undefined, "code": -32003, "error": Object { "code": 123, @@ -238,6 +252,7 @@ Object { exports[`rpc errors VersionNotSupportedError test constructor 1`] = ` Object { + "cause": undefined, "code": -32006, "error": Object { "code": 123, @@ -257,6 +272,7 @@ Object { exports[`rpc errors rpcErrors.RpcError test constructor 1`] = ` Object { + "cause": undefined, "code": 123, "error": Object { "code": 123, @@ -276,6 +292,7 @@ Object { exports[`rpc errors rpcErrors.RpcError test constructor with custom message 1`] = ` Object { + "cause": undefined, "code": 123, "error": Object { "code": 123, diff --git a/packages/web3-errors/test/unit/base-web3-error.test.ts b/packages/web3-errors/test/unit/base-web3-error.test.ts new file mode 100644 index 00000000000..dad318f30df --- /dev/null +++ b/packages/web3-errors/test/unit/base-web3-error.test.ts @@ -0,0 +1,50 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { BaseWeb3Error, MultipleErrors } from '../../src/web3_error_base'; + +class CustomError extends BaseWeb3Error { + public code = 0; +} +describe('BaseWeb3Error', () => { + it('innerError is readable from cause', () => { + const error = new CustomError('outer error'); + const innerError = new Error('inner error'); + error.cause = innerError; + // eslint-disable-next-line deprecation/deprecation + expect(error.innerError).toBe(innerError); + }); + it('case is set from innerError', () => { + const error = new CustomError('outer error'); + const cause = new Error('inner error'); + // eslint-disable-next-line deprecation/deprecation + error.innerError = cause; + expect(error.cause).toBe(cause); + }); + it('case is set from innerError array', () => { + const error = new CustomError('outer error'); + const innerErrors = [new Error('inner error1'), new Error('inner error2')]; + // eslint-disable-next-line deprecation/deprecation + error.innerError = innerErrors; + expect((error.cause as MultipleErrors).errors).toBe(innerErrors); + }); + it('case is set from array of errors at the constructor', () => { + const innerErrors = [new Error('inner error1'), new Error('inner error2')]; + const error = new CustomError('outer error', innerErrors); + expect((error.cause as MultipleErrors).errors).toBe(innerErrors); + }); +}); diff --git a/packages/web3-eth-abi/CHANGELOG.md b/packages/web3-eth-abi/CHANGELOG.md index 69c387b19c7..2192a71e872 100644 --- a/packages/web3-eth-abi/CHANGELOG.md +++ b/packages/web3-eth-abi/CHANGELOG.md @@ -154,4 +154,8 @@ Documentation: - Bug fix of `ERR_UNSUPPORTED_DIR_IMPORT` in ABI (#6535) -## [Unreleased] \ No newline at end of file +## [Unreleased] + +### Changed + +- Use `AbiError` instead of `Error` for errors at web3-eth-abi (#6641). diff --git a/packages/web3-eth-abi/src/api/errors_api.ts b/packages/web3-eth-abi/src/api/errors_api.ts index 7a6a2bc85ff..69933f5eb6e 100644 --- a/packages/web3-eth-abi/src/api/errors_api.ts +++ b/packages/web3-eth-abi/src/api/errors_api.ts @@ -15,6 +15,11 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +/** + * + * @module ABI + */ + import { sha3Raw } from 'web3-utils'; import { AbiError } from 'web3-errors'; import { AbiErrorFragment } from 'web3-types'; diff --git a/packages/web3-eth-abi/src/api/events_api.ts b/packages/web3-eth-abi/src/api/events_api.ts index 92b38b4afb9..67bb1791432 100644 --- a/packages/web3-eth-abi/src/api/events_api.ts +++ b/packages/web3-eth-abi/src/api/events_api.ts @@ -15,6 +15,11 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +/** + * + * @module ABI + */ + import { sha3Raw } from 'web3-utils'; import { AbiError } from 'web3-errors'; import { AbiEventFragment } from 'web3-types'; diff --git a/packages/web3-eth-abi/src/api/functions_api.ts b/packages/web3-eth-abi/src/api/functions_api.ts index 0c78c4f5a1f..ad05fc0c824 100644 --- a/packages/web3-eth-abi/src/api/functions_api.ts +++ b/packages/web3-eth-abi/src/api/functions_api.ts @@ -15,6 +15,10 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +/** + * + * @module ABI + */ import { AbiError } from 'web3-errors'; import { sha3Raw } from 'web3-utils'; import { AbiFunctionFragment } from 'web3-types'; diff --git a/packages/web3-eth-abi/src/api/logs_api.ts b/packages/web3-eth-abi/src/api/logs_api.ts index 677a4c50478..f7ebd012d57 100644 --- a/packages/web3-eth-abi/src/api/logs_api.ts +++ b/packages/web3-eth-abi/src/api/logs_api.ts @@ -15,6 +15,11 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +/** + * + * @module ABI + */ + import { HexString, AbiParameter, DecodedParams } from 'web3-types'; import { decodeParameter, decodeParametersWith } from './parameters_api.js'; diff --git a/packages/web3-eth-abi/src/api/parameters_api.ts b/packages/web3-eth-abi/src/api/parameters_api.ts index 1fe44a64bb1..0d0f007ecd2 100644 --- a/packages/web3-eth-abi/src/api/parameters_api.ts +++ b/packages/web3-eth-abi/src/api/parameters_api.ts @@ -14,6 +14,12 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ + +/** + * + * @module ABI + */ + import { AbiError } from 'web3-errors'; import { AbiInput, HexString } from 'web3-types'; import { decodeParameters as decodeParametersInternal } from '../coders/decode.js'; diff --git a/packages/web3-eth-abi/src/coders/base/index.ts b/packages/web3-eth-abi/src/coders/base/index.ts index 007d31e98a4..007e3ebb4d6 100644 --- a/packages/web3-eth-abi/src/coders/base/index.ts +++ b/packages/web3-eth-abi/src/coders/base/index.ts @@ -16,6 +16,7 @@ along with web3.js. If not, see . */ import { AbiParameter } from 'web3-types'; +import { AbiError } from 'web3-errors'; import { EncoderResult, DecoderResult } from '../types.js'; import { decodeAddress, encodeAddress } from './address.js'; import { decodeBool, encodeBoolean } from './bool.js'; @@ -59,7 +60,10 @@ export function encodeParamFromAbiParameter(param: AbiParameter, value: unknown) if (param.type.startsWith('uint') || param.type.startsWith('int')) { return encodeNumber(param, value); } - throw new Error('Unsupported'); + throw new AbiError('Unsupported', { + param, + value, + }); } export function decodeParamFromAbiParameter(param: AbiParameter, bytes: Uint8Array): DecoderResult { @@ -84,5 +88,8 @@ export function decodeParamFromAbiParameter(param: AbiParameter, bytes: Uint8Arr if (param.type.startsWith('uint') || param.type.startsWith('int')) { return decodeNumber(param, bytes); } - throw new Error('Unsupported'); + throw new AbiError('Unsupported', { + param, + bytes, + }); } diff --git a/packages/web3-eth-abi/src/eip_712.ts b/packages/web3-eth-abi/src/eip_712.ts index f08609bffc5..5a46df80be4 100644 --- a/packages/web3-eth-abi/src/eip_712.ts +++ b/packages/web3-eth-abi/src/eip_712.ts @@ -16,11 +16,56 @@ along with web3.js. If not, see . */ /** - * @note This code was taken from: https://github.com/Mrtenz/eip-712/tree/master + * The web3.eth.abi functions let you encode and decode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine). + * + * For using Web3 ABI functions, first install Web3 package using `npm i web3` or `yarn add web3`. + * After that, Web3 ABI functions will be available. + * ```ts + * import { Web3 } from 'web3'; + * + * const web3 = new Web3(); + * const encoded = web3.eth.abi.encodeFunctionSignature({ + * name: 'myMethod', + * type: 'function', + * inputs: [{ + * type: 'uint256', + * name: 'myNumber' + * },{ + * type: 'string', + * name: 'myString' + * }] + * }); + * + * ``` + * + * For using individual package install `web3-eth-abi` package using `npm i web3-eth-abi` or `yarn add web3-eth-abi` and only import required functions. + * This is more efficient approach for building lightweight applications. + * ```ts + * import { encodeFunctionSignature } from 'web3-eth-abi'; + * + * const encoded = encodeFunctionSignature({ + * name: 'myMethod', + * type: 'function', + * inputs: [{ + * type: 'uint256', + * name: 'myNumber' + * },{ + * type: 'string', + * name: 'myString' + * }] + * }); + * + * ``` + * + * @module ABI */ + +// This code was taken from: https://github.com/Mrtenz/eip-712/tree/master + import { Eip712TypedData } from 'web3-types'; import { isNullish, keccak256 } from 'web3-utils'; +import { AbiError } from 'web3-errors'; import { encodeParameters } from './coders/encode.js'; const TYPE_REGEX = /^\w+/; @@ -138,12 +183,17 @@ const encodeValue = ( const length = Number(match[2]) || undefined; if (!Array.isArray(data)) { - throw new Error('Cannot encode data: value is not of array type'); + throw new AbiError('Cannot encode data: value is not of array type', { + data, + }); } if (length && data.length !== length) { - throw new Error( + throw new AbiError( `Cannot encode data: expected length of ${length}, but got ${data.length}`, + { + data, + }, ); } @@ -182,7 +232,10 @@ const encodeData = ( const [types, values] = typedData.types[type].reduce<[string[], unknown[]]>( ([_types, _values], field) => { if (isNullish(data[field.name]) || isNullish(data[field.name])) { - throw new Error(`Cannot encode data: missing data for '${field.name}'`); + throw new AbiError(`Cannot encode data: missing data for '${field.name}'`, { + data, + field, + }); } const value = data[field.name]; diff --git a/packages/web3-eth-abi/src/index.ts b/packages/web3-eth-abi/src/index.ts index baa57947847..50886679928 100644 --- a/packages/web3-eth-abi/src/index.ts +++ b/packages/web3-eth-abi/src/index.ts @@ -15,9 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** - * The web3.eth.abi functions let you encode and decode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine). - */ export * from './api/errors_api.js'; export * from './api/events_api.js'; export * from './api/functions_api.js'; diff --git a/packages/web3-eth-abi/test/fixtures/data.ts b/packages/web3-eth-abi/test/fixtures/data.ts index a2f3b32ba20..aeefb7a9541 100644 --- a/packages/web3-eth-abi/test/fixtures/data.ts +++ b/packages/web3-eth-abi/test/fixtures/data.ts @@ -1031,7 +1031,7 @@ export const validDecodeContractErrorData: { code: 42, message: 'This is an error with params', }, - innerError: { + cause: { code: -32000, }, }, @@ -1067,7 +1067,7 @@ export const validDecodeContractErrorData: { code: 42, message: 'This is an error with params', }, - innerError: { + cause: { code: 3, }, }, diff --git a/packages/web3/test/e2e_manual/setup.js b/packages/web3-eth-abi/test/unit/coders/base/invalid.test.ts similarity index 50% rename from packages/web3/test/e2e_manual/setup.js rename to packages/web3-eth-abi/test/unit/coders/base/invalid.test.ts index e9757a61e1c..049f80774ee 100644 --- a/packages/web3/test/e2e_manual/setup.js +++ b/packages/web3-eth-abi/test/unit/coders/base/invalid.test.ts @@ -15,10 +15,23 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -// Have to use `require` because of Jest issue https://jestjs.io/docs/ecmascript-modules -// eslint-disable-next-line @typescript-eslint/no-require-imports -require('../config/setup'); +import { AbiError } from 'web3-errors'; +import { + decodeParamFromAbiParameter, + encodeParamFromAbiParameter, +} from '../../../../src/coders/base'; -const jestTimeout = 300000; - -jest.setTimeout(jestTimeout); +describe('abi - coder - base - invalid', () => { + describe('invalid type', () => { + it('invalid should cause `decodeParamFromAbiParameter` to throw', () => { + expect(() => + decodeParamFromAbiParameter({ type: 'invalid', name: '' }, new Uint8Array()), + ).toThrow(AbiError); + }); + it('invalid should cause `encodeParamFromAbiParameter` to throw', () => { + expect(() => + encodeParamFromAbiParameter({ type: 'invalid', name: '' }, 'something'), + ).toThrow(AbiError); + }); + }); +}); diff --git a/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts b/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts index c130af64c4a..3f6a624ef22 100644 --- a/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts +++ b/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts @@ -33,7 +33,7 @@ describe('decodeContractErrorData', () => { expect(err.errorSignature).toEqual(output.errorSignature); expect(err.errorArgs?.message).toEqual(output.errorArgs?.message); expect(Number(err.errorArgs?.code)).toEqual(output.errorArgs?.code); - expect(err.innerError?.code).toEqual(output.innerError?.code); + expect(err.cause?.code).toEqual(output.cause?.code); }, ); }); diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index 606ecaf035a..8b8dcce7fe5 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -16,7 +16,30 @@ along with web3.js. If not, see . */ /** + * The web3 accounts package contains functions to generate Ethereum accounts and sign transactions & data. + * + * For using accounts functions, first install Web3 package using `npm i web3` or `yarn add web3` based on your package manager usage. + * After that, Accounts functions will be available as mentioned in following snippet. + * ```ts + * import {Web3} from 'web3'; + * + * const web3 = new Web3(); + * const account = web3.eth.accounts.create(); + * const result = web3.eth.accounts.hashMessage("Test Message"); + * + * ``` + * + * For using individual package install `web3-eth-accounts` package using `npm i web3-eth-accounts` or `yarn add web3-eth-accounts` and only import required functions. + * This is more efficient approach for building lightweight applications. + * ```ts + * import {create,hashMessage} from 'web3-eth-accounts'; + * + * const account = create(); + * const result = hashMessage("Test Message"); + * + * ``` * @module Accounts + * */ import { @@ -76,7 +99,23 @@ import type { /** - * Get the private key Uint8Array after the validation + * Get the private key Uint8Array after the validation. + * Note: This function is not exported through main web3 package, so for using it directly import from accounts package. + * @param data - Private key + * @param ignoreLength - Optional, ignore length check during validation + * @returns The Uint8Array private key + * + * ```ts + * parseAndValidatePrivateKey("0x08c673022000ece7964ea4db2d9369c50442b2869cbd8fc21baaca59e18f642c") + * + * > Uint8Array(32) [ + * 186, 26, 143, 168, 235, 179, 90, 75, + * 101, 63, 84, 221, 152, 150, 30, 203, + * 8, 113, 94, 226, 53, 213, 216, 5, + * 194, 159, 17, 53, 219, 97, 121, 248 + * ] + * + * ``` */ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean): Uint8Array => { let privateKeyUint8Array: Uint8Array; @@ -101,15 +140,19 @@ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean): /** * - * Hashes the given message. The data will be UTF-8 HEX decoded and enveloped as follows: "\\x19Ethereum Signed Message:\\n" + message.length + message and hashed using keccak256. + * Hashes the given message. The data will be `UTF-8 HEX` decoded and enveloped as follows: + * `"\\x19Ethereum Signed Message:\\n" + message.length + message` and hashed using keccak256. * * @param message - A message to hash, if its HEX it will be UTF8 decoded. * @returns The hashed message * * ```ts - * hashMessage("Hello world") + * web3.eth.accounts.hashMessage("Hello world") + * * > "0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede" - * hashMessage(utf8ToHex("Hello world")) // Will be hex decoded in hashMessage + * + * web3.eth.accounts.hashMessage(web3.utils.utf8ToHex("Hello world")) // Will be hex decoded in hashMessage + * * > "0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede" * ``` */ @@ -129,8 +172,10 @@ export const hashMessage = (message: string): string => { /** * Signs arbitrary data with a given private key. - * **_NOTE:_** The value passed as the data parameter will be UTF-8 HEX decoded and wrapped as follows: "\\x19Ethereum Signed Message:\\n" + message.length + message - * + * :::info + * The value passed as the data parameter will be UTF-8 HEX decoded and wrapped as follows: "\\x19Ethereum Signed Message:\\n" + message.length + message + * ::: + * @param data - The data to sign * @param privateKey - The 32 byte private key to sign with * @returns The signature Object containing the message, messageHash, signature r, s, v @@ -181,16 +226,18 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * * Signing a legacy transaction * ```ts - * signTransaction({ + * import {signTransaction, Transaction} from 'web3-eth-accounts'; + * + * signTransaction(new Transaction({ * to: '0x118C2E5F57FD62C2B5b46a5ae9216F4FF4011a07', * value: '0x186A0', * gasLimit: '0x520812', * gasPrice: '0x09184e72a000', * data: '', * chainId: 1, - * nonce: 0, - * }, '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318')) - * } + * nonce: 0 }), + * '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318') + * * > { * messageHash: '0x28b7b75f7ba48d588a902c1ff4d5d13cc0ca9ac0aaa39562368146923fb853bf', * v: '0x25', @@ -199,9 +246,12 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * rawTransaction: '0xf869808609184e72a0008352081294118c2e5f57fd62c2b5b46a5ae9216f4ff4011a07830186a08025a00601b0017b0e20dd0eeda4b895fbc1a9e8968990953482214f880bae593e71b5a0690d984493560552e3ebdcc19a65b9c301ea9ddc82d3ab8cfde60485fd5722ce', * transactionHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' * ``` + * * Signing an eip 1559 transaction * ```ts - * signTransaction({ + * import {signTransaction, Transaction} from 'web3-eth-accounts'; + * + * signTransaction(new Transaction({ * to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55', * maxPriorityFeePerGas: '0x3B9ACA00', * maxFeePerGas: '0xB2D05E00', @@ -209,8 +259,8 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * value: '0x186A0', * data: '', * chainId: 1, - * nonce: 0, - * },"0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318") + * nonce: 0}), + * "0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318") * > { * messageHash: '0x5744f24d5f0aff6c70487c8e85adf07d8564e50b08558788f00479611d7bae5f', * v: '0x25', @@ -220,9 +270,12 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * transactionHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' * } * ``` + * * Signing an eip 2930 transaction * ```ts - * signTransaction({ + * import {signTransaction, Transaction} from 'web3-eth-accounts'; + * + * signTransaction(new Transaction ({ * chainId: 1, * nonce: 0, * gasPrice: '0x09184e72a000', @@ -239,7 +292,8 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * ], * }, * ], - * },"0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318") + * }),"0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318") + * * > { * messageHash: '0xc55ea24bdb4c379550a7c9a6818ac39ca33e75bc78ddb862bd82c31cc1c7a073', * v: '0x26', @@ -289,7 +343,7 @@ export const signTransaction = async ( * @param rawTransaction - The hex string having RLP encoded transaction * @returns The Ethereum address used to sign this transaction * ```ts - * recoverTransaction('0xf869808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a0c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895a0727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68'); + * web3.eth.accounts.recoverTransaction('0xf869808504e3b29200831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a0c9cf86333bcb065d140032ecaab5d9281bde80f21b9687b3e94161de42d51895a0727a108a0b8d101465414033c3f705a9c7b826e596766046ee1183dbc8aeaa68'); * > "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23" * ``` */ @@ -306,23 +360,29 @@ export const recoverTransaction = (rawTransaction: HexString): Address => { * * @param data - Either a signed message, hash, or the {@link signatureObject} * @param signature - The raw RLP encoded signature - * @param signatureOrV - signatureOrV - * @param prefixedOrR - prefixedOrR - * @param s - s - * @param prefixed - (default: false) If the last parameter is true, the given message will NOT automatically be prefixed with "\\x19Ethereum Signed Message:\\n" + message.length + message, and assumed to be already prefixed. + * @param signatureOrV - signature or V + * @param prefixedOrR - prefixed or R + * @param s - S value in signature + * @param prefixed - (default: false) If the last parameter is true, the given message will NOT automatically be prefixed with `"\\x19Ethereum Signed Message:\\n" + message.length + message`, and assumed to be already prefixed. * @returns The Ethereum address used to sign this data + * * ```ts - * sign('Some data', '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728'); + * const data = 'Some data'; + * const sigObj = web3.eth.accounts.sign(data, '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728') + * * > { - * message: 'Some data', - * messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655', - * v: '0x1b', - * r: '0xa8037a6116c176a25e6fc224947fde9e79a2deaa0dd8b67b366fbdfdbffc01f9', - * s: '0x53e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb150', - * signature: '0xa8037a6116c176a25e6fc224947fde9e79a2deaa0dd8b67b366fbdfdbffc01f953e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb1501b' + * message: 'Some data', + * messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655', + * v: '0x1b', + * r: '0xa8037a6116c176a25e6fc224947fde9e79a2deaa0dd8b67b366fbdfdbffc01f9', + * s: '0x53e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb150', + * signature: '0xa8037a6116c176a25e6fc224947fde9e79a2deaa0dd8b67b366fbdfdbffc01f953e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb1501b' * } - * recover('0xa8037a6116c176a25e6fc224947fde9e79a2deaa0dd8b67b366fbdfdbffc01f953e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb1501b'); - * > '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0' + * + * // now recover + * web3.eth.accounts.recover(data, sigObj.v, sigObj.r, sigObj.s) + * + * > 0xEB014f8c8B418Db6b45774c326A0E64C78914dC0 * ``` */ export const recover = ( @@ -371,7 +431,8 @@ export const recover = ( * @returns The Ethereum address * @example * ```ts - * privateKeyToAddress("0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728") + * web3.eth.accounts.privateKeyToAddress("0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728") + * * > "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0" * ``` */ @@ -399,7 +460,8 @@ export const privateKeyToAddress = (privateKey: Bytes): string => { * @returns The public key * @example * ```ts - * privateKeyToAddress("0x1e046a882bb38236b646c9f135cf90ad90a140810f439875f2a6dd8e50fa261f", true) + * web3.eth.accounts.privateKeyToPublicKey("0x1e046a882bb38236b646c9f135cf90ad90a140810f439875f2a6dd8e50fa261f", true) + * * > "0x42beb65f179720abaa3ec9a70a539629cbbc5ec65bb57e7fc78977796837e537662dd17042e6449dc843c281067a4d6d8d1a1775a13c41901670d5de7ee6503a" // uncompressed public key * ``` */ @@ -420,17 +482,18 @@ export const privateKeyToAddress = (privateKey: Bytes): string => { * @param options - Options to configure to encrypt the keystore either scrypt or pbkdf2 * @returns Returns a V3 JSON Keystore * - * - * Encrypt using scrypt options + * Encrypt using scrypt options: * ```ts - * encrypt('0x67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', - * '123', - * { - * n: 8192, - * iv: web3.utils.hexToBytes('0xbfb43120ae00e9de110f8325143a2709'), - * salt: web3.utils.hexToBytes('0x210d0ec956787d865358ac45716e6dd42e68d48e346d795746509523aeb477dd'), - * ), - * }).then(console.log) + * + * web3.eth.accounts.encrypt( + * '0x67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', + * '123', + * { + * n: 8192, + * iv: web3.utils.hexToBytes('0xbfb43120ae00e9de110f8325143a2709'), + * salt: web3.utils.hexToBytes('0x210d0ec956787d865358ac45716e6dd42e68d48e346d795746509523aeb477dd'), + * }).then(console.log) + * * > { * version: 3, * id: 'c0cb0a94-4702-4492-b6e6-eb2ac404344a', @@ -451,9 +514,10 @@ export const privateKeyToAddress = (privateKey: Bytes): string => { * } *} *``` - * Encrypting using pbkdf2 options + * + * Encrypting using pbkdf2 options: * ```ts - * encrypt('0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709', + * web3.eth.accounts.encrypt('0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709', *'123', *{ * iv: 'bfb43120ae00e9de110f8325143a2709', @@ -461,6 +525,7 @@ export const privateKeyToAddress = (privateKey: Bytes): string => { * c: 262144, * kdf: 'pbkdf2', *}).then(console.log) + * * > * { * version: 3, @@ -587,11 +652,13 @@ export const encrypt = async ( * @param ignoreLength - if true, will not error check length * @returns A Web3Account object * - * The `Web3Account.signTransaction` is not stateful here. We need network access to get the account `nonce` and `chainId` to sign the transaction. - * Use {@link Web3.eth.accounts.signTransaction} instead. + * :::info + * The `Web3Account.signTransaction` is not stateful if directly imported from accounts package and used. Network access is required to get the account `nonce` and `chainId` to sign the transaction, so use {@link Web3.eth.accounts.signTransaction} for signing transactions. + * :::: * * ```ts - * privateKeyToAccount("0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709"); + * web3.eth.accounts.privateKeyToAccount("0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709"); + * * > { * address: '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01', * privateKey: '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709', @@ -653,7 +720,7 @@ export const create = (): Web3Account => { * Decrypting scrypt * * ```ts - * decrypt({ + * web3.eth.accounts.decrypt({ * version: 3, * id: 'c0cb0a94-4702-4492-b6e6-eb2ac404344a', * address: 'cda9a91875fc35c8ac1320e098e584495d66e47c', @@ -671,7 +738,9 @@ export const create = (): Web3Account => { * }, * mac: 'efbf6d3409f37c0084a79d5fdf9a6f5d97d11447517ef1ea8374f51e581b7efd' * } - * }, '123').then(console.log) + * }, '123').then(console.log); + * + * * > { * address: '0xcdA9A91875fc35c8Ac1320E098e584495d66e47c', * privateKey: '67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', diff --git a/packages/web3-eth-accounts/src/wallet.ts b/packages/web3-eth-accounts/src/wallet.ts index 8d50efd557a..1e189fe4cbc 100644 --- a/packages/web3-eth-accounts/src/wallet.ts +++ b/packages/web3-eth-accounts/src/wallet.ts @@ -23,24 +23,27 @@ type BrowserError = { code: number; name: string }; /** * Wallet is an in memory `wallet` that can hold multiple accounts. - * These accounts can be used when using web3.eth.sendTransaction(). - * - * ### Parameters - * Web3AccountProvider - AccountProvider for the wallet + * These accounts can be used when using web3.eth.sendTransaction() or web3.eth.contract.methods.contractfunction().send(); * + * For using Wallet functionality, install Web3 package using `npm i web3` or `yarn add web3`. + * After that, Wallet functionality will be available as mentioned below. + * * ```ts - * import Web3 from 'web3'; - * const web3 = new Web3("https://localhost:8454") - * web3.eth.accounts.wallet - * > Wallet(0) [ - * _accountProvider: { - * create: [Function: create], - * privateKeyToAccount: [Function: privateKeyToAccount], - * decrypt: [Function: decrypt] - * }, - * _addressMap: Map(0) {}, - * _defaultKeyName: 'web3js_wallet' - * ] + * import { Web3 } from 'web3'; + * const web3 = new Web3('http://127.0.0.1:7545'); + * + * const wallet = await web3.eth.accounts.wallet.create(2); + * + * const signature = wallet.at(0).sign("Test Data"); // use wallet + * + * // fund account before sending following transaction ... + * + * const receipt = await web3.eth.sendTransaction({ // internally sign transaction using wallet + * from: wallet.at(0).address, + * to: "0xdAC17F958D2ee523a2206206994597C13D831ec7", + * value: 1 + * //.... + * }); * ``` */ export class Wallet< diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 67bc60842a0..580c6cc4d36 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -191,8 +191,140 @@ const contractSubscriptions = { }; /** - * The class designed to interact with smart contracts on the Ethereum blockchain. - */ +* The `web3.eth.Contract` makes it easy to interact with smart contracts on the ethereum blockchain. +* For using contract package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager, after that contracts features can be used as mentioned in following snippet. +* ```ts +* +* import { Web3 } from 'web3'; +* +* const web3 = new Web3('https://127.0.0.1:4545'); +* const abi = [...] as const; // your contract ABI +* +* let contract = new web3.eth.Contract(abi,'0xdAC17F958D2ee523a2206206994597C13D831ec7'); +* await contract.methods.balanceOf('0xdAC17F958D2ee523a2206206994597C13D831ec7').call(); +* ``` +* For using individual package install `web3-eth-contract` and `web3-core` packages using: `npm i web3-eth-contract web3-core` or `yarn add web3-eth-contract web3-core`. This is more efficient approach for building lightweight applications. +* ```ts +* +* import { Web3Context } from 'web3-core'; +* import { Contract } from 'web3-eth-contract'; +* +* const abi = [...] as const; // your contract ABI +* +* let contract = new web3.eth.Contract( +* abi, +* '0xdAC17F958D2ee523a2206206994597C13D831ec7' +* new Web3Context('http://127.0.0.1:8545')); +* +* await contract.methods.balanceOf('0xdAC17F958D2ee523a2206206994597C13D831ec7').call(); +* ``` +* ## Generated Methods +* Following methods are generated by web3.js contract object for each of contract functions by using its ABI. +* +* ### send +* This is used to send a transaction to the smart contract and execute its method. Note this can alter the smart contract state. +* +* #### Parameters +* options?: PayableTxOptions | NonPayableTxOptions +* +* #### Returns +* [Web3PromiEvent](/api/web3/namespace/core#Web3PromiEvent) : Web3 Promi Event +* +* ```ts +* // using the promise +* myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'}) +* .then(function(receipt){ +* // other parts of code to use receipt +* }); +* +* +* // using the event emitter +* myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'}) +* .on('transactionHash', function(hash){ +* // ... +* }) +* .on('confirmation', function(confirmationNumber, receipt){ +* // ... +* }) +* .on('receipt', function(receipt){ +* // ... +* }) +* .on('error', function(error, receipt) { +* // ... +* }); +* +* ``` +* +* ### call +* This will execute smart contract method in the EVM without sending any transaction. Note calling cannot alter the smart contract state. +* +* #### Parameters +* options?: PayableCallOptions | NonPayableCallOptions, +* block?: BlockNumberOrTag, +* +* #### Returns +* Promise : having results of call +* +* ```ts +* +* let myContract = new web3.eth.Contract(abi, address); +* +* myContract.methods.myFunction().call() +* .then(console.log); +* +* ``` +* ### estimateGas +* Returns the amount of gas consumed by executing the method in EVM without creating a new transaction on the blockchain. The returned amount can be used as a gas estimate for executing the transaction publicly. The actual gas used can be different when sending the transaction later, as the state of the smart contract can be different at that time. +* +* #### Parameters +* options?: PayableCallOptions, +* returnFormat: ReturnFormat = DEFAULT_RETURN_FORMAT as ReturnFormat, +* +* #### Returns +* Promise: The gas amount estimated. +* +* ```ts +* const estimatedGas = await contract.methods.approve('0xdAC17F958D2ee523a2206206994597C13D831ec7', 300) +* .estimateGas(); +* +* ``` +* +* ### encodeABI +* Encodes the ABI for this method. The resulting hex string is 32-bit function signature hash plus the passed parameters in Solidity tightly packed format. This can be used to send a transaction, call a method, or pass it into another smart contract’s method as arguments. Set the data field on web3.eth.sendTransaction options as the encodeABI() result and it is the same as calling the contract method with contract.myMethod.send(). +* +* Some use cases for encodeABI() include: preparing a smart contract transaction for a multisignature wallet, working with offline wallets and cold storage and creating transaction payload for complex smart contract proxy calls. +* +* #### Parameters +* None +* +* #### Returns +* String: The encoded ABI. +* +* ```ts +* const encodedABI = await contract.methods.approve('0xdAC17F958D2ee523a2206206994597C13D831ec7', 300) +* .encodeABI(); +* +* ``` +* +* ### createAccessList +* This will create an access list a method execution will access when executed in the EVM. +* Note: You must specify a from address and gas if it’s not specified in options when instantiating parent contract object. +* +* #### Parameters +* options?: PayableCallOptions | NonPayableCallOptions, +* block?: BlockNumberOrTag, +* +* #### Returns +* Promise: The generated access list for transaction. +* +* ```ts +* const accessList = await contract.methods.approve('0xbEe634C21c16F05B03B704BaE071536121e6cFeA', 300) +* .createAccessList({ +* from: "0x9992695e1053bb737d3cfae4743dcfc4b94f203d" +* }); +* ``` +* +*/ export class Contract extends Web3Context implements Web3EventEmitter> @@ -371,9 +503,8 @@ export class Contract : returnFormat ?? DEFAULT_RETURN_FORMAT; const address = typeof addressOrOptionsOrContext === 'string' ? addressOrOptionsOrContext : undefined; - this.config.contractDataInputFill = - (options as ContractInitOptions)?.dataInputFill ?? - this.config.contractDataInputFill; + this.config.contractDataInputFill = + (options as ContractInitOptions)?.dataInputFill ?? this.config.contractDataInputFill; this._parseAndSetJsonInterface(jsonInterface, returnDataFormat); if (!isNullish(address)) { @@ -479,10 +610,10 @@ export class Contract * @returns - The new contract instance. * * ```ts - * const contract1 = new eth.Contract(abi, address, {gasPrice: '12345678', from: fromAddress}); + * const contract1 = new web3.eth.Contract(abi, address, {gasPrice: '12345678', from: fromAddress}); * * const contract2 = contract1.clone(); - * contract2.options.address = address2; + * contract2.options.address = '0xdAC17F958D2ee523a2206206994597C13D831ec7'; * * (contract1.options.address !== contract2.options.address); * > true @@ -532,7 +663,7 @@ export class Contract * * ```ts * myContract.deploy({ - * input: '0x12345...', // data keyword can be used, too. If input is used, data will be ignored. + * input: '0x12345...', // data keyword can be used, too. * arguments: [123, 'My String'] * }) * .send({ @@ -1027,7 +1158,7 @@ export class Contract } catch (error: unknown) { if (error instanceof ContractExecutionError) { // this will parse the error data by trying to decode the ABI error inputs according to EIP-838 - decodeContractErrorData(errorsAbi, error.innerError); + decodeContractErrorData(errorsAbi, error.cause); } throw error; } @@ -1057,7 +1188,7 @@ export class Contract } catch (error: unknown) { if (error instanceof ContractExecutionError) { // this will parse the error data by trying to decode the ABI error inputs according to EIP-838 - decodeContractErrorData(errorsAbi, error.innerError); + decodeContractErrorData(errorsAbi, error.cause); } throw error; } @@ -1082,18 +1213,18 @@ export class Contract options: { ...options, dataInputFill: this.config.contractDataInputFill }, contractOptions: modifiedContractOptions, }); - + const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { // TODO Should make this configurable by the user checkRevertBeforeSending: false, contractAbi: this._jsonInterface, }); - + // eslint-disable-next-line no-void void transactionToSend.on('error', (error: unknown) => { if (error instanceof ContractExecutionError) { // this will parse the error data by trying to decode the ABI error inputs according to EIP-838 - decodeContractErrorData(errorsAbi, error.innerError); + decodeContractErrorData(errorsAbi, error.cause); } }); return transactionToSend; diff --git a/packages/web3-eth-contract/test/integration/contract_methods.test.ts b/packages/web3-eth-contract/test/integration/contract_methods.test.ts index dc28f17799a..a661854932a 100644 --- a/packages/web3-eth-contract/test/integration/contract_methods.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_methods.test.ts @@ -81,7 +81,7 @@ describe('contract', () => { // eslint-disable-next-line jest/no-standalone-expect expect(error).toBeDefined(); // eslint-disable-next-line jest/no-standalone-expect - expect(error?.innerError.message).toContain('REVERTED WITH REVERT'); + expect(error?.cause.message).toContain('REVERTED WITH REVERT'); }); }); }); diff --git a/packages/web3-eth-contract/test/integration/contract_methods_errors.test.ts b/packages/web3-eth-contract/test/integration/contract_methods_errors.test.ts index e51accfa09b..ccd27987b27 100644 --- a/packages/web3-eth-contract/test/integration/contract_methods_errors.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_methods_errors.test.ts @@ -68,7 +68,7 @@ describe('contract errors', () => { 'Error happened while trying to execute a function inside a smart contract', ), code: ERR_CONTRACT_EXECUTION_REVERTED, - innerError: { + cause: { errorName: 'Unauthorized', errorSignature: 'Unauthorized()', }, @@ -80,7 +80,7 @@ describe('contract errors', () => { name: 'ContractExecutionError', code: ERR_CONTRACT_EXECUTION_REVERTED, receipt: undefined, - innerError: { + cause: { code: 3, data: '0x82b42900', errorName: 'Unauthorized', @@ -113,7 +113,7 @@ describe('contract errors', () => { 'Error happened while trying to execute a function inside a smart contract', ), code: ERR_CONTRACT_EXECUTION_REVERTED, - innerError: { + cause: { errorName: 'CustomError', errorSignature: 'CustomError(string)', errorArgs: { @@ -128,7 +128,7 @@ describe('contract errors', () => { name: 'ContractExecutionError', code: ERR_CONTRACT_EXECUTION_REVERTED, receipt: undefined, - innerError: { + cause: { code: 3, data: '0x8d6ea8be0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b7265766572746564207573696e6720637573746f6d204572726f720000000000', errorName: 'CustomError', diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts index d390b731b42..20682fbd2a2 100644 --- a/packages/web3-eth-contract/test/unit/contract.test.ts +++ b/packages/web3-eth-contract/test/unit/contract.test.ts @@ -1179,7 +1179,7 @@ describe('Contract', () => { }), ).rejects.toThrow( expect.objectContaining({ - innerError: expect.any(Error), + cause: expect.any(Error), }), ); diff --git a/packages/web3-eth-ens/src/ens.ts b/packages/web3-eth-ens/src/ens.ts index 26c642efc13..e62fd36c617 100644 --- a/packages/web3-eth-ens/src/ens.ts +++ b/packages/web3-eth-ens/src/ens.ts @@ -34,8 +34,25 @@ import { Resolver } from './resolver.js'; /** * This class is designed to interact with the ENS system on the Ethereum blockchain. - * - */ +* For using ENS package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager, after that ENS features can be used as mentioned in following snippet. +* ```ts +* +* import { Web3 } from 'web3'; +* +* const web3 = new Web3('https://127.0.0.1:4545'); +* +* console.log(await web3.eth.ens.getAddress('ethereum.eth')) +* ``` +* For using individual package install `web3-eth-ens` packages using: `npm i web3-eth-ens` or `yarn add web3-eth-ens`. This is more efficient approach for building lightweight applications. +* +* ```ts +*import { ENS } from 'web3-eth-ens'; +* +* const ens = new ENS(undefined,'https://127.0.0.1:4545'); +* +* console.log(await ens.getAddress('vitalik.eth')); +* ``` +*/ export class ENS extends Web3Context { /** * The registryAddress property can be used to define a custom registry address when you are connected to an unknown chain. It defaults to the main registry address. diff --git a/packages/web3-eth-iban/src/iban.ts b/packages/web3-eth-iban/src/iban.ts index db7e024e3cf..4bdb5e32cc6 100644 --- a/packages/web3-eth-iban/src/iban.ts +++ b/packages/web3-eth-iban/src/iban.ts @@ -23,7 +23,25 @@ import { IbanOptions } from './types.js'; /** * Converts Ethereum addresses to IBAN or BBAN addresses and vice versa. - */ +* For using Iban package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager, after that ENS features can be used. +* ```ts +* +* import { Web3 } from 'web3'; +* const web3 = new Web3('https://mainnet.infura.io/v3/'); +* +* const iban = new web3.eth.Iban("XE81ETHXREGGAVOFYORK"); +* console.log(iban.checksum()); + +* ``` +* For using individual package install `web3-eth-iban` packages using: `npm i web3-eth-iban` or `yarn add web3-eth-iban`. +* +* ```ts +* import {Iban} from 'web3-eth-iban'; +* +* const iban = new Iban("XE81ETHXREGGAVOFYORK"); +* console.log(iban.checksum()); +* ``` +*/ export class Iban { private readonly _iban: string; diff --git a/packages/web3-eth-personal/src/personal.ts b/packages/web3-eth-personal/src/personal.ts index ee6e55183d0..14bee669d6f 100644 --- a/packages/web3-eth-personal/src/personal.ts +++ b/packages/web3-eth-personal/src/personal.ts @@ -21,8 +21,25 @@ import { Address, EthPersonalAPI, HexString, Transaction } from 'web3-types'; import * as rpcWrappers from './rpc_method_wrappers.js'; /** - * Eth Personal allows you to interact with the Ethereum node’s accounts. - */ +* Eth Personal allows you to interact with the Ethereum node’s accounts. +* For using Eth Personal package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager. +* ```ts +* +*import { Web3 } from 'web3'; +* const web3 = new Web3('http://127.0.0.1:7545'); +* +* console.log(await web3.eth.personal.getAccounts()); +* +* ``` +* For using individual package install `web3-eth-personal` packages using: `npm i web3-eth-personal` or `yarn add web3-eth-personal`. +* +* ```ts +* import {Personal} from 'web3-eth-personal'; +* +* const personal = new Personal('http://127.0.0.1:7545'); +* console.log(await personal.getAccounts()); +* ``` +*/ export class Personal extends Web3Context { /** *Returns a list of accounts the node controls by using the provider and calling the RPC method personal_listAccounts. Using `web3.eth.accounts.create()` will not add accounts into this list. For that use `web3.eth.personal.newAccount()`. @@ -92,6 +109,7 @@ export class Personal extends Web3Context { * await personal.lockAccount( * "0x0d4aa485ecbc499c70860feb7e5aaeaf5fd8172e" * ); + * ``` */ public async lockAccount(address: Address) { return rpcWrappers.lockAccount(this.requestManager, address); @@ -201,7 +219,7 @@ export class Personal extends Web3Context { * @returns - The signature. * @example * ```ts - * const sig = await personal .sign("Hello world", "0x0D4Aa485ECbC499c70860fEb7e5AaeAf5fd8172E", "123456") + * const sig = await personal.sign("Hello world", "0x0D4Aa485ECbC499c70860fEb7e5AaeAf5fd8172E", "123456") * console.log(sig) * > 0x5d21d01b3198ac34d0585a9d76c4d1c8123e5e06746c8962318a1c08ffb207596e6fce4a6f377b7c0fc98c5f646cd73438c80e8a1a95cbec55a84c2889dca0301b * ``` diff --git a/packages/web3-eth/src/utils/get_revert_reason.ts b/packages/web3-eth/src/utils/get_revert_reason.ts index 4b4b7d596a9..ae4fc32dbfa 100644 --- a/packages/web3-eth/src/utils/get_revert_reason.ts +++ b/packages/web3-eth/src/utils/get_revert_reason.ts @@ -16,7 +16,7 @@ along with web3.js. If not, see . */ import { Web3Context } from 'web3-core'; -import { ContractExecutionError, Eip838ExecutionError, InvalidResponseError } from 'web3-errors'; +import { ContractExecutionError, Eip838ExecutionError, InvalidResponseError , MultipleErrors } from 'web3-errors'; import { decodeContractErrorData, isAbiErrorFragment } from 'web3-eth-abi'; import { AbiErrorFragment, @@ -32,39 +32,36 @@ import { call } from '../rpc_method_wrappers.js'; import { RevertReason, RevertReasonWithCustomError } from '../types.js'; export const parseTransactionError = (error: unknown, contractAbi?: ContractAbi) => { - if ( - error instanceof ContractExecutionError && - error.innerError instanceof Eip838ExecutionError - ) { + if (error instanceof ContractExecutionError && error.cause instanceof Eip838ExecutionError) { if (contractAbi !== undefined) { const errorsAbi = contractAbi.filter(abi => isAbiErrorFragment(abi), ) as unknown as AbiErrorFragment[]; - decodeContractErrorData(errorsAbi, error.innerError); + decodeContractErrorData(errorsAbi, error.cause); return { - reason: error.innerError.message, - signature: error.innerError.data?.slice(0, 10), - data: error.innerError.data?.substring(10), - customErrorName: error.innerError.errorName, - customErrorDecodedSignature: error.innerError.errorSignature, - customErrorArguments: error.innerError.errorArgs, + reason: error.cause.message, + signature: error.cause.data?.slice(0, 10), + data: error.cause.data?.substring(10), + customErrorName: error.cause.errorName, + customErrorDecodedSignature: error.cause.errorSignature, + customErrorArguments: error.cause.errorArgs, } as RevertReasonWithCustomError; } return { - reason: error.innerError.message, - signature: error.innerError.data?.slice(0, 10), - data: error.innerError.data?.substring(10), + reason: error.cause.message, + signature: error.cause.data?.slice(0, 10), + data: error.cause.data?.substring(10), } as RevertReason; } if ( error instanceof InvalidResponseError && - !Array.isArray(error.innerError) && - error.innerError !== undefined + !Array.isArray((error.cause as MultipleErrors)?.errors) && + error.cause !== undefined ) { - return error.innerError.message; + return error.cause.message; } throw error; diff --git a/packages/web3-eth/src/utils/watch_transaction_by_pooling.ts b/packages/web3-eth/src/utils/watch_transaction_by_polling.ts similarity index 100% rename from packages/web3-eth/src/utils/watch_transaction_by_pooling.ts rename to packages/web3-eth/src/utils/watch_transaction_by_polling.ts diff --git a/packages/web3-eth/src/utils/watch_transaction_by_subscription.ts b/packages/web3-eth/src/utils/watch_transaction_by_subscription.ts index 8cdaa8fc214..d68c39da95d 100644 --- a/packages/web3-eth/src/utils/watch_transaction_by_subscription.ts +++ b/packages/web3-eth/src/utils/watch_transaction_by_subscription.ts @@ -20,7 +20,7 @@ import { format } from 'web3-utils'; import { DataFormat } from 'web3-types'; import { NewHeadsSubscription } from '../web3_subscriptions.js'; import { transactionReceiptSchema } from '../schemas.js'; -import { WaitProps, watchTransactionByPolling } from './watch_transaction_by_pooling.js'; +import { WaitProps, watchTransactionByPolling } from './watch_transaction_by_polling.js'; /** * This function watches a Transaction by subscribing to new heads. diff --git a/packages/web3-eth/src/utils/watch_transaction_for_confirmations.ts b/packages/web3-eth/src/utils/watch_transaction_for_confirmations.ts index e6826fea10d..60489d59c50 100644 --- a/packages/web3-eth/src/utils/watch_transaction_for_confirmations.ts +++ b/packages/web3-eth/src/utils/watch_transaction_for_confirmations.ts @@ -28,7 +28,7 @@ import { transactionReceiptSchema } from '../schemas.js'; import { watchTransactionByPolling, Web3PromiEventEventTypeBase, -} from './watch_transaction_by_pooling.js'; +} from './watch_transaction_by_polling.js'; import { watchTransactionBySubscription } from './watch_transaction_by_subscription.js'; export function watchTransactionForConfirmations< diff --git a/packages/web3-eth/src/web3_eth.ts b/packages/web3-eth/src/web3_eth.ts index a259ac3b6b3..c78b8b420cf 100644 --- a/packages/web3-eth/src/web3_eth.ts +++ b/packages/web3-eth/src/web3_eth.ts @@ -74,6 +74,26 @@ export const registeredSubscriptions = { /** * * The Web3Eth allows you to interact with an Ethereum blockchain. + * + * For using Web3 Eth functions, first install Web3 package using `npm i web3` or `yarn add web3` based on your package manager usage. + * After that, Web3 Eth functions will be available as mentioned in following snippet. + * ```ts + * import { Web3 } from 'web3'; + * const web3 = new Web3('https://mainnet.infura.io/v3/'); + * + * const block = await web3.eth.getBlock(0); + * + * ``` + * + * For using individual package install `web3-eth` package using `npm i web3-eth` or `yarn add web3-eth` and only import required functions. + * This is more efficient approach for building lightweight applications. + * ```ts + * import { Web3Eth } from 'web3-eth'; + * + * const eth = new Web3Eth('https://mainnet.infura.io/v3/'); + * const block = await eth.getBlock(0); + * + * ``` */ export class Web3Eth extends Web3Context { public constructor( @@ -1081,7 +1101,7 @@ export class Web3Eth extends Web3Context( message: Bytes, - addressOrIndex: Address, + addressOrIndex: Address | number, returnFormat: ReturnFormat = DEFAULT_RETURN_FORMAT as ReturnFormat, ) { return rpcMethodsWrappers.sign(this, message, addressOrIndex, returnFormat); diff --git a/packages/web3-eth/test/integration/defaults.test.ts b/packages/web3-eth/test/integration/defaults.test.ts index 3a17d9449de..a9651fa20e3 100644 --- a/packages/web3-eth/test/integration/defaults.test.ts +++ b/packages/web3-eth/test/integration/defaults.test.ts @@ -584,7 +584,7 @@ describe('defaults', () => { confirmations: bigint; receipt: { status: bigint }; }) => { - // Being able to get 2 confirmations means the pooling for new blocks works + // Being able to get 2 confirmations means the polling for new blocks works if (confirmations >= 2) { sentTx.removeAllListeners(); resolve(status); diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index 1fe6c4f4c63..66587e6e90f 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -409,7 +409,7 @@ describe('Web3Eth.sendSignedTransaction', () => { const expectedThrownError = { name: 'TransactionRevertInstructionError', - innerError: undefined, + cause: undefined, reason: getSystemTestBackend() === 'geth' ? expect.stringContaining( @@ -445,7 +445,7 @@ describe('Web3Eth.sendSignedTransaction', () => { const expectedThrownError = { name: 'TransactionRevertInstructionError', message: 'Transaction has been reverted by the EVM', - innerError: undefined, + cause: undefined, reason: getSystemTestBackend() === 'geth' ? expect.stringContaining( @@ -600,7 +600,7 @@ describe('Web3Eth.sendSignedTransaction', () => { const expectedThrownError = { name: 'TransactionRevertInstructionError', - innerError: undefined, + cause: undefined, reason: getSystemTestBackend() === 'geth' ? 'execution reverted: This is a send revert' diff --git a/packages/web3-eth/test/unit/utils/watch_transaction_by_polling.test.ts b/packages/web3-eth/test/unit/utils/watch_transaction_by_polling.test.ts index 5a44db457e8..125a6432274 100644 --- a/packages/web3-eth/test/unit/utils/watch_transaction_by_polling.test.ts +++ b/packages/web3-eth/test/unit/utils/watch_transaction_by_polling.test.ts @@ -21,7 +21,7 @@ import { ethRpcMethods } from 'web3-rpc-methods'; import * as rpcMethodWrappers from '../../../src/rpc_method_wrappers'; import * as WaitForTransactionReceipt from '../../../src/utils/wait_for_transaction_receipt'; -import * as WatchTransactionByPolling from '../../../src/utils/watch_transaction_by_pooling'; +import * as WatchTransactionByPolling from '../../../src/utils/watch_transaction_by_polling'; import { expectedTransactionReceipt, expectedTransactionHash, diff --git a/packages/web3-eth/test/unit/utils/watch_transaction_for_confirmations.test.ts b/packages/web3-eth/test/unit/utils/watch_transaction_for_confirmations.test.ts index 21f630c8bd1..d4a73939b05 100644 --- a/packages/web3-eth/test/unit/utils/watch_transaction_for_confirmations.test.ts +++ b/packages/web3-eth/test/unit/utils/watch_transaction_for_confirmations.test.ts @@ -26,7 +26,7 @@ import * as rpcMethodWrappers from '../../../src/rpc_method_wrappers'; import * as WaitForTransactionReceipt from '../../../src/utils/wait_for_transaction_receipt'; import * as WatchTransactionForConfirmations from '../../../src/utils/watch_transaction_for_confirmations'; -import * as WatchTransactionByPolling from '../../../src/utils/watch_transaction_by_pooling'; +import * as WatchTransactionByPolling from '../../../src/utils/watch_transaction_by_polling'; import * as WatchTransactionBySubscription from '../../../src/utils/watch_transaction_by_subscription'; import { expectedTransactionReceipt, @@ -38,7 +38,7 @@ import { SendSignedTransactionEvents } from '../../../src/types'; jest.mock('web3-rpc-methods'); jest.mock('../../../src/utils/wait_for_transaction_receipt'); -jest.mock('../../../src/utils/watch_transaction_by_pooling'); +jest.mock('../../../src/utils/watch_transaction_by_polling'); jest.mock('../../../src/utils/watch_transaction_by_subscription'); const testMessage = @@ -164,7 +164,7 @@ describe('watchTransactionForConfirmations', () => { ); }); - describe('should call watchTransactionByPooling when the provider does not support subscription', () => { + describe('should call watchTransactionByPolling when the provider does not support subscription', () => { let web3Context: Web3Context; beforeAll(() => { diff --git a/packages/web3-net/src/net.ts b/packages/web3-net/src/net.ts index 976f1206d20..eb84e567bb5 100644 --- a/packages/web3-net/src/net.ts +++ b/packages/web3-net/src/net.ts @@ -21,7 +21,24 @@ import * as rpcMethodsWrappers from './rpc_method_wrappers.js'; /** * Net class allows you to interact with an Ethereum node’s network properties. - */ +* For using Net package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager, after that Net features can be used. +* ```ts +* +* import { Web3 } from 'web3'; +* const web3 = new Web3('https://mainnet.infura.io/v3/'); +* +* console.log(await web3.eth.net.getId()); +* +* ``` +* For using individual package install `web3-net` packages using: `npm i web3-net` or `yarn add web3-net`. +* +* ```ts +* import {Net} from 'web3-net'; +* +* const net = new Net('https://mainnet.infura.io/v3/'); +* console.log(await net.getId()); +* ``` +*/ export class Net extends Web3Context { /** * Gets the current network ID diff --git a/packages/web3-providers-ws/test/integration/ganache_fault_tolerance.test.ts b/packages/web3-providers-ws/test/integration/ganache_fault_tolerance.test.ts index 4a0ba982996..30078527ca2 100644 --- a/packages/web3-providers-ws/test/integration/ganache_fault_tolerance.test.ts +++ b/packages/web3-providers-ws/test/integration/ganache_fault_tolerance.test.ts @@ -267,7 +267,7 @@ describeIf(getSystemTestBackend() === 'ganache' && isWs)('ganache tests', () => const errorPromise = new Promise(resolve => { webSocketProvider.on('error', (err: any) => { expect(err).toBeInstanceOf(InvalidResponseError); - if (err.innerError.message === 'Chunk timeout') { + if (err.cause.message === 'Chunk timeout') { resolve(true); } }); diff --git a/packages/web3-utils/src/chunk_response_parser.ts b/packages/web3-utils/src/chunk_response_parser.ts index d9b37c7b6ee..629323415cb 100644 --- a/packages/web3-utils/src/chunk_response_parser.ts +++ b/packages/web3-utils/src/chunk_response_parser.ts @@ -25,10 +25,12 @@ export class ChunkResponseParser { private _clearQueues: (() => void) | undefined; private readonly eventEmitter: EventEmitter; private readonly autoReconnect: boolean; + private readonly chunkTimout: number; public constructor(eventEmitter: EventEmitter, autoReconnect: boolean) { this.eventEmitter = eventEmitter; this.autoReconnect = autoReconnect; + this.chunkTimout = 1000 * 15; } private clearQueues(): void { if (typeof this._clearQueues === 'function') { @@ -81,7 +83,7 @@ export class ChunkResponseParser { error: { code: 2, message: 'Chunk timeout' }, }), ); - }, 1000 * 15); + }, this.chunkTimout); return; } diff --git a/packages/web3-utils/src/converters.ts b/packages/web3-utils/src/converters.ts index 83348b4a211..a93eea80cf0 100644 --- a/packages/web3-utils/src/converters.ts +++ b/packages/web3-utils/src/converters.ts @@ -221,6 +221,7 @@ export const hexToNumberString = (data: HexString): string => hexToNumber(data). * ```ts * console.log(utf8ToHex('web3.js')); * > "0x776562332e6a73" + * ``` * */ export const utf8ToHex = (str: string): HexString => { diff --git a/packages/web3-utils/src/hash.ts b/packages/web3-utils/src/hash.ts index 3d8ec866d01..bb4bbd44636 100644 --- a/packages/web3-utils/src/hash.ts +++ b/packages/web3-utils/src/hash.ts @@ -16,6 +16,27 @@ along with web3.js. If not, see . */ /** + * This package provides utility functions for Ethereum dapps and other web3.js packages. + * + * For using Utils functions, first install Web3 package using `npm i web3` or `yarn add web3`. + * After that, Web3 Utils functions will be available as mentioned below. + * ```ts + * import { Web3 } from 'web3'; + * const web3 = new Web3(); + * + * const value = web3.utils.fromWei("1", "ether") + * + * ``` + * + * For using individual package install `web3-utils` package using `npm i web3-utils` or `yarn add web3-utils` and only import required functions. + * This is more efficient approach for building lightweight applications. + * ```ts + * import { fromWei, soliditySha3Raw } from 'web3-utils'; + * + * console.log(fromWei("1", "ether")); + * console.log(soliditySha3Raw({ type: "string", value: "helloworld" })) + * + * ``` * @module Utils */ @@ -342,7 +363,6 @@ export const encodePacked = (...values: Sha3Input[]): string => { * * @example * ```ts - * console.log([{ type: 'string', value: '31323334' }]); * console.log(web3.utils.soliditySha3({ type: "string", value: "31323334" })); * > 0xf15f8da2ad27e486d632dc37d24912f634398918d6f9913a0a0ff84e388be62b * ``` diff --git a/packages/web3-utils/test/fixtures/converters.ts b/packages/web3-utils/test/fixtures/converters.ts index 42d992ec34a..464c196b32d 100644 --- a/packages/web3-utils/test/fixtures/converters.ts +++ b/packages/web3-utils/test/fixtures/converters.ts @@ -326,6 +326,8 @@ export const bytesToUint8ArrayValidData: [Bytes, Uint8Array][] = [ ['0X12c6', new Uint8Array([18, 198])], ['0X01', new Uint8Array([1])], ['0X00', new Uint8Array([0])], + ['0X00', new Uint8Array([0])], + ['0x1234', new Uint8Array([18, 52])], ['0x1234', new Uint8Array([18, 52])], [new Uint8Array(hexToBytes('0c12')), new Uint8Array(hexToBytes('0c12'))], ]; @@ -335,6 +337,7 @@ export const toBigIntValidData: [any, bigint][] = [ [24, BigInt(24)], ['123', BigInt(123)], ['0x04', BigInt(4)], + ['-0x1', -BigInt(1)], ]; export const toBigIntInvalidData: [any, string][] = [ @@ -342,3 +345,25 @@ export const toBigIntInvalidData: [any, string][] = [ ['wwwww', ' Error: can not parse as number data'], ['zzzzee0xiiuu', ' Error: can not parse as number data'], ]; + +export const toBoolValidData: [boolean | string | number | unknown, boolean][] = [ + [true, true], + [false, false], + [0, false], + [1, true], + [BigInt(1), true], + [BigInt(0), false], + ['true', true], + ['false', false], + ['1', true], + ['0', false], + ['0x0', false], + ['0x1', true], +]; + +export const toBoolInvalidData: [boolean | string | number | unknown, string][] = [ + [100, 'not a valid boolean'], + [BigInt(100), 'not a valid boolean'], + ['100', 'not a valid boolean'], + [{}, 'not a valid boolean'], +]; diff --git a/packages/web3-utils/test/fixtures/hugeData.ts b/packages/web3-utils/test/fixtures/hugeData.ts new file mode 100644 index 00000000000..0470ae6c807 --- /dev/null +++ b/packages/web3-utils/test/fixtures/hugeData.ts @@ -0,0 +1,29 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +export const hugeData = { + data: '{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f8192","result":"0x1414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141"}\n{"jsonrpc":"2.0","id":"1b10c675-5eac-4c80-b300-36085d63d5f4","result":"0xd5"}\n{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f819c","result":"0xd5"}\n{"jsonrpc":"2.0","id":"bba428bf-6726-425a-8cbc-2ed7c9448ee7","result":{"blockHash":"0xccfea468ce813e63d59be075dd71de76d4236fa3292dc3b4cc5e6f15c27c3ad1","blockNumber":"0xd4","contractAddress":null,"cumulativeGasUsed":"0xad8c516","effectiveGasPrice":"0x9502f907","from":"0x12b1d9d74d73b1c3a245b19c1c5501c653af1af9","gasUsed":"0x22b5a9e","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":"0xf362b2285d41dc806fd61b92f7c192006b707f42","transactionHash":"0x01ab900543af6d9dbb27b21cf62339c07bfd6d1acdc01f66c932ed8f3c731412","transactionIndex":"0x4","type":"0x2"}}\n', + result: [ + JSON.parse( + '{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f8192","result":"0x1414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141"}', + ), + JSON.parse('{"jsonrpc":"2.0","id":"1b10c675-5eac-4c80-b300-36085d63d5f4","result":"0xd5"}'), + JSON.parse('{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f819c","result":"0xd5"}'), + JSON.parse( + '{"jsonrpc":"2.0","id":"bba428bf-6726-425a-8cbc-2ed7c9448ee7","result":{"blockHash":"0xccfea468ce813e63d59be075dd71de76d4236fa3292dc3b4cc5e6f15c27c3ad1","blockNumber":"0xd4","contractAddress":null,"cumulativeGasUsed":"0xad8c516","effectiveGasPrice":"0x9502f907","from":"0x12b1d9d74d73b1c3a245b19c1c5501c653af1af9","gasUsed":"0x22b5a9e","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","status":"0x1","to":"0xf362b2285d41dc806fd61b92f7c192006b707f42","transactionHash":"0x01ab900543af6d9dbb27b21cf62339c07bfd6d1acdc01f66c932ed8f3c731412","transactionIndex":"0x4","type":"0x2"}}\n', + ), + ], +}; diff --git a/packages/web3-utils/test/unit/chunk_response_parser.test.ts b/packages/web3-utils/test/unit/chunk_response_parser.test.ts new file mode 100644 index 00000000000..1fc08c2fceb --- /dev/null +++ b/packages/web3-utils/test/unit/chunk_response_parser.test.ts @@ -0,0 +1,74 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { EventEmitter } from 'events'; +import { InvalidResponseError } from 'web3-errors'; +import { ChunkResponseParser } from '../../src/chunk_response_parser'; +import { hugeData } from '../fixtures/hugeData'; + +jest.setTimeout(20000); +describe('chunk_response_parser', () => { + let parser: ChunkResponseParser; + let eventEmiter: EventEmitter; + beforeEach(() => { + eventEmiter = new EventEmitter(); + parser = new ChunkResponseParser(eventEmiter, false); + }); + it('clearQueue', () => { + const clearQueue = jest.fn(); + parser.onError(clearQueue); + // @ts-expect-error call private method + parser.clearQueues(); + expect(clearQueue).toHaveBeenCalled(); + }); + it('parse response', () => { + const res = parser.parseResponse(hugeData.data); + expect(res).toEqual(hugeData.result); + }); + + it('parse response with last chunk mechanism', () => { + parser.parseResponse( + '{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f8192","result":"0x141414141', + ); + parser.parseResponse('123'); + const res = parser.parseResponse('14141"}\n'); + expect(res[0]).toEqual({ + jsonrpc: '2.0', + id: '96aa3f13-077c-4c82-a64a-64b8626f8192', + result: '0x14141414112314141', + }); + }); + + it('lastChunkTimeout error', async () => { + // @ts-expect-error set private property + parser.chunkTimout = 10; + parser.parseResponse( + '{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f8192","result":"0x141414141', + ); + const onError = jest.fn(); + eventEmiter.on('error', onError); + // eslint-disable-next-line no-promise-executor-return + await new Promise(resolve => setTimeout(resolve, 1000)); + expect(onError).toHaveBeenCalledWith( + new InvalidResponseError({ + id: 1, + jsonrpc: '2.0', + error: { code: 2, message: 'Chunk timeout' }, + }), + ); + }); +}); diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts index 88e2f4c2385..cb6fa58caa0 100644 --- a/packages/web3-utils/test/unit/converters.test.ts +++ b/packages/web3-utils/test/unit/converters.test.ts @@ -40,6 +40,7 @@ import { toChecksumAddress, bytesToUint8Array, toBigInt, + toBool, } from '../../src/converters'; import { @@ -71,6 +72,8 @@ import { toBigIntInvalidData, toCheckSumInvalidData, numberToHexstrictValidData, + toBoolValidData, + toBoolInvalidData, } from '../fixtures/converters'; describe('converters', () => { @@ -403,4 +406,18 @@ describe('converters', () => { }); }); }); + + describe('toBool', () => { + describe('valid cases', () => { + it.each(toBoolValidData)('%s', (input, output) => { + expect(toBool(input)).toEqual(output); + }); + }); + + describe('invalid cases', () => { + it.each(toBoolInvalidData)('%s', (input, output) => { + expect(() => toBool(input)).toThrow(output); + }); + }); + }); }); diff --git a/packages/web3/test/e2e_manual/data.test.ts b/packages/web3/test/e2e_manual/data.test.ts deleted file mode 100644 index eb57a6ebab8..00000000000 --- a/packages/web3/test/e2e_manual/data.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* -This file is part of web3.js. - -web3.js is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -web3.js is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with web3.js. If not, see . -*/ - -/* eslint-disable */ -import { Web3 } from 'web3'; -import WebSocketProvider from 'web3-providers-ws'; -import accounts from '../../../../scripts/accounts.json'; -import { isWs, isIpc, getSystemTestProvider } from '../../../../scripts/system_tests_utils'; -import { BasicAbi, BasicBytecode } from '../../../../fixtures/build/Basic'; - -const DATA_AMOUNT = 50 * 1024; // 50 kB - -const sendAndGetData = async (web3: Web3, i: number) => { - const sendOptions = { from: accounts[i].address }; - const deployOptions = { - data: BasicBytecode, - arguments: [0, ''] as [number, string], - gasPrice: await web3.eth.getGasPrice(), - gas: BigInt(9000000000000), - gasLimit: BigInt(9000000000000), - type: BigInt(0), - }; - const c = new web3.eth.Contract(BasicAbi); - const contract = await c.deploy(deployOptions).send(sendOptions); - - await contract.methods - .setValues(1, 'A'.repeat(DATA_AMOUNT), true) - .send({ from: accounts[i].address }); - - await contract.methods.getStringValue().call(); -}; - -describe('huge data', () => { - let web3: Web3; - beforeAll(() => { - web3 = new Web3(getSystemTestProvider()); - }); - afterAll(() => { - if (isWs || isIpc) { - (web3.provider as unknown as WebSocketProvider).disconnect(); - } - }); - - it('send and get', async () => { - for (const a of accounts) { - const acc = web3.eth.accounts.privateKeyToAccount(a.privateKey); - web3.eth.accounts.wallet.add(acc); - } - - const prs = []; - for (let i = 0; i < 15; i++) { - prs.push(sendAndGetData(web3, i)); - } - await Promise.all(prs); - }); -}); diff --git a/packages/web3/test/e2e_manual/jest.config.js b/packages/web3/test/e2e_manual/jest.config.js deleted file mode 100644 index 7ce09e43a4b..00000000000 --- a/packages/web3/test/e2e_manual/jest.config.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const base = require('../config/jest.config'); - -module.exports = { - ...base, - setupFilesAfterEnv: ['/test/e2e/setup.js'], - testMatch: [`/test/e2e_manual/**/*.(spec|test).(js|ts)`], - /** - * restoreMocks [boolean] - * - * Default: false - * - * Automatically restore mock state between every test. - * Equivalent to calling jest.restoreAllMocks() between each test. - * This will lead to any mocks having their fake implementations removed - * and restores their initial implementation. - */ - restoreMocks: true, - - /** - * resetModules [boolean] - * - * Default: false - * - * By default, each test file gets its own independent module registry. - * Enabling resetModules goes a step further and resets the module registry before running each individual test. - * This is useful to isolate modules for every test so that local module state doesn't conflict between tests. - * This can be done programmatically using jest.resetModules(). - */ - resetModules: true, -}; diff --git a/packages/web3/test/e2e_manual/requests.test.ts b/packages/web3/test/e2e_manual/requests.test.ts deleted file mode 100644 index b79e09fd573..00000000000 --- a/packages/web3/test/e2e_manual/requests.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* -This file is part of web3.js. - -web3.js is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -web3.js is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with web3.js. If not, see . -*/ - -/* eslint-disable */ -import WebSocketProvider from 'web3-providers-ws'; -import { Web3Account } from 'web3-eth-accounts'; -import { Web3, Contract, Numbers, EventLog } from 'web3'; -import { BasicBytecode, BasicAbi } from '../../../../fixtures/build/Basic'; -import { isWs, isIpc, getSystemTestProvider } from '../../../../scripts/system_tests_utils'; - -const contracts: { [key: string]: Contract } = {}; - -const deployContracts = async (web3: Web3, accounts: Web3Account[]) => { - const prs = []; - for (let i = 0; i < accounts.length; i++) { - const account = accounts[i]; - const sendOptions = { from: account.address }; - const deployOptions = { - data: BasicBytecode, - arguments: [123, ''] as [number, string], - gas: BigInt(9000000000000), - gasLimit: BigInt(9000000000000), - type: BigInt(0), - }; - const c = new web3.eth.Contract(BasicAbi); - prs.push( - c - .deploy(deployOptions) - .send(sendOptions) - .then((contract: typeof c) => { - contracts[account.address] = contract; - }), - ); - } - await Promise.all(prs); -}; - -const addAccount = async ( - web3: Web3, - mainAcc: string, - address: string, - privateKey: string, - nonce: Numbers, -) => { - web3.eth.accounts.wallet.add(privateKey); - return web3.eth.sendTransaction({ - from: mainAcc, - to: address, - nonce, - gas: 1500000, - value: '1000000000000000000', - }); -}; - -const prepareAccounts = async (web3: Web3, n = 1000) => { - const prs = []; - const list = await web3.eth.personal.getAccounts(); - const mainAcc = list[0]; - const accountList: Web3Account[] = []; - const nonce = await web3.eth.getTransactionCount(mainAcc); - for (let i = 0; i < n; i++) { - const acc = web3.eth.accounts.create(); - prs.push(addAccount(web3, mainAcc, acc.address, acc.privateKey, Number(nonce) + i)); - accountList.push(acc); - } - await Promise.all(prs); - return accountList; -}; - -const sendData = async (account: Web3Account) => { - const contract = contracts[account.address]; - return contract.methods - .firesStringEvent(`String event: ${account.address}`) - .send({ from: account.address }); -}; - -const getData = async (account: Web3Account) => { - const contract = contracts[account.address]; - await contract.methods.getStringValue().call(); -}; - -const receivedEvents: { [key: string]: EventLog } = {}; -const subscribeContract = (acc: Web3Account) => { - const contract = contracts[acc.address]; - const event = contract.events.StringEvent(); - - event.on('data', res => { - if (res.returnValues.str !== `String event: ${acc.address}`) { - throw new Error('Event is not correct'); - } - receivedEvents[acc.address] = res; - }); -}; -const contractSubscriptions = (accounts: Web3Account[]) => { - for (const acc of accounts) { - subscribeContract(acc); - } -}; - -describe('huge data', () => { - let web3: Web3; - let parallelCount = 100; - let accounts: Web3Account[] = []; - beforeAll(async () => { - parallelCount = isIpc ? 5 : parallelCount; - web3 = new Web3(getSystemTestProvider()); - accounts = await prepareAccounts(web3, parallelCount); - await deployContracts(web3, accounts); - }); - afterAll(() => { - if (isWs || isIpc) { - (web3.provider as unknown as WebSocketProvider).disconnect(); - } - }); - it('send requests', async () => { - const sendPrs = []; - for (let i = 0; i < parallelCount; i++) { - sendPrs.push(sendData(accounts[i])); - } - await Promise.all(sendPrs); - // if socket subscribe to events - if (isIpc || isWs) { - contractSubscriptions(accounts); - } - }); - it('get requests', async () => { - const getPrs = []; - for (let i = 0; i < parallelCount; i++) { - getPrs.push(getData(accounts[i])); - } - await Promise.all(getPrs); - }); -}); diff --git a/packages/web3/test/e2e_manual/validation.test.ts b/packages/web3/test/e2e_manual/validation.test.ts deleted file mode 100644 index 7ef7e44ef4c..00000000000 --- a/packages/web3/test/e2e_manual/validation.test.ts +++ /dev/null @@ -1,183 +0,0 @@ -/* -This file is part of web3.js. - -web3.js is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -web3.js is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with web3.js. If not, see . -*/ - -import { Web3Validator, Json, JsonSchema, ValidationSchemaInput } from 'web3-validator'; - -const abi = [ - { indexed: true, internalType: 'address', name: 'from', type: 'address' }, - { indexed: true, internalType: 'address', name: 'to', type: 'address' }, - { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' }, -]; - -const abiJsonSchema = { - type: 'array', - items: [ - { name: 'from', format: 'address' }, - { name: 'to', format: 'address' }, - { name: 'value', format: 'uint256' }, - ], -}; - -const abiData = [ - '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', -]; - -const simpleSchema = { - type: 'object', - required: ['blockHash', 'blockNumber', 'from', 'to', 'data'], - properties: { - blockHash: { - format: 'bytes32', - }, - blockNumber: { - format: 'uint', - }, - from: { - format: 'address', - }, - to: { - oneOf: [{ format: 'address' }, { type: 'null' }], - }, - data: { - format: 'bytes', - }, - }, -}; - -const simpleData = { - blockHash: '0x0dec0518fa672a70027b04c286582e543ab17319fbdd384fa7bc8f3d5a542c0b', - blockNumber: BigInt(2), - from: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - to: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - data: '0xafea', -} as unknown as ValidationSchemaInput; - -const createHugeSchema = ( - schema: JsonSchema, - data: Json, - n = 3, -): { schema: JsonSchema; data: Json } => { - if (n > 0) { - const { data: resultData, schema: resultSchema } = createHugeSchema( - { ...simpleSchema } as JsonSchema, - { ...simpleData } as Json, - n - 1, - ); - return { - data: { ...(data as unknown as object), simple: resultData }, - schema: { ...schema, properties: { ...schema.properties, simple: resultSchema } }, - }; - } - return { - schema, - data, - }; -}; - -const { schema: hugeSchema, data: hugeData } = createHugeSchema( - { ...simpleSchema } as JsonSchema, - { ...simpleData } as Json, - 500, -); - -const { schema: hugeSchema1000, data: hugeData1000 } = createHugeSchema( - { ...simpleSchema } as JsonSchema, - { ...simpleData } as Json, - 1000, -); -describe('validator', () => { - let validator: Web3Validator; - beforeAll(() => { - validator = new Web3Validator(); - }); - - it('huge schema', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - validator.validateJSONSchema(hugeSchema, hugeData as object); - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(6000); - expect(t).toBeGreaterThan(0); - }); - - it('huge schema 1000', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - validator.validateJSONSchema(hugeSchema1000, hugeData1000 as object); - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(6000); - expect(t).toBeGreaterThan(0); - }); - - it('simple schema multiple times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 500; i += 1) { - validator.validateJSONSchema(simpleSchema, simpleData as object); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(3000); - expect(t).toBeGreaterThan(0); - }); - - it('simple schema 1000 times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 1000; i += 1) { - validator.validateJSONSchema(simpleSchema, simpleData as object); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(4000); - expect(t).toBeGreaterThan(0); - }); - - it('simple JSON schema 1000 times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 1000; i += 1) { - validator.validateJSONSchema(abiJsonSchema, abiData as object); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(4000); - expect(t).toBeGreaterThan(0); - }); - - it('simple ABI 1000 times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 1000; i += 1) { - validator.validate(abi, abiData); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(4000); - expect(t).toBeGreaterThan(0); - }); -}); diff --git a/packages/web3/test/integration/web3-plugin-add-tx.test.ts b/packages/web3/test/integration/web3-plugin-add-tx.test.ts index 13a3e0df615..9b5bad43fa1 100644 --- a/packages/web3/test/integration/web3-plugin-add-tx.test.ts +++ b/packages/web3/test/integration/web3-plugin-add-tx.test.ts @@ -31,6 +31,7 @@ class Eip4844Plugin extends Web3PluginBase { public pluginNamespace = 'txType3'; public constructor() { super(); + // eslint-disable-next-line this.registerNewTransactionType(TRANSACTION_TYPE, SomeNewTxTypeTransaction); } } diff --git a/scripts/docshelper/functionsdoc.config.js b/scripts/docshelper/functionsdoc.config.js index 35d04a44ddd..1c606fbf540 100644 --- a/scripts/docshelper/functionsdoc.config.js +++ b/scripts/docshelper/functionsdoc.config.js @@ -8,7 +8,14 @@ module.exports = { "./packages/web3-eth-accounts/src/account.ts", //utils "./packages/web3-utils/src/converters.ts", - "./packages/web3-utils/src/hash.ts" + "./packages/web3-utils/src/hash.ts", + //ABI + "./packages/web3-eth-abi/src/api/functions_api.ts", + "./packages/web3-eth-abi/src/eip_712.ts", + "./packages/web3-eth-abi/src/api/errors_api.ts", + "./packages/web3-eth-abi/src/api/events_api.ts", + "./packages/web3-eth-abi/src/api/logs_api.ts", + "./packages/web3-eth-abi/src/api/parameters_api.ts" ], mergeModulesMergeMode: "module", // NEW option of TypeDoc added by typedoc-plugin-merge-modules plugin