From bcbfea3e9870a789a7507012e5e9a28ae35b377d Mon Sep 17 00:00:00 2001 From: fibonacci998 Date: Fri, 14 Jun 2024 11:16:02 +0700 Subject: [PATCH 1/2] fix: recover evm tx address sender from cosmos tx --- src/services/crawl-tx/crawl_tx.service.ts | 64 ++++++++++++++++++++++- src/services/evm/constant.ts | 2 + 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/services/crawl-tx/crawl_tx.service.ts b/src/services/crawl-tx/crawl_tx.service.ts index 5ecefebe7..dec287db5 100644 --- a/src/services/crawl-tx/crawl_tx.service.ts +++ b/src/services/crawl-tx/crawl_tx.service.ts @@ -7,11 +7,16 @@ import { import { HttpBatchClient } from '@cosmjs/tendermint-rpc'; import { createJsonRpcRequest } from '@cosmjs/tendermint-rpc/build/jsonrpc'; import { decodeTxRaw } from '@cosmjs/proto-signing'; -import { toBase64, fromBase64 } from '@cosmjs/encoding'; +import { toBase64, fromBase64, toHex } from '@cosmjs/encoding'; import { Knex } from 'knex'; import { Queue } from 'bullmq'; import { GetNodeInfoResponseSDKType } from '@aura-nw/aurajs/types/codegen/cosmos/base/tendermint/v1beta1/query'; import _ from 'lodash'; +import { + TransactionSerializable, + recoverTransactionAddress, + serializeTransaction, +} from 'viem'; import Utils from '../../common/utils/utils'; import { BULL_JOB_NAME, @@ -31,6 +36,8 @@ import config from '../../../config.json' assert { type: 'json' }; import knex from '../../common/utils/db_connection'; import ChainRegistry from '../../common/utils/chain.registry'; import { getProviderRegistry } from '../../common/utils/provider.registry'; +import { MSG_TYPE } from '../evm/constant'; +import { convertEthAddressToBech32Address } from '../evm/utils'; @Service({ name: SERVICE.V1.CrawlTransaction.key, @@ -416,7 +423,7 @@ export default class CrawlTxService extends BullableService { block_height: tx.height, source: Event.SOURCE.TX_EVENT, })) ?? []; - const msgInsert = + const msgInsert: TransactionMessage[] = rawLogTx.tx.body.messages.map((message: any, index: any) => ({ tx_id: tx.id, sender, @@ -424,6 +431,15 @@ export default class CrawlTxService extends BullableService { type: message['@type'], content: message, })) ?? []; + this.updateSenderInEVMTx( + msgInsert.filter((msg) => + [ + MSG_TYPE.MSG_ETHEREUM_TX, + MSG_TYPE.MSG_DYNAMIC_FEE_TX, + MSG_TYPE.MSG_LEGACY_TX, + ].includes(msg.type) + ) + ); listEventModel.push(...eventInsert); listMsgModel.push(...msgInsert); }); @@ -579,6 +595,50 @@ export default class CrawlTxService extends BullableService { } } + public async updateSenderInEVMTx( + listTransactionMessage: TransactionMessage[] + ) { + await Promise.all( + listTransactionMessage.map(async (txmsg: TransactionMessage) => { + const { content } = txmsg; + const evmTransaction = { + chainId: parseInt(content.data.chain_id, 10), + maxFeePerGas: BigInt(content.data.gas_fee_cap), + maxPriorityFeePerGas: BigInt(content.data.gas_tip_cap), + to: content.data.to, + value: BigInt(content.data.value), + data: `0x${toHex(fromBase64(content.data.data))}`, + nonce: parseInt(content.data.nonce, 10), + gas: BigInt(content.data.gas), + accessList: content.data.accesses.map((accessElement: any) => ({ + address: accessElement.address, + storageKeys: accessElement.storage_keys, + })), + } as const satisfies TransactionSerializable; + + const recovedAddress = await recoverTransactionAddress({ + serializedTransaction: serializeTransaction(evmTransaction), + signature: { + r: `0x${toHex(fromBase64(content.data.r))}`, + s: `0x${toHex(fromBase64(content.data.s))}`, + v: content.data.v ? BigInt(1) : BigInt(0), + }, + }); + const bech32RecovedAddress = convertEthAddressToBech32Address( + config.networkPrefixAddress, + recovedAddress + ); + if (txmsg.sender !== bech32RecovedAddress) { + this.logger.warn(`Sender not match in evm tx ${content.hash}`); + this.logger.warn(`Currently: ${txmsg.sender}`); + this.logger.warn(`Recover: ${bech32RecovedAddress}`); + // eslint-disable-next-line no-param-reassign + txmsg.sender = bech32RecovedAddress; + } + }) + ); + } + public async _start() { const providerRegistry = await getProviderRegistry(); this._registry = new ChainRegistry(this.logger, providerRegistry); diff --git a/src/services/evm/constant.ts b/src/services/evm/constant.ts index dcb7d0a18..ba8855894 100644 --- a/src/services/evm/constant.ts +++ b/src/services/evm/constant.ts @@ -225,4 +225,6 @@ export const BULL_JOB_NAME = { export const MSG_TYPE = { MSG_ETHEREUM_TX: '/ethermint.evm.v1.MsgEthereumTx', + MSG_DYNAMIC_FEE_TX: '/ethermint.evm.v1.DynamicFeeTx', + MSG_LEGACY_TX: '/ethermint.evm.v1.LegacyTx', }; From c81762a2fc27369c7cab1ab1599c13f8525e7aae Mon Sep 17 00:00:00 2001 From: fibonacci998 Date: Mon, 24 Jun 2024 10:50:20 +0700 Subject: [PATCH 2/2] feat: add unit test to check sender in evm tx --- .../crawl-transaction/evm_tx.fixture.json | 187 ++++++++++++++++++ .../parse_transaction.spec.ts | 47 ++++- 2 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 test/unit/services/crawl-transaction/evm_tx.fixture.json diff --git a/test/unit/services/crawl-transaction/evm_tx.fixture.json b/test/unit/services/crawl-transaction/evm_tx.fixture.json new file mode 100644 index 000000000..23fc58e2e --- /dev/null +++ b/test/unit/services/crawl-transaction/evm_tx.fixture.json @@ -0,0 +1,187 @@ +{ + "txs": [ + { + "hash": "CE1C281B2F98B4569616CACC82E28456E805BE571CB71EC464183935F8E76D3C", + "height": "20006980", + "index": 0, + "tx_result": { + "code": 0, + "data": "EsAECicvZXRoZXJtaW50LmV2bS52MS5Nc2dFdGhlcmV1bVR4UmVzcG9uc2USlAQKQjB4MTU4Y2ZmMTA0NGZjZDViZThlZjI3ZDczNGQxMWIzNzAyYzAyYWZlZjlhMTFiNTlmZDUzYjUxYjY0OGUyZWY5MxLJAwoqMHgwZTQyZGFGYzAzYmRiQTc0YzA1NjhkRGUyOURkYmM1RGFBNzQwYjYyEkIweDhjNWJlMWU1ZWJlYzdkNWJkMTRmNzE0MjdkMWU4NGYzZGQwMzE0YzBmN2IyMjkxZTViMjAwYWM4YzdjM2I5MjUSQjB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMzY0ZTI3ZWZhZDFjY2M4ZGJjY2M4ZTFiZTk0ZTE5OWUwZGU2N2NiMRJCMHgwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBhMWY3MzIwYzBkNDQ1MDkwMjM3NzVjZTg5ZDgwYjNkNGY0MjE3MWRjEkIweDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAzZTcgxJDFCSpCMHgxNThjZmYxMDQ0ZmNkNWJlOGVmMjdkNzM0ZDExYjM3MDJjMDJhZmVmOWExMWI1OWZkNTNiNTFiNjQ4ZTJlZjkzOkIweDlmZmRhN2JkYTY5ZTljOTQ4ZWNhYjgyYjFhZmY2NGM3MDc0YzliMzIxZjZkMjE1ZDQwMTQ2MDAyOTFjZjA3YmEoxP8C", + "log": "[{\"msg_index\":0,\"events\":[{\"type\":\"message\",\"attributes\":[{\"key\":\"action\",\"value\":\"/ethermint.evm.v1.MsgEthereumTx\"},{\"key\":\"sender\",\"value\":\"aura1xe8z0madrnxgm0xv3cd7jnsencx7vl93tj3znv\"}]},{\"type\":\"ethereum_tx\",\"attributes\":[{\"key\":\"amount\",\"value\":\"0\"},{\"key\":\"ethereumTxHash\",\"value\":\"0x158cff1044fcd5be8ef27d734d11b3702c02afef9a11b59fd53b51b648e2ef93\"},{\"key\":\"txIndex\",\"value\":\"0\"},{\"key\":\"txGasUsed\",\"value\":\"49092\"},{\"key\":\"txHash\",\"value\":\"CE1C281B2F98B4569616CACC82E28456E805BE571CB71EC464183935F8E76D3C\"},{\"key\":\"recipient\",\"value\":\"0x0e42daFc03bdbA74c0568dDe29Ddbc5DaA740b62\"}]},{\"type\":\"tx_log\",\"attributes\":[{\"key\":\"txLog\",\"value\":\"{\\\"address\\\":\\\"0x0e42daFc03bdbA74c0568dDe29Ddbc5DaA740b62\\\",\\\"topics\\\":[\\\"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\\\",\\\"0x000000000000000000000000364e27efad1ccc8dbccc8e1be94e199e0de67cb1\\\",\\\"0x000000000000000000000000a1f7320c0d44509023775ce89d80b3d4f42171dc\\\",\\\"0x00000000000000000000000000000000000000000000000000000000000003e7\\\"],\\\"blockNumber\\\":20006980,\\\"transactionHash\\\":\\\"0x158cff1044fcd5be8ef27d734d11b3702c02afef9a11b59fd53b51b648e2ef93\\\",\\\"transactionIndex\\\":0,\\\"blockHash\\\":\\\"0x9ffda7bda69e9c948ecab82b1aff64c7074c9b321f6d215d4014600291cf07ba\\\",\\\"logIndex\\\":0}\"}]},{\"type\":\"message\",\"attributes\":[{\"key\":\"module\",\"value\":\"evm\"},{\"key\":\"sender\",\"value\":\"0x364E27efAd1Ccc8dBCcc8e1bE94E199E0De67Cb1\"},{\"key\":\"txType\",\"value\":\"2\"}]}]}]", + "info": "", + "gas_wanted": "58910", + "gas_used": "49092", + "events": [ + { + "type": "coin_spent", + "attributes": [ + { + "key": "spender", + "value": "aura1w9vxuke5dz6hyza2j932qgmxltnfxwl7qlx4mg", + "index": true + }, + { + "key": "amount", + "value": "1uaura", + "index": true + } + ] + }, + { + "type": "coin_received", + "attributes": [ + { + "key": "receiver", + "value": "aura17xpfvakm2amg962yls6f84z3kell8c5lt05zfy", + "index": true + }, + { + "key": "amount", + "value": "1uaura", + "index": true + } + ] + }, + { + "type": "transfer", + "attributes": [ + { + "key": "recipient", + "value": "aura17xpfvakm2amg962yls6f84z3kell8c5lt05zfy", + "index": true + }, + { + "key": "sender", + "value": "aura1w9vxuke5dz6hyza2j932qgmxltnfxwl7qlx4mg", + "index": true + }, + { + "key": "amount", + "value": "1uaura", + "index": true + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "sender", + "value": "aura1w9vxuke5dz6hyza2j932qgmxltnfxwl7qlx4mg", + "index": true + } + ] + }, + { + "type": "tx", + "attributes": [ + { + "key": "fee", + "value": "589100000000aaura", + "index": true + } + ] + }, + { + "type": "ethereum_tx", + "attributes": [ + { + "key": "ethereumTxHash", + "value": "0x158cff1044fcd5be8ef27d734d11b3702c02afef9a11b59fd53b51b648e2ef93", + "index": true + }, + { + "key": "txIndex", + "value": "0", + "index": true + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "action", + "value": "/ethermint.evm.v1.MsgEthereumTx", + "index": true + }, + { + "key": "sender", + "value": "aura1xe8z0madrnxgm0xv3cd7jnsencx7vl93tj3znv", + "index": true + } + ] + }, + { + "type": "ethereum_tx", + "attributes": [ + { + "key": "amount", + "value": "0", + "index": true + }, + { + "key": "ethereumTxHash", + "value": "0x158cff1044fcd5be8ef27d734d11b3702c02afef9a11b59fd53b51b648e2ef93", + "index": true + }, + { + "key": "txIndex", + "value": "0", + "index": true + }, + { + "key": "txGasUsed", + "value": "49092", + "index": true + }, + { + "key": "txHash", + "value": "CE1C281B2F98B4569616CACC82E28456E805BE571CB71EC464183935F8E76D3C", + "index": true + }, + { + "key": "recipient", + "value": "0x0e42daFc03bdbA74c0568dDe29Ddbc5DaA740b62", + "index": true + } + ] + }, + { + "type": "tx_log", + "attributes": [ + { + "key": "txLog", + "value": "{\"address\":\"0x0e42daFc03bdbA74c0568dDe29Ddbc5DaA740b62\",\"topics\":[\"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\"0x000000000000000000000000364e27efad1ccc8dbccc8e1be94e199e0de67cb1\",\"0x000000000000000000000000a1f7320c0d44509023775ce89d80b3d4f42171dc\",\"0x00000000000000000000000000000000000000000000000000000000000003e7\"],\"blockNumber\":20006980,\"transactionHash\":\"0x158cff1044fcd5be8ef27d734d11b3702c02afef9a11b59fd53b51b648e2ef93\",\"transactionIndex\":0,\"blockHash\":\"0x9ffda7bda69e9c948ecab82b1aff64c7074c9b321f6d215d4014600291cf07ba\",\"logIndex\":0}", + "index": true + } + ] + }, + { + "type": "message", + "attributes": [ + { + "key": "module", + "value": "evm", + "index": true + }, + { + "key": "sender", + "value": "0x364E27efAd1Ccc8dBCcc8e1bE94E199E0De67Cb1", + "index": true + }, + { + "key": "txType", + "value": "2", + "index": true + } + ] + } + ], + "codespace": "" + }, + "tx": "Cp8DCusCCh8vZXRoZXJtaW50LmV2bS52MS5Nc2dFdGhlcmV1bVR4EscCCoACCh4vZXRoZXJtaW50LmV2bS52MS5EeW5hbWljRmVlVHgS3QEKBDEyMzYQgQQaCDEwMDAwMDAwIggxMDAwMDAwMCiezAMyKjB4MGU0MmRhRmMwM2JkYkE3NGMwNTY4ZERlMjlEZGJjNURhQTc0MGI2MjoBMEJECV6nswAAAAAAAAAAAAAAAKH3MgwNRFCQI3dc6J2As9T0IXHcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+dSAQFaIMeKwwGr4Si1AusIPTaSXMF0N/PFYRB4gNxkFi22WDEQYiAjm9eTINjssHbvhHkpBD2fP/rJs54wgg72vSPBGBzR7xpCMHgxNThjZmYxMDQ0ZmNkNWJlOGVmMjdkNzM0ZDExYjM3MDJjMDJhZmVmOWExMWI1OWZkNTNiNTFiNjQ4ZTJlZjkz+j8uCiwvZXRoZXJtaW50LmV2bS52MS5FeHRlbnNpb25PcHRpb25zRXRoZXJldW1UeBIdEhsKFQoFYWF1cmESDDU4OTEwMDAwMDAwMBCezAM=" + } + ], + "total_count": "1" +} diff --git a/test/unit/services/crawl-transaction/parse_transaction.spec.ts b/test/unit/services/crawl-transaction/parse_transaction.spec.ts index 5ae4a7c5c..5a2a1cd31 100644 --- a/test/unit/services/crawl-transaction/parse_transaction.spec.ts +++ b/test/unit/services/crawl-transaction/parse_transaction.spec.ts @@ -13,6 +13,7 @@ import CrawlTxService from '../../../../src/services/crawl-tx/crawl_tx.service'; import knex from '../../../../src/common/utils/db_connection'; import tx_fixture from './tx.fixture.json' assert { type: 'json' }; import tx_fixture_authz from './tx_authz.fixture.json' assert { type: 'json' }; +import tx_fixture_evm from './evm_tx.fixture.json' assert { type: 'json' }; import ChainRegistry from '../../../../src/common/utils/chain.registry'; import { getProviderRegistry } from '../../../../src/common/utils/provider.registry'; @@ -168,8 +169,50 @@ export default class CrawlTransactionTest { }); }); } - // } - // ); + } + + @Test('Parse transaction evm and insert to DB') + public async testHandleTransactionEvm() { + await Block.query().insert( + Block.fromJson({ + height: 2006980, + hash: 'data hash evm', + time: '2023-04-17T03:44:41.000Z', + proposer_address: 'proposer address', + data: {}, + }) + ); + const listdecodedTx = await this.crawlTxService?.decodeListRawTx([ + { + listTx: { ...tx_fixture_evm }, + height: 2006980, + timestamp: '2023-04-17T03:44:41.000Z', + }, + ]); + if (listdecodedTx) + await knex.transaction(async (trx) => { + await this.crawlTxService?.insertTxDecoded(listdecodedTx, trx); + const listTxRaw = await Transaction.query() + .where('height', '>', 2006979) + .andWhere('height', '<=', 2006980) + .orderBy('height', 'asc') + .orderBy('index', 'asc') + .transacting(trx); + await this.crawlTxService?.insertRelatedTx(listTxRaw, trx); + }); + const tx = await Transaction.query() + .findOne( + 'hash', + 'CE1C281B2F98B4569616CACC82E28456E805BE571CB71EC464183935F8E76D3C' + ) + .withGraphFetched('messages'); + expect(tx).not.toBeUndefined(); + if (tx) { + // check evm tx use signing user as sender, not from event_attribute + expect(tx.messages[0].sender).toEqual( + 'aura1xe8z0madrnxgm0xv3cd7jnsencx7vl93tj3znv' + ); + } } arrDest = {