Skip to content

Commit 9fcc858

Browse files
authored
chore: cherry pick fix: Resolve BigInt type mismatch in eth_sendRawTransaction precheck (#3463) to release/0.65 (#3464)
fix: Resolve BigInt type mismatch in eth_sendRawTransaction precheck (#3463) fix: fixed BigInt mismatch types in eth_sendRawTransaction precheck Signed-off-by: Logan Nguyen <[email protected]>
1 parent aa08fa6 commit 9fcc858

File tree

3 files changed

+124
-3
lines changed

3 files changed

+124
-3
lines changed

packages/relay/src/lib/precheck.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ export class Precheck {
169169
*/
170170
gasPrice(tx: Transaction, networkGasPriceInWeiBars: number, requestDetails: RequestDetails): void {
171171
const networkGasPrice = BigInt(networkGasPriceInWeiBars);
172-
const txGasPrice = tx.gasPrice || tx.maxFeePerGas! + tx.maxPriorityFeePerGas!;
172+
173+
const txGasPrice = BigInt(tx.gasPrice || tx.maxFeePerGas! + tx.maxPriorityFeePerGas!);
173174

174175
// **notice: Pass gasPrice precheck if txGasPrice is greater than the minimum network's gas price value,
175176
// OR if the transaction is the deterministic deployment transaction (a special case).
@@ -220,8 +221,9 @@ export class Precheck {
220221
passes: false,
221222
error: predefined.INSUFFICIENT_ACCOUNT_BALANCE,
222223
};
223-
const txGas = tx.gasPrice || tx.maxFeePerGas! + tx.maxPriorityFeePerGas!;
224-
const txTotalValue = tx.value + txGas * tx.gasLimit;
224+
225+
const txGasPrice = BigInt(tx.gasPrice || tx.maxFeePerGas! + tx.maxPriorityFeePerGas!);
226+
const txTotalValue = tx.value + txGasPrice * tx.gasLimit;
225227

226228
if (account == null) {
227229
if (this.logger.isLevelEnabled('trace')) {

packages/relay/tests/lib/precheck.spec.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,44 @@ describe('Precheck', async function () {
345345
const adjustedGasPrice = parsedTxGasPrice + Number(constants.GAS_PRICE_TINY_BAR_BUFFER);
346346
precheck.gasPrice(parsedTxWithMatchingChainId, adjustedGasPrice, requestDetails);
347347
});
348+
349+
it('should pass for gas price if the transaction has valid gasPrice but null maxFeePerGas and null maxPriorityFeePerGas', async function () {
350+
const parsedTx = {
351+
...parsedTxWithMatchingChainId,
352+
gasPrice: BigInt(100),
353+
maxFeePerGas: null,
354+
maxPriorityFeePerGas: null,
355+
} as Transaction;
356+
357+
expect(() => precheck.gasPrice(parsedTx, 50, requestDetails)).to.not.throw();
358+
});
359+
360+
it('should pass for gas price if the transaction has null gasPrice but valid maxFeePerGas and valid maxPriorityFeePerGas', async function () {
361+
const parsedTx = {
362+
...parsedTxWithMatchingChainId,
363+
gasPrice: null,
364+
maxFeePerGas: BigInt(100),
365+
maxPriorityFeePerGas: BigInt(100),
366+
} as Transaction;
367+
368+
expect(() => precheck.gasPrice(parsedTx, 50, requestDetails)).to.not.throw();
369+
});
370+
371+
it('should not pass for gas price if the transaction has null gasPrice and null maxFeePerGas and null maxPriorityFeePerGas', async function () {
372+
const tx = {
373+
...parsedTxWithMatchingChainId,
374+
gasPrice: null,
375+
maxFeePerGas: null,
376+
maxPriorityFeePerGas: null,
377+
};
378+
const signed = await signTransaction(tx);
379+
const parsedTx = ethers.Transaction.from(signed);
380+
const minGasPrice = 1000 * constants.TINYBAR_TO_WEIBAR_COEF;
381+
382+
expect(() => precheck.gasPrice(parsedTx, minGasPrice, requestDetails)).to.throw(
383+
`Gas price '0' is below configured minimum gas price '${minGasPrice}'`,
384+
);
385+
});
348386
});
349387

350388
describe('balance', async function () {
@@ -444,6 +482,68 @@ describe('Precheck', async function () {
444482
const result = precheck.balance(parsedTransaction, account, requestDetails);
445483
expect(result).to.not.exist;
446484
});
485+
486+
it('should calculate balance correctly when transaction has valid gasPrice but null maxFeePerGas and null maxPriorityFeePerGas', async function () {
487+
const tx = {
488+
...parsedTxWithMatchingChainId,
489+
value: BigInt(1000),
490+
gasPrice: BigInt(100),
491+
gasLimit: BigInt(21000),
492+
maxFeePerGas: null,
493+
maxPriorityFeePerGas: null,
494+
} as Transaction;
495+
496+
const account = {
497+
account: accountId,
498+
balance: {
499+
// Set balance higher than value + (gasPrice * gasLimit)
500+
balance: (BigInt(1000) + BigInt(100) * BigInt(21000) + BigInt(1000)).toString(),
501+
},
502+
};
503+
504+
expect(() => precheck.balance(tx, account, requestDetails)).to.not.throw();
505+
});
506+
507+
it('should calculate balance correctly when transaction has null gasPrice but valid maxFeePerGas and maxPriorityFeePerGas', async function () {
508+
const tx = {
509+
...parsedTxWithMatchingChainId,
510+
value: BigInt(1000),
511+
gasPrice: null,
512+
gasLimit: BigInt(21000),
513+
maxFeePerGas: BigInt(100),
514+
maxPriorityFeePerGas: BigInt(100),
515+
} as Transaction;
516+
517+
const account = {
518+
account: accountId,
519+
balance: {
520+
// Set balance higher than value + ((maxFeePerGas + maxPriorityFeePerGas) * gasLimit)
521+
balance: (BigInt(1000) + BigInt(200) * BigInt(21000) + BigInt(1000)).toString(),
522+
},
523+
};
524+
525+
expect(() => precheck.balance(tx, account, requestDetails)).to.not.throw();
526+
});
527+
528+
it('should still pass when transaction has null gasPrice, null maxFeePerGas, and null maxPriorityFeePerGas', async function () {
529+
const tx = {
530+
...parsedTxWithMatchingChainId,
531+
value: BigInt(1000),
532+
gasPrice: null,
533+
gasLimit: BigInt(21000),
534+
maxFeePerGas: null,
535+
maxPriorityFeePerGas: null,
536+
} as Transaction;
537+
538+
const account = {
539+
account: accountId,
540+
balance: {
541+
balance: BigInt(1000).toString(), // Any balance would fail as txTotalValue calculation would error
542+
},
543+
};
544+
545+
expect(() => precheck.balance(tx, account, requestDetails)).to.not.throw();
546+
});
447547
});
448548

449549
describe('nonce', async function () {

packages/server/tests/acceptance/rpc_batch1.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,25 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () {
17361736
expect(info).to.exist;
17371737
expect(info.result).to.equal('SUCCESS');
17381738
});
1739+
1740+
it('should fail "eth_sendRawTransaction" for transaction with null gasPrice, null maxFeePerGas, and null maxPriorityFeePerGas', async function () {
1741+
const transaction = {
1742+
...defaultLegacyTransactionData,
1743+
chainId: Number(CHAIN_ID),
1744+
gasPrice: null,
1745+
maxFeePerGas: null,
1746+
maxPriorityFeePerGas: null,
1747+
to: parentContractAddress,
1748+
nonce: await relay.getAccountNonce(accounts[2].address, requestId),
1749+
};
1750+
const signedTx = await accounts[2].wallet.signTransaction(transaction);
1751+
const error = predefined.GAS_PRICE_TOO_LOW(0, GAS_PRICE_REF);
1752+
1753+
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, false, relay, [
1754+
signedTx,
1755+
requestDetails,
1756+
]);
1757+
});
17391758
});
17401759

17411760
it('@release should execute "eth_getTransactionByHash" for existing transaction', async function () {

0 commit comments

Comments
 (0)