Skip to content

Commit ce450f2

Browse files
fix: added support for legacy pre EIP 155 transactions with no chainI… (#2240)
fix: added support for legacy pre EIP 155 transactions with no chainID (chainId=0x0) (#2228) * feat: added support for legacy unprotected ETX pre EIP-155 (chainID=0x0) * test: added new UT for precheck.chainId() with a case that has chainID=0x0 * test: fixed UT to allow support for pre EIP155 txs * feat: added isLegacyUnprotectedEtx() method --------- Signed-off-by: Logan Nguyen <[email protected]> Co-authored-by: Logan Nguyen <[email protected]>
1 parent 6163415 commit ce450f2

File tree

3 files changed

+44
-6
lines changed

3 files changed

+44
-6
lines changed

packages/relay/src/lib/precheck.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export class Precheck {
100100
chainId(tx: Transaction, requestId?: string) {
101101
const requestIdPrefix = formatRequestIdMessage(requestId);
102102
const txChainId = prepend0x(Number(tx.chainId).toString(16));
103-
const passes = txChainId === this.chain;
103+
const passes = this.isLegacyUnprotectedEtx(tx) || txChainId === this.chain;
104104
if (!passes) {
105105
this.logger.trace(
106106
`${requestIdPrefix} Failed chainId precheck for sendRawTransaction(transaction=%s, chainId=%s)`,
@@ -111,6 +111,17 @@ export class Precheck {
111111
}
112112
}
113113

114+
/**
115+
* Checks if the transaction is an (unprotected) pre-EIP155 transaction.
116+
* Conditions include chainId being 0x0 and the signature's v value being either 27 or 28.
117+
* @param tx the Ethereum transaction
118+
*/
119+
isLegacyUnprotectedEtx(tx: Transaction): boolean {
120+
const chainId = tx.chainId;
121+
const vValue = tx.signature?.v;
122+
return chainId === BigInt(0) && (vValue === 27 || vValue === 28);
123+
}
124+
114125
/**
115126
* @param tx
116127
* @param gasPrice

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ describe('Precheck', async function () {
4242
'0x02f87482012a0485a7a358200085a7a3582000832dc6c09400000000000000000000000000000000000003f78502540be40080c001a006f4cd8e6f84b76a05a5c1542a08682c928108ef7163d9c1bf1f3b636b1cd1fba032097cbf2dda17a2dcc40f62c97964d9d930cdce2e8a9df9a8ba023cda28e4ad';
4343
const parsedTxWithMatchingChainId = ethers.Transaction.from(txWithMatchingChainId);
4444
const parsedTxGasPrice = 1440000000000;
45-
const txWithNonMatchingChainId =
45+
const txWithChainId0x0 =
4646
'0xf86a0385a7a3582000832dc6c09400000000000000000000000000000000000003f78502540be400801ca06750e92db52fa708e27f94f27e0cfb7f5800f9b657180bb2e94c1520cfb1fb6da01bec6045068b6db38b55017bb8b50166699384bc1791fd8331febab0cf629a2a';
47+
const parsedtxWithChainId0x0 = ethers.Transaction.from(txWithChainId0x0);
48+
const txWithNonMatchingChainId =
49+
'0xf86c8085a54f4c3c00832dc6c094000000000000000000000000000000000000042f8502540be40080820306a0fe71ab0077a58d112eecc7f95b9a7563ffdc14a45440cc1b2c698dbb1a687abea063ba3725ae54118f45999f5b53b38ba67b61f2365965784a81b9b47f37b78c10';
4750
const parsedTxWithNonMatchingChainId = ethers.Transaction.from(txWithNonMatchingChainId);
4851
const txWithValueMoreThanOneTinyBar =
4952
'0xf8628080809449858d4445908c12fcf70251d3f4682e8c9c381085174876e800801ba015ec73d3e329c7f5c0228be39bf30758f974d69468847dd507082c89ec453fe2a04124cc1dd6ac07417e7cdbe04cb99d698bddc6ce4d04054dd8978dec3493f3d2';
@@ -133,14 +136,31 @@ describe('Precheck', async function () {
133136
}
134137
});
135138

139+
it('should pass when chainId=0x0', async function () {
140+
try {
141+
precheck.chainId(parsedtxWithChainId0x0);
142+
} catch (e: any) {
143+
expect(e).to.not.exist;
144+
}
145+
});
146+
136147
it('should not pass for non-matching chainId', async function () {
137148
try {
138149
precheck.chainId(parsedTxWithNonMatchingChainId);
139150
expectedError();
140151
} catch (e: any) {
141152
expect(e).to.exist;
142153
expect(e.code).to.eq(-32000);
143-
expect(e.message).to.eq('ChainId (0x0) not supported. The correct chainId is 0x12a');
154+
expect(e.message).to.eq('ChainId (0x171) not supported. The correct chainId is 0x12a');
155+
}
156+
});
157+
158+
it('Should check if a transaction is an unprotected pre-EIP155 transaction', function () {
159+
try {
160+
expect(precheck.isLegacyUnprotectedEtx(parsedtxWithChainId0x0)).to.be.true;
161+
expect(precheck.isLegacyUnprotectedEtx(parsedTxWithMatchingChainId)).to.be.false;
162+
} catch (e: any) {
163+
expect(e).to.not.exist;
144164
}
145165
});
146166
});

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -828,17 +828,24 @@ describe('@api-batch-1 RPC Server Acceptance Tests', function () {
828828
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, true, relay, [signedTx, requestId]);
829829
});
830830

831-
it('should fail "eth_sendRawTransaction" for Legacy transactions (with no chainId)', async function () {
831+
it('should execute "eth_sendRawTransaction" for legacy transactions (with no chainId i.e. chainId=0x0)', async function () {
832+
const receiverInitialBalance = await relay.getBalance(mirrorContract.evm_address, 'latest', requestId);
832833
const transaction = {
833834
...defaultLegacyTransactionData,
834835
to: mirrorContract.evm_address,
835836
nonce: await relay.getAccountNonce(accounts[2].address, requestId),
836837
gasPrice: await relay.gasPrice(requestId),
837838
};
838839
const signedTx = await accounts[2].wallet.signTransaction(transaction);
839-
const error = predefined.UNSUPPORTED_CHAIN_ID('0x0', CHAIN_ID);
840+
const transactionHash = await relay.sendRawTransaction(signedTx, requestId);
841+
// Since the transactionId is not available in this context
842+
// Wait for the transaction to be processed and imported in the mirror node with axios-retry
843+
await new Promise((r) => setTimeout(r, 5000));
844+
await mirrorNode.get(`/contracts/results/${transactionHash}`, requestId);
840845

841-
await Assertions.assertPredefinedRpcError(error, sendRawTransaction, true, relay, [signedTx, requestId]);
846+
const receiverEndBalance = await relay.getBalance(mirrorContract.evm_address, 'latest', requestId);
847+
const balanceChange = receiverEndBalance - receiverInitialBalance;
848+
expect(balanceChange.toString()).to.eq(Number(ONE_TINYBAR).toString());
842849
});
843850

844851
it('should fail "eth_sendRawTransaction" for Legacy transactions (with gas price too low)', async function () {

0 commit comments

Comments
 (0)