Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit cb742c7

Browse files
Merge branch '4.x' into 6371-uncaught-typeerror-class-extends-value-undefined-is-not-a-constructor-or-null
2 parents 6d0bd23 + 90d78c1 commit cb742c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+89140
-175
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
"buffer": "^6.0.3",
101101
"bufferutil": "^4.0.6",
102102
"clean-webpack-plugin": "^4.0.0",
103+
"concurrently": "^8.2.0",
103104
"cypress-jest-adapter": "^0.1.1",
104105
"declaration-bundler-webpack-plugin": "^1.0.3",
105106
"eslint": "^8.20.0",

packages/web3-core/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,5 @@ Documentation:
183183

184184
### Changed
185185

186-
- defaultTransactionType is now type 0x2 instead of 0x0 (#6282)
186+
- defaultTransactionType is now type 0x2 instead of 0x0 (#6282)
187+
- Allows formatter to parse large base fee (#6456)

packages/web3-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"scripts": {
2626
"clean": "rimraf dist && rimraf lib",
2727
"prebuild": "yarn clean",
28-
"build": "yarn build:cjs & yarn build:esm & yarn build:types",
28+
"build": "concurrently --kill-others-on-fail \"yarn:build:*(!check)\"",
2929
"build:cjs": "tsc --build tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > ./lib/commonjs/package.json",
3030
"build:esm": "tsc --build tsconfig.esm.json && echo '{\"type\": \"module\"}' > ./lib/esm/package.json",
3131
"build:types": "tsc --build tsconfig.types.json",

packages/web3-core/src/formatters.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ export const outputBlockFormatter = (block: BlockInput): BlockOutput => {
450450
}
451451

452452
if (block.baseFeePerGas) {
453-
modifiedBlock.baseFeePerGas = hexToNumber(block.baseFeePerGas);
453+
modifiedBlock.baseFeePerGas = outputBigIntegerFormatter(block.baseFeePerGas);
454454
}
455455

456456
return modifiedBlock;

packages/web3-core/test/unit/formatters.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,12 +537,13 @@ describe('formatters', () => {
537537
});
538538

539539
it('should convert "baseFeePerGas" from hex to number', () => {
540+
jest.spyOn(formatters, 'outputBigIntegerFormatter').mockReturnValue(123);
540541
const result = outputBlockFormatter({
541542
...validBlock,
542543
baseFeePerGas: 'baseFeePerGas',
543544
} as any);
544545

545-
expect(utils.hexToNumber).toHaveBeenCalledWith('baseFeePerGas');
546+
expect(outputBigIntegerFormatter).toHaveBeenCalledWith('baseFeePerGas');
546547
expect(result).toEqual(expect.objectContaining({ baseFeePerGas: hexToNumberResult }));
547548
});
548549
});

packages/web3-core/test/unit/web3_batch_request.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

1818
import { JsonRpcBatchRequest, JsonRpcBatchResponse, JsonRpcOptionalRequest } from 'web3-types';
19-
import { jsonRpc, Web3DeferredPromise } from 'web3-utils';
19+
import { jsonRpc, Web3DeferredPromise, Timeout } from 'web3-utils';
2020
import { OperationAbortError, OperationTimeoutError } from 'web3-errors';
2121
import { Web3BatchRequest } from '../../src/web3_batch_request';
2222

@@ -174,7 +174,7 @@ describe('Web3BatchRequest', () => {
174174
});
175175

176176
it('should timeout if request not executed in a particular time', async () => {
177-
let timerId!: NodeJS.Timeout;
177+
let timerId!: Timeout;
178178

179179
jest.spyOn(requestManager, 'sendBatch').mockImplementation(async () => {
180180
return new Promise(resolve => {

packages/web3-errors/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"scripts": {
2626
"clean": "rimraf dist && rimraf lib",
2727
"prebuild": "yarn clean",
28-
"build": "yarn build:cjs & yarn build:esm & yarn build:types",
28+
"build": "concurrently --kill-others-on-fail \"yarn:build:*(!check)\"",
2929
"build:cjs": "tsc --build tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > ./lib/commonjs/package.json",
3030
"build:esm": "tsc --build tsconfig.esm.json && echo '{\"type\": \"module\"}' > ./lib/esm/package.json",
3131
"build:types": "tsc --build tsconfig.types.json",

packages/web3-errors/src/errors/generic_errors.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ export class OperationAbortError extends BaseWeb3Error {
8383

8484
export class AbiError extends BaseWeb3Error {
8585
public code = ERR_ABI_ENCODING;
86+
public readonly props: Record<string, unknown> & { name?: string };
87+
88+
public constructor(message: string, props?: Record<string, unknown> & { name?: string }) {
89+
super(message);
90+
this.props = props ?? {};
91+
}
8692
}
8793

8894
export class ExistingPluginNamespaceError extends BaseWeb3Error {

packages/web3-eth-abi/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"scripts": {
2626
"clean": "rimraf dist && rimraf lib",
2727
"prebuild": "yarn clean",
28-
"build": "yarn build:cjs & yarn build:esm & yarn build:types",
28+
"build": "concurrently --kill-others-on-fail \"yarn:build:*(!check)\"",
2929
"build:cjs": "tsc --build tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > ./lib/commonjs/package.json",
3030
"build:esm": "tsc --build tsconfig.esm.json && echo '{\"type\": \"module\"}' > ./lib/esm/package.json",
3131
"build:types": "tsc --build tsconfig.types.json",
@@ -42,8 +42,8 @@
4242
"test:integration": "jest --config=./test/integration/jest.config.js --passWithNoTests"
4343
},
4444
"dependencies": {
45-
"@ethersproject/abi": "^5.7.0",
46-
"@ethersproject/bignumber": "^5.7.0",
45+
"abitype": "0.7.1",
46+
"web3-validator": "^2.0.2",
4747
"web3-errors": "^1.1.2",
4848
"web3-types": "^1.2.0",
4949
"web3-utils": "^4.0.6"

packages/web3-eth-abi/src/api/parameters_api.ts

Lines changed: 9 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ GNU Lesser General Public License for more details.
1414
You should have received a copy of the GNU Lesser General Public License
1515
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
17-
1817
import { AbiError } from 'web3-errors';
19-
import { ParamType, Result } from '@ethersproject/abi';
20-
import { HexString, AbiInput, DecodedParams } from 'web3-types';
21-
import ethersAbiCoder from '../ethers_abi_coder.js';
22-
import { formatParam, isAbiFragment, mapTypes, modifyParams } from '../utils.js';
18+
import { AbiInput, HexString } from 'web3-types';
19+
import { decodeParameters as decodeParametersInternal } from '../coders/decode.js';
20+
import { encodeParameters as encodeParametersInternal } from '../coders/encode.js';
2321

2422
/**
2523
* Encodes a parameter based on its type to its ABI representation.
@@ -37,40 +35,8 @@ import { formatParam, isAbiFragment, mapTypes, modifyParams } from '../utils.js'
3735
* > 0x000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000
3836
* ```
3937
*/
40-
export const encodeParameters = (abi: ReadonlyArray<AbiInput>, params: unknown[]): string => {
41-
try {
42-
const modifiedTypes = mapTypes(
43-
Array.isArray(abi) ? (abi as AbiInput[]) : ([abi] as unknown as AbiInput[]),
44-
);
45-
const modifiedParams: Array<unknown> = [];
46-
for (const [index, param] of params.entries()) {
47-
const item = modifiedTypes[index];
48-
let type: string;
49-
50-
if (isAbiFragment(item) && item.type) {
51-
// We may get a named type of shape {name, type}
52-
type = item.type;
53-
} else {
54-
type = item as unknown as string;
55-
}
56-
57-
const newParam = formatParam(type, param);
58-
59-
if (typeof type === 'string' && type.includes('tuple')) {
60-
const coder = ethersAbiCoder._getCoder(ParamType.from(type));
61-
modifyParams(coder, [newParam]);
62-
}
63-
64-
modifiedParams.push(newParam);
65-
}
66-
return ethersAbiCoder.encode(
67-
modifiedTypes.map(p => ParamType.from(p)),
68-
modifiedParams,
69-
);
70-
} catch (err) {
71-
throw new AbiError(`Parameter encoding error`, err as Error);
72-
}
73-
};
38+
export const encodeParameters = (abi: ReadonlyArray<AbiInput>, params: unknown[]): string =>
39+
encodeParametersInternal(abi, params);
7440

7541
/**
7642
* Encodes a parameter based on its type to its ABI representation.
@@ -130,30 +96,6 @@ export const encodeParameters = (abi: ReadonlyArray<AbiInput>, params: unknown[]
13096
*/
13197
export const encodeParameter = (abi: AbiInput, param: unknown): string =>
13298
encodeParameters([abi], [param]);
133-
134-
// If encoded param is an array and there are mixed on integer and string keys
135-
const isParamRequiredToConvert = (data: Result): boolean =>
136-
Array.isArray(data) &&
137-
Object.keys(data).filter(k => Number.isInteger(+k)).length !== Object.keys(data).length;
138-
139-
// Ethers-Encoder return the decoded result as an array with additional string indexes for named params
140-
// We want these to be converted to an object with named keys
141-
const formatArrayResToObject = (data: Result): DecodedParams => {
142-
const returnValue: DecodedParams = {
143-
__length__: 0,
144-
};
145-
146-
for (const key of Object.keys(data)) {
147-
returnValue[key] =
148-
Array.isArray(data[key]) && isParamRequiredToConvert(data[key] as Result)
149-
? formatArrayResToObject(data[key] as Result)
150-
: data[key];
151-
152-
returnValue.__length__ += Number.isInteger(+key) ? 1 : 0;
153-
}
154-
return returnValue;
155-
};
156-
15799
/**
158100
* Should be used to decode list of params
159101
*/
@@ -172,14 +114,11 @@ export const decodeParametersWith = (
172114
'or querying a node which is not fully synced.',
173115
);
174116
}
175-
const res = ethersAbiCoder.decode(
176-
mapTypes(abis).map(p => ParamType.from(p)),
177-
`0x${bytes.replace(/0x/i, '')}`,
178-
loose,
179-
);
180-
return formatArrayResToObject(res);
117+
return decodeParametersInternal(abis, `0x${bytes.replace(/0x/i, '')}`, loose);
181118
} catch (err) {
182-
throw new AbiError(`Parameter decoding error: ${(err as Error).message}`);
119+
throw new AbiError(`Parameter decoding error: ${(err as Error).message}`, {
120+
internalErr: err,
121+
});
183122
}
184123
};
185124

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
This file is part of web3.js.
3+
4+
web3.js is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
web3.js is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public License
15+
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
import { AbiError } from 'web3-errors';
18+
import { AbiParameter } from 'web3-types';
19+
import { toChecksumAddress } from 'web3-utils';
20+
import { isAddress, utils } from 'web3-validator';
21+
import { DecoderResult, EncoderResult } from '../types.js';
22+
import { alloc, WORD_SIZE } from '../utils.js';
23+
24+
const ADDRESS_BYTES_COUNT = 20;
25+
const ADDRESS_OFFSET = WORD_SIZE - ADDRESS_BYTES_COUNT;
26+
27+
export function encodeAddress(param: AbiParameter, input: unknown): EncoderResult {
28+
if (typeof input !== 'string') {
29+
throw new AbiError('address type expects string as input type', {
30+
value: input,
31+
name: param.name,
32+
type: param.type,
33+
});
34+
}
35+
let address = input.toLowerCase();
36+
if (!address.startsWith('0x')) {
37+
address = `0x${address}`;
38+
}
39+
if (!isAddress(address)) {
40+
throw new AbiError('provided input is not valid address', {
41+
value: input,
42+
name: param.name,
43+
type: param.type,
44+
});
45+
}
46+
// for better performance, we could convert hex to destination bytes directly (encoded var)
47+
const addressBytes = utils.hexToUint8Array(address);
48+
// expand address to WORD_SIZE
49+
const encoded = alloc(WORD_SIZE);
50+
encoded.set(addressBytes, ADDRESS_OFFSET);
51+
return {
52+
dynamic: false,
53+
encoded,
54+
};
55+
}
56+
57+
export function decodeAddress(_param: AbiParameter, bytes: Uint8Array): DecoderResult<string> {
58+
const addressBytes = bytes.subarray(ADDRESS_OFFSET, WORD_SIZE);
59+
if (addressBytes.length !== ADDRESS_BYTES_COUNT) {
60+
throw new AbiError('Invalid decoding input, not enough bytes to decode address', { bytes });
61+
}
62+
const result = utils.uint8ArrayToHexString(addressBytes);
63+
64+
// should we check is decoded value is valid address?
65+
// if(!isAddress(result)) {
66+
// throw new AbiError("encoded data is not valid address", {
67+
// address: result,
68+
// });
69+
// }
70+
return {
71+
result: toChecksumAddress(result),
72+
encoded: bytes.subarray(WORD_SIZE),
73+
consumed: WORD_SIZE,
74+
};
75+
}

0 commit comments

Comments
 (0)