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

Commit d966042

Browse files
nazarhussainjdevcs
andauthored
🎨 Improve the nullish value usage around the codebase (#5095)
* 🎨 Update the usage of "null" around the codebase * 🎨 Update value check to avoid prototype pollution * 🚨 Fix all lint errors for null values * 🚨 Add linting rules * 🎨 Update json-rpc "null" validation * 🎨 Update the legacy provider error type to accept "null" * Apply suggestions from code review Co-authored-by: Junaid <[email protected]> * 🎨 Improve the tests to make sure transaction complete in each test case Co-authored-by: Junaid <[email protected]>
1 parent f60b919 commit d966042

File tree

107 files changed

+1371
-412
lines changed

Some content is hidden

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

107 files changed

+1371
-412
lines changed

packages/web3-common/src/deferred_promise.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class DeferredPromise<T> implements Promise<T> {
7171
return this._promise.catch(onrejected);
7272
}
7373

74-
public async finally(onfinally?: (() => void) | null): Promise<T> {
74+
public async finally(onfinally?: (() => void) | undefined): Promise<T> {
7575
return this._promise.finally(onfinally);
7676
}
7777

packages/web3-common/src/eth_execution_api.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export interface TransactionCall {
5555
}
5656

5757
export interface BaseTransaction {
58-
readonly to?: Address | null;
58+
readonly to?: Address;
5959
readonly type: HexStringSingleByte;
6060
readonly nonce: Uint;
6161
readonly gas: Uint;
@@ -113,11 +113,11 @@ export type TransactionSigned =
113113

114114
// https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.json#L269
115115
export type TransactionInfo = TransactionSigned & {
116-
readonly blockHash: HexString32Bytes | null;
117-
readonly blockNumber: Uint | null;
116+
readonly blockHash?: HexString32Bytes;
117+
readonly blockNumber?: Uint;
118118
readonly from: Address;
119119
readonly hash: HexString32Bytes;
120-
readonly transactionIndex: Uint | null;
120+
readonly transactionIndex?: Uint;
121121
};
122122

123123
// https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.json#L24
@@ -131,34 +131,34 @@ export interface Block {
131131
readonly stateRoot: HexString32Bytes;
132132
readonly transactionsRoot: HexString32Bytes;
133133
readonly receiptsRoot: HexString32Bytes;
134-
readonly logsBloom: HexString256Bytes | null;
134+
readonly logsBloom?: HexString256Bytes;
135135
readonly difficulty?: Uint;
136-
readonly number: Uint | null;
136+
readonly number?: Uint;
137137
readonly gasLimit: Uint;
138138
readonly gasUsed: Uint;
139139
readonly timestamp: Uint;
140140
readonly extraData: HexStringBytes;
141141
readonly mixHash: HexString32Bytes;
142-
readonly nonce: Uint | null;
142+
readonly nonce?: Uint;
143143
readonly totalDifficulty: Uint;
144144
readonly baseFeePerGas?: Uint;
145145
readonly size: Uint;
146146
readonly transactions: TransactionHash[] | TransactionInfo[];
147147
readonly uncles: Uncles;
148-
readonly hash: HexString32Bytes | null;
148+
readonly hash?: HexString32Bytes;
149149
}
150150

151151
// https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.json#L2
152152
export interface Log {
153153
readonly removed?: boolean;
154-
readonly logIndex?: Uint | null;
155-
readonly transactionIndex?: Uint | null;
156-
readonly transactionHash?: HexString32Bytes | null;
157-
readonly blockHash?: HexString32Bytes | null;
158-
readonly blockNumber?: Uint | null;
154+
readonly logIndex?: Uint;
155+
readonly transactionIndex?: Uint;
156+
readonly transactionHash?: HexString32Bytes;
157+
readonly blockHash?: HexString32Bytes;
158+
readonly blockNumber?: Uint;
159159
readonly address?: Address;
160160
readonly data?: HexStringBytes;
161-
readonly topics?: null | Topic | Topic[];
161+
readonly topics?: Topic | Topic[];
162162
}
163163

164164
// https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.json#L44
@@ -171,7 +171,7 @@ export interface ReceiptInfo {
171171
readonly to: Address;
172172
readonly cumulativeGasUsed: Uint;
173173
readonly gasUsed: Uint;
174-
readonly contractAddress: Address | null;
174+
readonly contractAddress?: Address;
175175
readonly logs: Log[];
176176
readonly logsBloom: HexString256Bytes;
177177
readonly root: HexString32Bytes;
@@ -224,16 +224,16 @@ export type EthExecutionAPI = {
224224
eth_getUncleByBlockNumberAndIndex: (blockNumber: BlockNumberOrTag, uncleIndex: Uint) => Block;
225225

226226
// https://github.com/ethereum/execution-apis/blob/main/src/eth/transaction.json
227-
eth_getTransactionByHash: (transactionHash: HexString32Bytes) => TransactionInfo | null;
227+
eth_getTransactionByHash: (transactionHash: HexString32Bytes) => TransactionInfo | undefined;
228228
eth_getTransactionByBlockHashAndIndex: (
229229
blockHash: HexString32Bytes,
230230
transactionIndex: Uint,
231-
) => TransactionInfo | null;
231+
) => TransactionInfo | undefined;
232232
eth_getTransactionByBlockNumberAndIndex: (
233233
blockNumber: BlockNumberOrTag,
234234
transactionIndex: Uint,
235-
) => TransactionInfo | null;
236-
eth_getTransactionReceipt: (transactionHash: HexString32Bytes) => ReceiptInfo | null;
235+
) => TransactionInfo | undefined;
236+
eth_getTransactionReceipt: (transactionHash: HexString32Bytes) => ReceiptInfo | undefined;
237237

238238
// https://github.com/ethereum/execution-apis/blob/main/src/eth/client.json
239239
eth_protocolVersion: () => string;

packages/web3-common/src/formatter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
numberToHex,
2626
toBigInt,
2727
} from 'web3-utils';
28-
import { isObject, JsonSchema, utils, ValidationSchemaInput } from 'web3-validator';
28+
import { isNullish, isObject, JsonSchema, utils, ValidationSchemaInput } from 'web3-validator';
2929

3030
const { parseBaseType } = utils;
3131

@@ -159,7 +159,7 @@ export const convert = (
159159
const schemaProp = findSchemaByDataPath(schema, dataPath);
160160

161161
// If value is a scaler value
162-
if (schemaProp === undefined) {
162+
if (isNullish(schemaProp)) {
163163
delete object[key];
164164
dataPath.pop();
165165

@@ -175,7 +175,7 @@ export const convert = (
175175

176176
// If value is an array
177177
if (Array.isArray(value)) {
178-
if (schemaProp?.items === undefined) {
178+
if (isNullish(schemaProp?.items)) {
179179
// Can not find schema for array item, delete that item
180180
delete object[key];
181181
dataPath.pop();
@@ -184,7 +184,7 @@ export const convert = (
184184
}
185185

186186
// If schema for array items is a single type
187-
if (isObject(schemaProp.items) && schemaProp.items.eth !== undefined) {
187+
if (isObject(schemaProp.items) && !isNullish(schemaProp.items.eth)) {
188188
for (let i = 0; i < value.length; i += 1) {
189189
(object[key] as unknown[])[i] = convertScalarValue(
190190
value[i],

packages/web3-common/src/formatters.ts

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
toUtf8,
3636
utf8ToHex,
3737
} from 'web3-utils';
38-
import { isBlockTag, isHex } from 'web3-validator';
38+
import { isBlockTag, isHex, isNullish } from 'web3-validator';
3939
import {
4040
BlockInput,
4141
BlockOutput,
@@ -55,11 +55,15 @@ import {
5555

5656
/**
5757
* Will format the given storage key array values to hex strings.
58+
*
59+
* @param keys
5860
*/
5961
export const inputStorageKeysFormatter = (keys: Array<string>) => keys.map(numberToHex);
6062

6163
/**
6264
* Will format the given proof response from the node.
65+
*
66+
* @param proof
6367
*/
6468
export const outputProofFormatter = (proof: Proof): Proof => ({
6569
address: toChecksumAddress(proof.address),
@@ -69,14 +73,18 @@ export const outputProofFormatter = (proof: Proof): Proof => ({
6973

7074
/**
7175
* Should the format output to a big number
76+
*
77+
* @param number
7278
*/
7379
export const outputBigIntegerFormatter = (number: Numbers) => toNumber(number);
7480

7581
/**
7682
* Returns the given block number as hex string or the predefined block number 'latest', 'pending', 'earliest', 'genesis'
83+
*
84+
* @param blockNumber
7785
*/
7886
export const inputBlockNumberFormatter = (blockNumber: Numbers | undefined) => {
79-
if (blockNumber === undefined) {
87+
if (isNullish(blockNumber)) {
8088
return undefined;
8189
}
8290

@@ -97,6 +105,9 @@ export const inputBlockNumberFormatter = (blockNumber: Numbers | undefined) => {
97105

98106
/**
99107
* Returns the given block number as hex string or does return the defaultBlock property of the current module
108+
*
109+
* @param blockNumber
110+
* @param defaultBlock
100111
*/
101112
export const inputDefaultBlockNumberFormatter = (
102113
blockNumber: Numbers | undefined,
@@ -127,6 +138,8 @@ export const inputAddressFormatter = (address: string): string | never => {
127138

128139
/**
129140
* Formats the input of a transaction and converts all values to HEX
141+
*
142+
* @param options
130143
*/
131144
export const txInputOptionsFormatter = (options: TransactionInput): Mutable<TransactionOutput> => {
132145
const modifiedOptions = { ...options } as unknown as Mutable<TransactionOutput>;
@@ -165,7 +178,7 @@ export const txInputOptionsFormatter = (options: TransactionInput): Mutable<Tran
165178
}
166179

167180
['gasPrice', 'gas', 'value', 'maxPriorityFeePerGas', 'maxFeePerGas', 'nonce', 'chainId']
168-
.filter(key => modifiedOptions[key] !== undefined)
181+
.filter(key => !isNullish(modifiedOptions[key]))
169182
.forEach(key => {
170183
modifiedOptions[key] = numberToHex(modifiedOptions[key] as Numbers);
171184
});
@@ -175,6 +188,9 @@ export const txInputOptionsFormatter = (options: TransactionInput): Mutable<Tran
175188

176189
/**
177190
* Formats the input of a transaction and converts all values to HEX
191+
*
192+
* @param options
193+
* @param defaultAccount
178194
*/
179195
export const inputCallFormatter = (options: TransactionInput, defaultAccount?: string) => {
180196
const opts = txInputOptionsFormatter(options);
@@ -190,6 +206,9 @@ export const inputCallFormatter = (options: TransactionInput, defaultAccount?: s
190206

191207
/**
192208
* Formats the input of a transaction and converts all values to HEX
209+
*
210+
* @param options
211+
* @param defaultAccount
193212
*/
194213
export const inputTransactionFormatter = (options: TransactionInput, defaultAccount?: string) => {
195214
const opts = txInputOptionsFormatter(options);
@@ -210,15 +229,17 @@ export const inputTransactionFormatter = (options: TransactionInput, defaultAcco
210229

211230
/**
212231
* Hex encodes the data passed to eth_sign and personal_sign
232+
*
233+
* @param data
213234
*/
214235
export const inputSignFormatter = (data: string) => (isHexStrict(data) ? data : utf8ToHex(data));
215236

216237
/**
217238
* Formats the output of a transaction to its proper values
218239
*
219-
* @method outputTransactionFormatter
220-
* @param {Object} tx
221-
* @returns {Object}
240+
* @function outputTransactionFormatter
241+
* @param {object} tx
242+
* @returns {object}
222243
*/
223244
export const outputTransactionFormatter = (tx: TransactionInput): TransactionOutput => {
224245
const modifiedTx = { ...tx } as unknown as Mutable<TransactionOutput>;
@@ -266,26 +287,31 @@ export const outputTransactionFormatter = (tx: TransactionInput): TransactionOut
266287
return modifiedTx;
267288
};
268289

290+
// To align with specification we use the type "null" here
291+
// eslint-disable-next-line @typescript-eslint/ban-types
269292
export const inputTopicFormatter = (topic: Topic): Topic | null => {
270-
if (topic === null || typeof topic === 'undefined') return null;
293+
// Using "null" value intentionally for validation
294+
// eslint-disable-next-line no-null/no-null
295+
if (isNullish(topic)) return null;
271296

272297
const value = String(topic);
273298

274299
return isHex(value) ? value : fromUtf8(value);
275300
};
276301

277302
export const inputLogFormatter = (filter: Filter) => {
278-
const val: Mutable<Filter> =
279-
filter === undefined ? {} : mergeDeep({}, filter as Record<string, unknown>);
303+
const val: Mutable<Filter> = isNullish(filter)
304+
? {}
305+
: mergeDeep({}, filter as Record<string, unknown>);
280306

281307
// If options !== undefined, don't blow out existing data
282-
if (val.fromBlock === undefined) {
308+
if (isNullish(val.fromBlock)) {
283309
val.fromBlock = BlockTags.LATEST;
284310
}
285311

286312
val.fromBlock = inputBlockNumberFormatter(val.fromBlock);
287313

288-
if (val.toBlock !== undefined) {
314+
if (!isNullish(val.toBlock)) {
289315
val.toBlock = inputBlockNumberFormatter(val.toBlock);
290316
}
291317

@@ -309,9 +335,9 @@ export const inputLogFormatter = (filter: Filter) => {
309335
/**
310336
* Formats the output of a log
311337
*
312-
* @method outputLogFormatter
313-
* @param {Object} log object
314-
* @returns {Object} log
338+
* @function outputLogFormatter
339+
* @param {object} log object
340+
* @returns {object} log
315341
*/
316342
export const outputLogFormatter = (log: Partial<LogsInput>): LogsOutput => {
317343
const modifiedLog = { ...log } as unknown as Mutable<LogsOutput>;
@@ -353,6 +379,8 @@ export const outputLogFormatter = (log: Partial<LogsInput>): LogsOutput => {
353379

354380
/**
355381
* Formats the output of a transaction receipt to its proper values
382+
*
383+
* @param receipt
356384
*/
357385
export const outputTransactionReceiptFormatter = (receipt: ReceiptInput): ReceiptOutput => {
358386
if (typeof receipt !== 'object') {
@@ -393,9 +421,9 @@ export const outputTransactionReceiptFormatter = (receipt: ReceiptInput): Receip
393421
/**
394422
* Formats the output of a block to its proper values
395423
*
396-
* @method outputBlockFormatter
397-
* @param {Object} block
398-
* @returns {Object}
424+
* @function outputBlockFormatter
425+
* @param {object} block
426+
* @returns {object}
399427
*/
400428
export const outputBlockFormatter = (block: BlockInput): BlockOutput => {
401429
const modifiedBlock = { ...block } as unknown as Mutable<BlockOutput>;
@@ -435,6 +463,8 @@ export const outputBlockFormatter = (block: BlockInput): BlockOutput => {
435463

436464
/**
437465
* Formats the input of a whisper post and converts all values to HEX
466+
*
467+
* @param post
438468
*/
439469
export const inputPostFormatter = (post: PostOutput): PostInput => {
440470
const modifiedPost = { ...post } as unknown as Mutable<PostInput>;
@@ -467,9 +497,10 @@ export const inputPostFormatter = (post: PostOutput): PostInput => {
467497
/**
468498
* Formats the output of a received post message
469499
*
470-
* @method outputPostFormatter
471-
* @param {Object}
472-
* @returns {Object}
500+
* @function outputPostFormatter
501+
* @param post
502+
* @param {object}
503+
* @returns {object}
473504
*/
474505
export const outputPostFormatter = (post: PostInput): PostOutput => {
475506
const modifiedPost = { ...post } as unknown as Mutable<PostOutput>;

0 commit comments

Comments
 (0)