@@ -3,42 +3,44 @@ const BridgeTx = require("./BridgeTx");
3
3
const BridgeMethod = require ( "./BridgeMethod" ) ;
4
4
const BridgeEvent = require ( "./BridgeEvent" ) ;
5
5
const utils = require ( "./utils" ) ;
6
+ const { ethers} = require ( 'ethers' ) ;
7
+ const { formatBigIntForJson} = require ( "./utils" ) ;
6
8
7
9
class BridgeTransactionParser {
8
10
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` ) ;
12
14
}
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 ) ;
19
17
}
20
18
21
19
getBridgeTransactionByTxHash = async ( transactionHash ) => {
22
20
utils . verifyHashOrBlockNumber ( transactionHash ) ;
23
-
21
+
24
22
let transaction ;
25
- const txReceipt = await this . web3Client . eth . getTransactionReceipt ( transactionHash ) ;
23
+ const txReceipt = await this . rskClient . getTransactionReceipt (
24
+ transactionHash ) ;
26
25
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 ) ;
28
28
transaction = await this . createBridgeTx ( tx , txReceipt ) ;
29
29
}
30
-
30
+
31
31
return transaction ;
32
32
}
33
33
34
34
getBridgeTransactionsInThisBlock = async ( blockHashOrBlockNumber ) => {
35
35
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 ) ;
38
40
if ( ! block ) {
39
41
throw new Error ( `Block ${ blockHashOrBlockNumber } not found` ) ;
40
42
}
41
-
43
+
42
44
const bridgeTxs = [ ] ;
43
45
for ( let txHash of block . transactions ) {
44
46
const transaction = await this . getBridgeTransactionByTxHash ( txHash ) ;
@@ -48,83 +50,107 @@ class BridgeTransactionParser {
48
50
}
49
51
return bridgeTxs ;
50
52
}
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 ) => {
53
61
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' ) ;
57
67
}
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 ;
61
73
62
74
const bridgeTxs = [ ] ;
63
75
for ( let i = 0 ; i < blocksToSearch ; i ++ ) {
64
76
const blockNumber = parseInt ( startingBlockNumber ) + i ;
65
- const blockBridgeTxs = await this . getBridgeTransactionsInThisBlock ( blockNumber ) ;
77
+ const blockBridgeTxs = await this . getBridgeTransactionsInThisBlock (
78
+ blockNumber ) ;
66
79
if ( blockBridgeTxs . length ) {
67
80
bridgeTxs . push ( ...blockBridgeTxs ) ;
68
81
}
69
82
}
70
83
return bridgeTxs ;
71
-
72
84
}
73
-
85
+
74
86
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.` ) ;
77
90
}
78
91
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` ) ;
80
94
}
81
-
95
+
82
96
return this . createBridgeTx ( bridgeTx , bridgeTxReceipt ) ;
83
97
}
84
-
98
+
85
99
decodeBridgeMethodParameters = ( methodName , data ) => {
86
100
const abi = Bridge . abi . find ( m => m . name === methodName ) ;
87
101
if ( ! abi ) {
88
102
throw new Error ( `${ methodName } does not exist in Bridge abi` ) ;
89
103
}
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
+
94
109
// TODO: the parsing of the arguments is not tested
95
110
const args = { } ;
96
111
for ( let input of abi . inputs ) {
97
112
args [ input . name ] = dataDecoded [ input . name ] ;
98
113
}
99
114
return args ;
100
115
}
101
-
116
+
102
117
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 ) ;
105
121
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
+
108
124
let bridgeMethod = '' ;
109
125
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 ) ;
112
130
}
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 ,
118
136
txReceipt . blockNumber ,
119
137
block . timestamp
120
138
) ;
139
+
140
+ // Format any BigInt values in the bridgeTx
141
+ return formatBigIntForJson ( bridgeTx ) ;
121
142
} ;
122
-
143
+
123
144
decodeLogs = ( txReceipt ) => {
124
145
const events = [ ] ;
125
146
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 ) {
128
154
continue ;
129
155
}
130
156
const event = this . decodeLog ( log , abiElement ) ;
@@ -134,22 +160,16 @@ class BridgeTransactionParser {
134
160
}
135
161
136
162
decodeLog = ( log , abiElement ) => {
163
+ const parsedLog = this . bridge . interface . parseLog ( log ) ;
164
+
137
165
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 ] ;
149
169
}
150
- return new BridgeEvent ( abiElement . name , abiElement . signature , args ) ;
151
- }
152
170
171
+ return new BridgeEvent ( abiElement . name , log . topics [ 0 ] , args ) ;
172
+ }
153
173
}
154
174
155
175
module . exports = BridgeTransactionParser ;
0 commit comments