Skip to content

Commit 044d533

Browse files
authored
Merge pull request #64 from rsksmart/stop-using-web3
Replace web3js for ethersjs
2 parents a8030eb + a966e41 commit 044d533

15 files changed

+2839
-7107
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ A tool to find interactions with the Bridge on Rootstock
2121
- `txHash`: A transaction hash.
2222
- `starting block hash or number`: block hash or number from where to start searching interaction with the Bridge contract
2323
- `blocks to search`: amount of blocks to search, from the starting block forward. Max 100 blocks.
24-
- bridgeTx: A bridgeTx: web3TransactionObject. E.g.: {\"hash\":\"0xc2dee2f542cee022196948b1da5d8d44331e3f8de964ee6fb025e06bb077c880\",\"nonce\":241,\"blockHash\":\"0x3cd357a760e69e3942d344062f751eff7be4d07d4a01f095ebfd42c8c0d2498e\",\"blockNumber\":2867321,\"transactionIndex\":3,\"from\":\"0x92C94AE16eEfC9202bb8BCAf1F6B0c8702fb56eE\",\"to\":\"0x0000000000000000000000000000000001000006\",\"gas\":67152,\"gasPrice\":\"65164000\",\"value\":\"0\",\"input\":\"0x43dc06560000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000022280e00000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000131010000000001014e80d52d5ed9dfe3523c47e7cb095b9cffe6677f22090fd9e0bbf32813c18be00200000017160014c4cb069eec8a8b695a8c50515eaec10b4e65bb5bffffffff030000000000000000306a2e52534b54013a29282d5144cea68cb33995ce82212f4b21ccec012b6f4aecd3bad677f9056c20958b1c1ff56d25c3405489000000000017a9148f38b3d8ec8816f7f58a390f306bb90bb178d6ac87ee3a07000000000017a914f38b645178d325b086b1849bb79147518b8931698702483045022100be99ce8ce2de3147ba64e81ec5fe4bc0dea12dccf258cd4dca65c0c09108da8f022024b5c36e2184a4d2a67b5212b52e6955e4e7a9fbff896825bef7e028d34ef4c70121028d2a1b7ef1feffdfd1aa57d543bf0799107ec44469f9e3d332ffe25fec2b8e590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000470200000002000000000000000000000000000000000000000000000000000000000000000076113d8b6fc306e168ac534d80874e3ee1b9f418b8c1985ead59399d638b1ea3010500000000000000000000000000000000000000000000000000\",\"v\":\"0x62\",\"r\":\"0x802a61cfaa81791b8e5a5101887932f4e9cd0f64d3bb0d7d61ae77d190f289a2\",\"s\":\"0x5e1f5b3d2ae30474665e2485f472c81979f6b6db8c9dc2c92408b4f96d7d2baf\"}
25-
- bridgeTxReceipt: A bridgeTxReceipt: web3TransactionObject. E.g.: {\"transactionHash\":\"0xc2dee2f542cee022196948b1da5d8d44331e3f8de964ee6fb025e06bb077c880\",\"transactionIndex\":3,\"blockHash\":\"0x3cd357a760e69e3942d344062f751eff7be4d07d4a01f095ebfd42c8c0d2498e\",\"blockNumber\":2867321,\"cumulativeGasUsed\":507369,\"gasUsed\":67152,\"contractAddress\":null,\"logs\":[],\"from\":\"0x92c94ae16eefc9202bb8bcaf1f6b0c8702fb56ee\",\"to\":\"0x0000000000000000000000000000000001000006\",\"status\":true,\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"}
24+
- bridgeTx: A bridgeTx: ethersjs TransactionRequest. E.g.: {\"accessList\":null,\"blockNumber\":6142522,\"blockHash\":\"0xde1747c904c98b7af485df23cce4f408ae1059ed725c94dfa0b83098acc0b748\",\"blobVersionedHashes\":null,\"chainId\":\"31\",\"data\":\"0x0c5a9990\",\"from\":\"0x4ae78A7E6016CDb9F8EaafcE7664892af88E50Fb\",\"gasLimit\":\"69072\",\"gasPrice\":\"5830269\",\"hash\":\"0x967a0cdae80dac64f87ba0ab3f2f75e220fe883209bdbe33b920291d281784fc\",\"maxFeePerGas\":null,\"maxPriorityFeePerGas\":null,\"maxFeePerBlobGas\":null,\"nonce\":1904,\"signature\":{\"_type\":\"signature\",\"networkV\":\"98\",\"r\":\"0xf769ef5d6f8577ce5371a145712bb209fa85231e72bd9dbaaf312eb14c44fd1a\",\"s\":\"0x2bb2d57c11baacfa30eb470394516b59b6aa512ff81e36cdd5132cf1965c0c47\",\"v\":28},\"to\":\"0x0000000000000000000000000000000001000006\",\"index\":1,\"type\":0,\"value\":\"0\"}
25+
- bridgeTxReceipt: A bridgeTxReceipt: ethersjs TransactionReceipt. E.g.: {\"blockHash\":\"0xde1747c904c98b7af485df23cce4f408ae1059ed725c94dfa0b83098acc0b748\",\"blockNumber\":6142522,\"contractAddress\":null,\"cumulativeGasUsed\":\"133408\",\"from\":\"0x4ae78A7E6016CDb9F8EaafcE7664892af88E50Fb\",\"gasPrice\":\"5830269\",\"blobGasUsed\":null,\"blobGasPrice\":null,\"gasUsed\":\"69072\",\"hash\":\"0x967a0cdae80dac64f87ba0ab3f2f75e220fe883209bdbe33b920291d281784fc\",\"index\":1,\"logs\":[{\"address\":\"0x0000000000000000000000000000000001000006\",\"blockHash\":\"0xde1747c904c98b7af485df23cce4f408ae1059ed725c94dfa0b83098acc0b748\",\"blockNumber\":6142522,\"data\":\"0x0000000000000000000000004ae78a7e6016cdb9f8eaafce7664892af88e50fb\",\"index\":0,\"topics\":[\"0x1069152f4f916cbf155ee32a695d92258481944edb5b6fd649718fc1b43e515e\"],\"transactionHash\":\"0x967a0cdae80dac64f87ba0ab3f2f75e220fe883209bdbe33b920291d281784fc\",\"transactionIndex\":1}],\"logsBloom\":\"0x00000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000\",\"status\":1,\"to\":\"0x0000000000000000000000000000000001000006\"}
2626

2727
## Live monitoring tool
2828

@@ -159,9 +159,9 @@ If `toBlock` param is provided and the monitor reaches that block number, then t
159159
```js
160160

161161
const LiveMonitor = require('./tool/live-monitor');
162-
const Web3 = require('web3');
162+
const ethers = require('ethers');
163163

164-
const rskClient = new Web3('https://public-node.testnet.rsk.co/');
164+
const rskClient = new ethers.JsonRpcProvider('https://public-node.testnet.rsk.co/');
165165

166166
const params = {
167167
fromBlock: 'latest',

index.d.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import Web3 from "web3";
2-
import { TransactionReceipt, Transaction as Web3Transaction } from "web3-core";
1+
import {JsonRpcProvider, TransactionReceipt, TransactionRequest} from "ethers";
32

43
interface Transaction {
54
txHash: string,
@@ -25,7 +24,7 @@ interface BridgeEvent {
2524
export interface Log {
2625
data: string;
2726
topics: string[];
28-
};
27+
}
2928

3029
export interface AbiElement {
3130
type: string;
@@ -39,9 +38,9 @@ export default class BridgeTransactionParser {
3938

4039
/**
4140
*
42-
* @param web3Client Web3 Instance
41+
* @param rskClient JsonRpcProvider
4342
*/
44-
constructor(web3Client: Web3);
43+
constructor(rskClient: JsonRpcProvider);
4544

4645
/**
4746
* Gets Bridge Transactions In a Specified Block Hash Or Block Number
@@ -66,12 +65,12 @@ export default class BridgeTransactionParser {
6665
getBridgeTransactionByTxHash(transactionHash: string): Promise<Transaction>;
6766

6867
/**
69-
* Gets a Bridge Transaction given a web3 transaction: web3TransactionObject and a bridgeTxReceipt: TransactionReceipt.
70-
* @param web3Tx The web3TransactionObject.
71-
* @param bridgeTxReceipt The bridgeTxReceipt: web3TransactionReceiptObject.
68+
* Gets a Bridge Transaction given a transaction request: TransactionRequest and a bridgeTxReceipt: TransactionReceipt.
69+
* @param transactionRequest The transactionRequest.
70+
* @param bridgeTxReceipt The bridgeTxReceipt: TransactionReceipt.
7271
* @returns Object - A transaction object
7372
*/
74-
decodeBridgeTransaction(web3Tx: Web3Transaction, bridgeTxReceipt: TransactionReceipt): Promise<Transaction>;
73+
decodeBridgeTransaction(transactionRequest: TransactionRequest, bridgeTxReceipt: TransactionReceipt): Promise<Transaction>;
7574

7675
/**
7776
* Decodes logs from a transaction receipt

index.js

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,44 @@ const BridgeTx = require("./BridgeTx");
33
const BridgeMethod = require("./BridgeMethod");
44
const BridgeEvent = require("./BridgeEvent");
55
const utils = require("./utils");
6+
const {ethers} = require('ethers');
7+
const {formatBigIntForJson} = require("./utils");
68

79
class BridgeTransactionParser {
810

9-
constructor(web3Client) {
10-
if (!web3Client) {
11-
throw new Error(`web3Client is required`);
11+
constructor(rskClient) {
12+
if (!rskClient) {
13+
throw new Error(`rskClient is required`);
1214
}
13-
this.web3Client = web3Client;
14-
this.bridge = new web3Client.eth.Contract(Bridge.abi, Bridge.address);
15-
this.jsonInterfaceMap = this.bridge._jsonInterface.reduce((map, item) => {
16-
map[item.signature] = item;
17-
return map;
18-
}, {});
15+
this.rskClient = rskClient;
16+
this.bridge = new ethers.Contract(Bridge.address, Bridge.abi, rskClient);
1917
}
2018

2119
getBridgeTransactionByTxHash = async (transactionHash) => {
2220
utils.verifyHashOrBlockNumber(transactionHash);
23-
21+
2422
let transaction;
25-
const txReceipt = await this.web3Client.eth.getTransactionReceipt(transactionHash);
23+
const txReceipt = await this.rskClient.getTransactionReceipt(
24+
transactionHash);
2625
if (txReceipt?.to === Bridge.address) {
27-
const tx = await this.web3Client.eth.getTransaction(txReceipt.transactionHash);
26+
const tx = await this.rskClient.getTransaction(
27+
txReceipt.hash);
2828
transaction = await this.createBridgeTx(tx, txReceipt);
2929
}
30-
30+
3131
return transaction;
3232
}
3333

3434
getBridgeTransactionsInThisBlock = async (blockHashOrBlockNumber) => {
3535
utils.verifyHashOrBlockNumber(blockHashOrBlockNumber);
36-
37-
const block = await this.web3Client.eth.getBlock(blockHashOrBlockNumber);
36+
37+
// block in number should be parsed as a Number in order to call the getBlock method
38+
const blockTag = this.#parseBlockTag(blockHashOrBlockNumber);
39+
const block = await this.rskClient.getBlock(blockTag);
3840
if (!block) {
3941
throw new Error(`Block ${blockHashOrBlockNumber} not found`);
4042
}
41-
43+
4244
const bridgeTxs = [];
4345
for (let txHash of block.transactions) {
4446
const transaction = await this.getBridgeTransactionByTxHash(txHash);
@@ -48,83 +50,107 @@ class BridgeTransactionParser {
4850
}
4951
return bridgeTxs;
5052
}
51-
52-
getBridgeTransactionsSinceThisBlock = async (startingBlockHashOrBlockNumber, blocksToSearch) => {
53+
54+
#parseBlockTag = (blockHashOrBlockNumber) => {
55+
return typeof blockHashOrBlockNumber === 'string' && blockHashOrBlockNumber.indexOf('0x') === 0 ?
56+
blockHashOrBlockNumber : Number(blockHashOrBlockNumber);
57+
}
58+
59+
getBridgeTransactionsSinceThisBlock = async (startingBlockHashOrBlockNumber,
60+
blocksToSearch) => {
5361
utils.verifyHashOrBlockNumber(startingBlockHashOrBlockNumber);
54-
55-
if (isNaN(blocksToSearch) || blocksToSearch > 100 || blocksToSearch <= 0) {
56-
throw new Error('blocksToSearch must be greater than 0 or less than 100');
62+
63+
if (isNaN(blocksToSearch) || blocksToSearch > 100 || blocksToSearch
64+
<= 0) {
65+
throw new Error(
66+
'blocksToSearch must be greater than 0 or less than 100');
5767
}
58-
59-
const startingBlockNumber = typeof startingBlockHashOrBlockNumber === 'string' && startingBlockHashOrBlockNumber.indexOf('0x') === 0 ?
60-
(await this.web3Client.eth.getBlock(startingBlockHashOrBlockNumber)).number : startingBlockHashOrBlockNumber;
68+
69+
const startingBlockTag = this.#parseBlockTag(startingBlockHashOrBlockNumber);
70+
const startingBlock = await this.rskClient.getBlock(
71+
startingBlockTag);
72+
const startingBlockNumber = startingBlock.number;
6173

6274
const bridgeTxs = [];
6375
for (let i = 0; i < blocksToSearch; i++) {
6476
const blockNumber = parseInt(startingBlockNumber) + i;
65-
const blockBridgeTxs = await this.getBridgeTransactionsInThisBlock(blockNumber);
77+
const blockBridgeTxs = await this.getBridgeTransactionsInThisBlock(
78+
blockNumber);
6679
if (blockBridgeTxs.length) {
6780
bridgeTxs.push(...blockBridgeTxs);
6881
}
6982
}
7083
return bridgeTxs;
71-
7284
}
73-
85+
7486
decodeBridgeTransaction = async (bridgeTx, bridgeTxReceipt) => {
75-
if (bridgeTx.hash !== bridgeTxReceipt.transactionHash) {
76-
throw new Error(`Given bridgeTx(${bridgeTx.hash}) and bridgeTxReceipt(${bridgeTxReceipt.transactionHash}) should belong to the same transaction.`);
87+
if (bridgeTx.hash !== bridgeTxReceipt.hash) {
88+
throw new Error(
89+
`Given bridgeTx(${bridgeTx.hash}) and bridgeTxReceipt(${bridgeTxReceipt.hash}) should belong to the same transaction.`);
7790
}
7891
if (bridgeTxReceipt.to !== Bridge.address) {
79-
throw new Error(`Given bridgeTxReceipt is not a bridge transaction`);
92+
throw new Error(
93+
`Given bridgeTxReceipt is not a bridge transaction`);
8094
}
81-
95+
8296
return this.createBridgeTx(bridgeTx, bridgeTxReceipt);
8397
}
84-
98+
8599
decodeBridgeMethodParameters = (methodName, data) => {
86100
const abi = Bridge.abi.find(m => m.name === methodName);
87101
if (!abi) {
88102
throw new Error(`${methodName} does not exist in Bridge abi`);
89103
}
90-
91-
const argumentsData = data.substring(10); // Remove the signature bits from the data
92-
const dataDecoded = this.web3Client.eth.abi.decodeParameters(abi.inputs, argumentsData);
93-
104+
105+
const functionFragment = this.bridge.interface.getFunction(methodName);
106+
const dataDecoded = this.bridge.interface.decodeFunctionData(functionFragment,
107+
data);
108+
94109
// TODO: the parsing of the arguments is not tested
95110
const args = {};
96111
for (let input of abi.inputs) {
97112
args[input.name] = dataDecoded[input.name];
98113
}
99114
return args;
100115
}
101-
116+
102117
createBridgeTx = async (tx, txReceipt) => {
103-
const txData = tx.input;
104-
const method = this.jsonInterfaceMap[txData.substring(0, 10)];
118+
const txData = tx.data;
119+
const functionSignature = txData.substring(0, 10);
120+
const method = this.bridge.interface.getFunction(functionSignature);
105121
const events = this.decodeLogs(txReceipt);
106-
const block = await this.web3Client.eth.getBlock(txReceipt.blockNumber);
107-
122+
const block = await this.rskClient.getBlock(txReceipt.blockNumber);
123+
108124
let bridgeMethod = '';
109125
if (method) {
110-
const args = await this.decodeBridgeMethodParameters(method.name, txData);
111-
bridgeMethod = new BridgeMethod(method.name, method.signature, args);
126+
const args = await this.decodeBridgeMethodParameters(method.name,
127+
txData);
128+
bridgeMethod = new BridgeMethod(method.name, functionSignature,
129+
args);
112130
}
113-
return new BridgeTx(
114-
txReceipt.transactionHash,
115-
bridgeMethod,
116-
events,
117-
txReceipt.from,
131+
let bridgeTx = new BridgeTx(
132+
txReceipt.hash,
133+
bridgeMethod,
134+
events,
135+
txReceipt.from,
118136
txReceipt.blockNumber,
119137
block.timestamp
120138
);
139+
140+
// Format any BigInt values in the bridgeTx
141+
return formatBigIntForJson(bridgeTx);
121142
};
122-
143+
123144
decodeLogs = (txReceipt) => {
124145
const events = [];
125146
for (let log of txReceipt.logs) {
126-
const abiElement = this.jsonInterfaceMap[log.topics[0]];
127-
if(!abiElement) {
147+
if (log.topics.length === 0) {
148+
continue;
149+
}
150+
151+
const eventSignature = log.topics[0];
152+
const abiElement = this.bridge.interface.getEvent(eventSignature)
153+
if (!abiElement) {
128154
continue;
129155
}
130156
const event = this.decodeLog(log, abiElement);
@@ -134,22 +160,16 @@ class BridgeTransactionParser {
134160
}
135161

136162
decodeLog = (log, abiElement) => {
163+
const parsedLog = this.bridge.interface.parseLog(log);
164+
137165
const args = {};
138-
const dataDecoded = this.web3Client.eth.abi.decodeParameters(abiElement.inputs.filter(i => !i.indexed), log.data);
139-
let topicIndex = 1;
140-
for (let input of abiElement.inputs) {
141-
let value;
142-
if (input.indexed) {
143-
value = this.web3Client.eth.abi.decodeParameter(input.type, log.topics[topicIndex]);
144-
topicIndex++;
145-
} else {
146-
value = dataDecoded[input.name];
147-
}
148-
args[input.name] = value;
166+
for (let i = 0; i < abiElement.inputs.length; i++) {
167+
const input = abiElement.inputs[i];
168+
args[input.name] = parsedLog.args[i];
149169
}
150-
return new BridgeEvent(abiElement.name, abiElement.signature, args);
151-
}
152170

171+
return new BridgeEvent(abiElement.name, log.topics[0], args);
172+
}
153173
}
154174

155175
module.exports = BridgeTransactionParser;

0 commit comments

Comments
 (0)