You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

928 lines
36 KiB

4 years ago
  1. package eth
  2. import (
  3. "context"
  4. "fmt"
  5. "math/big"
  6. "strconv"
  7. "strings"
  8. "github.com/ethereum/go-ethereum"
  9. "github.com/ethereum/go-ethereum/accounts/abi"
  10. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  11. ethCommon "github.com/ethereum/go-ethereum/common"
  12. "github.com/ethereum/go-ethereum/core/types"
  13. "github.com/ethereum/go-ethereum/crypto"
  14. "github.com/ethereum/go-ethereum/ethclient"
  15. "github.com/hermeznetwork/hermez-node/common"
  16. Hermez "github.com/hermeznetwork/hermez-node/eth/contracts/hermez"
  17. HEZ "github.com/hermeznetwork/hermez-node/eth/contracts/tokenHEZ"
  18. "github.com/hermeznetwork/hermez-node/log"
  19. "github.com/hermeznetwork/tracerr"
  20. "github.com/iden3/go-iden3-crypto/babyjub"
  21. )
  22. // QueueStruct is the queue of L1Txs for a batch
  23. type QueueStruct struct {
  24. L1TxQueue []common.L1Tx
  25. TotalL1TxFee *big.Int
  26. }
  27. // NewQueueStruct creates a new clear QueueStruct.
  28. func NewQueueStruct() *QueueStruct {
  29. return &QueueStruct{
  30. L1TxQueue: make([]common.L1Tx, 0),
  31. TotalL1TxFee: big.NewInt(0),
  32. }
  33. }
  34. // RollupState represents the state of the Rollup in the Smart Contract
  35. type RollupState struct {
  36. StateRoot *big.Int
  37. ExitRoots []*big.Int
  38. // ExitNullifierMap map[[256 / 8]byte]bool
  39. ExitNullifierMap map[int64]map[int64]bool // batchNum -> idx -> bool
  40. TokenList []ethCommon.Address
  41. TokenMap map[ethCommon.Address]bool
  42. MapL1TxQueue map[int64]*QueueStruct
  43. LastL1L2Batch int64
  44. CurrentToForgeL1TxsNum int64
  45. LastToForgeL1TxsNum int64
  46. CurrentIdx int64
  47. }
  48. // RollupEventL1UserTx is an event of the Rollup Smart Contract
  49. type RollupEventL1UserTx struct {
  50. // ToForgeL1TxsNum int64 // QueueIndex *big.Int
  51. // Position int // TransactionIndex *big.Int
  52. L1UserTx common.L1Tx
  53. }
  54. // RollupEventL1UserTxAux is an event of the Rollup Smart Contract
  55. type rollupEventL1UserTxAux struct {
  56. ToForgeL1TxsNum uint64 // QueueIndex *big.Int
  57. Position uint8 // TransactionIndex *big.Int
  58. L1UserTx []byte
  59. }
  60. // RollupEventAddToken is an event of the Rollup Smart Contract
  61. type RollupEventAddToken struct {
  62. TokenAddress ethCommon.Address
  63. TokenID uint32
  64. }
  65. // RollupEventForgeBatch is an event of the Rollup Smart Contract
  66. type RollupEventForgeBatch struct {
  67. BatchNum int64
  68. // Sender ethCommon.Address
  69. EthTxHash ethCommon.Hash
  70. L1UserTxsLen uint16
  71. }
  72. // RollupEventUpdateForgeL1L2BatchTimeout is an event of the Rollup Smart Contract
  73. type RollupEventUpdateForgeL1L2BatchTimeout struct {
  74. NewForgeL1L2BatchTimeout int64
  75. }
  76. // RollupEventUpdateFeeAddToken is an event of the Rollup Smart Contract
  77. type RollupEventUpdateFeeAddToken struct {
  78. NewFeeAddToken *big.Int
  79. }
  80. // RollupEventWithdraw is an event of the Rollup Smart Contract
  81. type RollupEventWithdraw struct {
  82. Idx uint64
  83. NumExitRoot uint64
  84. InstantWithdraw bool
  85. TxHash ethCommon.Hash // Hash of the transaction that generated this event
  86. }
  87. type rollupEventUpdateBucketWithdrawAux struct {
  88. NumBucket uint8
  89. BlockStamp *big.Int
  90. Withdrawals *big.Int
  91. }
  92. // RollupEventUpdateBucketWithdraw is an event of the Rollup Smart Contract
  93. type RollupEventUpdateBucketWithdraw struct {
  94. NumBucket int
  95. BlockStamp int64 // blockNum
  96. Withdrawals *big.Int
  97. }
  98. // RollupEventUpdateWithdrawalDelay is an event of the Rollup Smart Contract
  99. type RollupEventUpdateWithdrawalDelay struct {
  100. NewWithdrawalDelay uint64
  101. }
  102. // RollupUpdateBucketsParameters are the bucket parameters used in an update
  103. type RollupUpdateBucketsParameters struct {
  104. CeilUSD *big.Int
  105. Withdrawals *big.Int
  106. BlockWithdrawalRate *big.Int
  107. MaxWithdrawals *big.Int
  108. }
  109. type rollupEventUpdateBucketsParametersAux struct {
  110. ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
  111. }
  112. // RollupEventUpdateBucketsParameters is an event of the Rollup Smart Contract
  113. type RollupEventUpdateBucketsParameters struct {
  114. // ArrayBuckets [common.RollupConstNumBuckets][4]*big.Int
  115. ArrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters
  116. SafeMode bool
  117. }
  118. // RollupEventUpdateTokenExchange is an event of the Rollup Smart Contract
  119. type RollupEventUpdateTokenExchange struct {
  120. AddressArray []ethCommon.Address
  121. ValueArray []uint64
  122. }
  123. // RollupEventSafeMode is an event of the Rollup Smart Contract
  124. type RollupEventSafeMode struct {
  125. }
  126. // RollupEvents is the list of events in a block of the Rollup Smart Contract
  127. type RollupEvents struct {
  128. L1UserTx []RollupEventL1UserTx
  129. AddToken []RollupEventAddToken
  130. ForgeBatch []RollupEventForgeBatch
  131. UpdateForgeL1L2BatchTimeout []RollupEventUpdateForgeL1L2BatchTimeout
  132. UpdateFeeAddToken []RollupEventUpdateFeeAddToken
  133. Withdraw []RollupEventWithdraw
  134. UpdateWithdrawalDelay []RollupEventUpdateWithdrawalDelay
  135. UpdateBucketWithdraw []RollupEventUpdateBucketWithdraw
  136. UpdateBucketsParameters []RollupEventUpdateBucketsParameters
  137. UpdateTokenExchange []RollupEventUpdateTokenExchange
  138. SafeMode []RollupEventSafeMode
  139. }
  140. // NewRollupEvents creates an empty RollupEvents with the slices initialized.
  141. func NewRollupEvents() RollupEvents {
  142. return RollupEvents{
  143. L1UserTx: make([]RollupEventL1UserTx, 0),
  144. AddToken: make([]RollupEventAddToken, 0),
  145. ForgeBatch: make([]RollupEventForgeBatch, 0),
  146. UpdateForgeL1L2BatchTimeout: make([]RollupEventUpdateForgeL1L2BatchTimeout, 0),
  147. UpdateFeeAddToken: make([]RollupEventUpdateFeeAddToken, 0),
  148. Withdraw: make([]RollupEventWithdraw, 0),
  149. }
  150. }
  151. // RollupForgeBatchArgs are the arguments to the ForgeBatch function in the Rollup Smart Contract
  152. type RollupForgeBatchArgs struct {
  153. NewLastIdx int64
  154. NewStRoot *big.Int
  155. NewExitRoot *big.Int
  156. L1UserTxs []common.L1Tx
  157. L1CoordinatorTxs []common.L1Tx
  158. L1CoordinatorTxsAuths [][]byte // Authorization for accountCreations for each L1CoordinatorTx
  159. L2TxsData []common.L2Tx
  160. FeeIdxCoordinator []common.Idx
  161. // Circuit selector
  162. VerifierIdx uint8
  163. L1Batch bool
  164. ProofA [2]*big.Int
  165. ProofB [2][2]*big.Int
  166. ProofC [2]*big.Int
  167. }
  168. // RollupForgeBatchArgsAux are the arguments to the ForgeBatch function in the Rollup Smart Contract
  169. type rollupForgeBatchArgsAux struct {
  170. NewLastIdx *big.Int
  171. NewStRoot *big.Int
  172. NewExitRoot *big.Int
  173. EncodedL1CoordinatorTx []byte
  174. L1L2TxsData []byte
  175. FeeIdxCoordinator []byte
  176. // Circuit selector
  177. VerifierIdx uint8
  178. L1Batch bool
  179. ProofA [2]*big.Int
  180. ProofB [2][2]*big.Int
  181. ProofC [2]*big.Int
  182. }
  183. // RollupInterface is the inteface to to Rollup Smart Contract
  184. type RollupInterface interface {
  185. //
  186. // Smart Contract Methods
  187. //
  188. // Public Functions
  189. RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error)
  190. RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error)
  191. RollupWithdrawMerkleProof(babyPubKey *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error)
  192. RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error)
  193. RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (*types.Transaction, error)
  194. RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error)
  195. // Governance Public Functions
  196. RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (*types.Transaction, error)
  197. RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (*types.Transaction, error)
  198. // Viewers
  199. RollupRegisterTokensCount() (*big.Int, error)
  200. RollupLastForgedBatch() (int64, error)
  201. //
  202. // Smart Contract Status
  203. //
  204. RollupConstants() (*common.RollupConstants, error)
  205. RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error)
  206. RollupForgeBatchArgs(ethCommon.Hash, uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error)
  207. }
  208. //
  209. // Implementation
  210. //
  211. // RollupClient is the implementation of the interface to the Rollup Smart Contract in ethereum.
  212. type RollupClient struct {
  213. client *EthereumClient
  214. chainID *big.Int
  215. address ethCommon.Address
  216. tokenHEZCfg TokenConfig
  217. hermez *Hermez.Hermez
  218. tokenHEZ *HEZ.HEZ
  219. contractAbi abi.ABI
  220. opts *bind.CallOpts
  221. }
  222. // NewRollupClient creates a new RollupClient
  223. func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZCfg TokenConfig) (*RollupClient, error) {
  224. contractAbi, err := abi.JSON(strings.NewReader(string(Hermez.HermezABI)))
  225. if err != nil {
  226. return nil, tracerr.Wrap(err)
  227. }
  228. hermez, err := Hermez.NewHermez(address, client.Client())
  229. if err != nil {
  230. return nil, tracerr.Wrap(err)
  231. }
  232. tokenHEZ, err := HEZ.NewHEZ(tokenHEZCfg.Address, client.Client())
  233. if err != nil {
  234. return nil, tracerr.Wrap(err)
  235. }
  236. chainID, err := client.client.ChainID(context.Background())
  237. if err != nil {
  238. return nil, tracerr.Wrap(err)
  239. }
  240. return &RollupClient{
  241. client: client,
  242. chainID: chainID,
  243. address: address,
  244. tokenHEZCfg: tokenHEZCfg,
  245. hermez: hermez,
  246. tokenHEZ: tokenHEZ,
  247. contractAbi: contractAbi,
  248. opts: newCallOpts(),
  249. }, nil
  250. }
  251. // RollupForgeBatch is the interface to call the smart contract function
  252. func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) {
  253. if tx, err = c.client.CallAuth(
  254. 1000000, //nolint:gomnd
  255. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  256. rollupConst, err := c.RollupConstants()
  257. if err != nil {
  258. return nil, tracerr.Wrap(err)
  259. }
  260. nLevels := rollupConst.Verifiers[args.VerifierIdx].NLevels
  261. lenBytes := nLevels / 8 //nolint:gomnd
  262. newLastIdx := big.NewInt(int64(args.NewLastIdx))
  263. // L1CoordinatorBytes
  264. var l1CoordinatorBytes []byte
  265. for i := 0; i < len(args.L1CoordinatorTxs); i++ {
  266. l1 := args.L1CoordinatorTxs[i]
  267. bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i])
  268. if err != nil {
  269. return nil, tracerr.Wrap(err)
  270. }
  271. l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...)
  272. }
  273. // L1L2TxData
  274. var l1l2TxData []byte
  275. for i := 0; i < len(args.L1UserTxs); i++ {
  276. l1User := args.L1UserTxs[i]
  277. bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels))
  278. if err != nil {
  279. return nil, tracerr.Wrap(err)
  280. }
  281. l1l2TxData = append(l1l2TxData, bytesl1User[:]...)
  282. }
  283. for i := 0; i < len(args.L1CoordinatorTxs); i++ {
  284. l1Coord := args.L1CoordinatorTxs[i]
  285. bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels))
  286. if err != nil {
  287. return nil, tracerr.Wrap(err)
  288. }
  289. l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...)
  290. }
  291. for i := 0; i < len(args.L2TxsData); i++ {
  292. l2 := args.L2TxsData[i]
  293. bytesl2, err := l2.BytesDataAvailability(uint32(nLevels))
  294. if err != nil {
  295. return nil, tracerr.Wrap(err)
  296. }
  297. l1l2TxData = append(l1l2TxData, bytesl2[:]...)
  298. }
  299. // FeeIdxCoordinator
  300. var feeIdxCoordinator []byte
  301. if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator {
  302. return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v",
  303. common.RollupConstMaxFeeIdxCoordinator))
  304. }
  305. for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ {
  306. feeIdx := common.Idx(0)
  307. if i < len(args.FeeIdxCoordinator) {
  308. feeIdx = args.FeeIdxCoordinator[i]
  309. }
  310. bytesFeeIdx, err := feeIdx.Bytes()
  311. if err != nil {
  312. return nil, tracerr.Wrap(err)
  313. }
  314. feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...)
  315. }
  316. return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC)
  317. },
  318. ); err != nil {
  319. return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err))
  320. }
  321. return tx, nil
  322. }
  323. // RollupAddToken is the interface to call the smart contract function.
  324. // `feeAddToken` is the amount of HEZ tokens that will be paid to add the
  325. // token. `feeAddToken` must match the public value of the smart contract.
  326. func (c *RollupClient) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (tx *types.Transaction, err error) {
  327. if tx, err = c.client.CallAuth(
  328. 0,
  329. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  330. owner := c.client.account.Address
  331. spender := c.address
  332. nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
  333. if err != nil {
  334. return nil, tracerr.Wrap(err)
  335. }
  336. tokenName := c.tokenHEZCfg.Name
  337. tokenAddr := c.tokenHEZCfg.Address
  338. digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, feeAddToken, nonce, deadline, tokenName)
  339. signature, _ := c.client.ks.SignHash(*c.client.account, digest)
  340. permit := createPermit(owner, spender, feeAddToken, deadline, digest, signature)
  341. return c.hermez.AddToken(auth, tokenAddress, permit)
  342. },
  343. ); err != nil {
  344. return nil, tracerr.Wrap(fmt.Errorf("Failed add Token %w", err))
  345. }
  346. return tx, nil
  347. }
  348. // RollupWithdrawMerkleProof is the interface to call the smart contract function
  349. func (c *RollupClient) RollupWithdrawMerkleProof(fromBJJ *babyjub.PublicKey, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (tx *types.Transaction, err error) {
  350. if tx, err = c.client.CallAuth(
  351. 0,
  352. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  353. pkCompL := fromBJJ.Compress()
  354. pkCompB := common.SwapEndianness(pkCompL[:])
  355. babyPubKey := new(big.Int).SetBytes(pkCompB)
  356. numExitRootB := uint32(numExitRoot)
  357. idxBig := big.NewInt(idx)
  358. return c.hermez.WithdrawMerkleProof(auth, tokenID, amount, babyPubKey, numExitRootB, siblings, idxBig, instantWithdraw)
  359. },
  360. ); err != nil {
  361. return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawMerkleProof: %w", err))
  362. }
  363. return tx, nil
  364. }
  365. // RollupWithdrawCircuit is the interface to call the smart contract function
  366. func (c *RollupClient) RollupWithdrawCircuit(proofA, proofC [2]*big.Int, proofB [2][2]*big.Int, tokenID uint32, numExitRoot, idx int64, amount *big.Int, instantWithdraw bool) (*types.Transaction, error) {
  367. log.Error("TODO")
  368. return nil, tracerr.Wrap(errTODO)
  369. }
  370. // RollupL1UserTxERC20ETH is the interface to call the smart contract function
  371. func (c *RollupClient) RollupL1UserTxERC20ETH(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64) (tx *types.Transaction, err error) {
  372. if tx, err = c.client.CallAuth(
  373. 0,
  374. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  375. var babyPubKey *big.Int
  376. if fromBJJ != nil {
  377. pkCompL := fromBJJ.Compress()
  378. pkCompB := common.SwapEndianness(pkCompL[:])
  379. babyPubKey = new(big.Int).SetBytes(pkCompB)
  380. } else {
  381. babyPubKey = big.NewInt(0)
  382. }
  383. fromIdxBig := big.NewInt(fromIdx)
  384. toIdxBig := big.NewInt(toIdx)
  385. depositAmountF, err := common.NewFloat16(depositAmount)
  386. if err != nil {
  387. return nil, tracerr.Wrap(err)
  388. }
  389. amountF, err := common.NewFloat16(amount)
  390. if err != nil {
  391. return nil, tracerr.Wrap(err)
  392. }
  393. if tokenID == 0 {
  394. auth.Value = depositAmount
  395. }
  396. var permit []byte
  397. return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
  398. uint16(amountF), tokenID, toIdxBig, permit)
  399. },
  400. ); err != nil {
  401. return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20/ETH: %w", err))
  402. }
  403. return tx, nil
  404. }
  405. // RollupL1UserTxERC20Permit is the interface to call the smart contract function
  406. func (c *RollupClient) RollupL1UserTxERC20Permit(fromBJJ *babyjub.PublicKey, fromIdx int64, depositAmount *big.Int, amount *big.Int, tokenID uint32, toIdx int64, deadline *big.Int) (tx *types.Transaction, err error) {
  407. if tx, err = c.client.CallAuth(
  408. 0,
  409. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  410. var babyPubKey *big.Int
  411. if fromBJJ != nil {
  412. pkCompL := fromBJJ.Compress()
  413. pkCompB := common.SwapEndianness(pkCompL[:])
  414. babyPubKey = new(big.Int).SetBytes(pkCompB)
  415. } else {
  416. babyPubKey = big.NewInt(0)
  417. }
  418. fromIdxBig := big.NewInt(fromIdx)
  419. toIdxBig := big.NewInt(toIdx)
  420. depositAmountF, err := common.NewFloat16(depositAmount)
  421. if err != nil {
  422. return nil, tracerr.Wrap(err)
  423. }
  424. amountF, err := common.NewFloat16(amount)
  425. if err != nil {
  426. return nil, tracerr.Wrap(err)
  427. }
  428. if tokenID == 0 {
  429. auth.Value = depositAmount
  430. }
  431. owner := c.client.account.Address
  432. spender := c.address
  433. nonce, err := c.tokenHEZ.Nonces(c.opts, owner)
  434. if err != nil {
  435. return nil, tracerr.Wrap(err)
  436. }
  437. tokenName := c.tokenHEZCfg.Name
  438. tokenAddr := c.tokenHEZCfg.Address
  439. digest, _ := createPermitDigest(tokenAddr, owner, spender, c.chainID, amount, nonce, deadline, tokenName)
  440. signature, _ := c.client.ks.SignHash(*c.client.account, digest)
  441. permit := createPermit(owner, spender, amount, deadline, digest, signature)
  442. return c.hermez.AddL1Transaction(auth, babyPubKey, fromIdxBig, uint16(depositAmountF),
  443. uint16(amountF), tokenID, toIdxBig, permit)
  444. },
  445. ); err != nil {
  446. return nil, tracerr.Wrap(fmt.Errorf("Failed add L1 Tx ERC20Permit: %w", err))
  447. }
  448. return tx, nil
  449. }
  450. // RollupRegisterTokensCount is the interface to call the smart contract function
  451. func (c *RollupClient) RollupRegisterTokensCount() (registerTokensCount *big.Int, err error) {
  452. if err := c.client.Call(func(ec *ethclient.Client) error {
  453. registerTokensCount, err = c.hermez.RegisterTokensCount(c.opts)
  454. return tracerr.Wrap(err)
  455. }); err != nil {
  456. return nil, tracerr.Wrap(err)
  457. }
  458. return registerTokensCount, nil
  459. }
  460. // RollupLastForgedBatch is the interface to call the smart contract function
  461. func (c *RollupClient) RollupLastForgedBatch() (lastForgedBatch int64, err error) {
  462. if err := c.client.Call(func(ec *ethclient.Client) error {
  463. _lastForgedBatch, err := c.hermez.LastForgedBatch(c.opts)
  464. lastForgedBatch = int64(_lastForgedBatch)
  465. return tracerr.Wrap(err)
  466. }); err != nil {
  467. return 0, tracerr.Wrap(err)
  468. }
  469. return lastForgedBatch, nil
  470. }
  471. // RollupUpdateForgeL1L2BatchTimeout is the interface to call the smart contract function
  472. func (c *RollupClient) RollupUpdateForgeL1L2BatchTimeout(newForgeL1L2BatchTimeout int64) (tx *types.Transaction, err error) {
  473. if tx, err = c.client.CallAuth(
  474. 0,
  475. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  476. return c.hermez.UpdateForgeL1L2BatchTimeout(auth, uint8(newForgeL1L2BatchTimeout))
  477. },
  478. ); err != nil {
  479. return nil, tracerr.Wrap(fmt.Errorf("Failed update ForgeL1L2BatchTimeout: %w", err))
  480. }
  481. return tx, nil
  482. }
  483. // RollupUpdateFeeAddToken is the interface to call the smart contract function
  484. func (c *RollupClient) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Transaction, err error) {
  485. if tx, err = c.client.CallAuth(
  486. 0,
  487. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  488. return c.hermez.UpdateFeeAddToken(auth, newFeeAddToken)
  489. },
  490. ); err != nil {
  491. return nil, tracerr.Wrap(fmt.Errorf("Failed update FeeAddToken: %w", err))
  492. }
  493. return tx, nil
  494. }
  495. // RollupUpdateBucketsParameters is the interface to call the smart contract function
  496. func (c *RollupClient) RollupUpdateBucketsParameters(
  497. arrayBuckets [common.RollupConstNumBuckets]RollupUpdateBucketsParameters,
  498. ) (tx *types.Transaction, err error) {
  499. params := [common.RollupConstNumBuckets][4]*big.Int{}
  500. for i, bucket := range arrayBuckets {
  501. params[i][0] = bucket.CeilUSD
  502. params[i][1] = bucket.Withdrawals
  503. params[i][2] = bucket.BlockWithdrawalRate
  504. params[i][3] = bucket.MaxWithdrawals
  505. }
  506. if tx, err = c.client.CallAuth(
  507. 12500000, //nolint:gomnd
  508. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  509. return c.hermez.UpdateBucketsParameters(auth, params)
  510. },
  511. ); err != nil {
  512. return nil, tracerr.Wrap(fmt.Errorf("Failed update Buckets Parameters: %w", err))
  513. }
  514. return tx, nil
  515. }
  516. // RollupUpdateTokenExchange is the interface to call the smart contract function
  517. func (c *RollupClient) RollupUpdateTokenExchange(addressArray []ethCommon.Address, valueArray []uint64) (tx *types.Transaction, err error) {
  518. if tx, err = c.client.CallAuth(
  519. 0,
  520. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  521. return c.hermez.UpdateTokenExchange(auth, addressArray, valueArray)
  522. },
  523. ); err != nil {
  524. return nil, tracerr.Wrap(fmt.Errorf("Failed update Token Exchange: %w", err))
  525. }
  526. return tx, nil
  527. }
  528. // RollupUpdateWithdrawalDelay is the interface to call the smart contract function
  529. func (c *RollupClient) RollupUpdateWithdrawalDelay(newWithdrawalDelay int64) (tx *types.Transaction, err error) {
  530. if tx, err = c.client.CallAuth(
  531. 0,
  532. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  533. return c.hermez.UpdateWithdrawalDelay(auth, uint64(newWithdrawalDelay))
  534. },
  535. ); err != nil {
  536. return nil, tracerr.Wrap(fmt.Errorf("Failed update WithdrawalDelay: %w", err))
  537. }
  538. return tx, nil
  539. }
  540. // RollupSafeMode is the interface to call the smart contract function
  541. func (c *RollupClient) RollupSafeMode() (tx *types.Transaction, err error) {
  542. if tx, err = c.client.CallAuth(
  543. 0,
  544. func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
  545. return c.hermez.SafeMode(auth)
  546. },
  547. ); err != nil {
  548. return nil, tracerr.Wrap(fmt.Errorf("Failed update Safe Mode: %w", err))
  549. }
  550. return tx, nil
  551. }
  552. // RollupInstantWithdrawalViewer is the interface to call the smart contract function
  553. func (c *RollupClient) RollupInstantWithdrawalViewer(tokenAddress ethCommon.Address, amount *big.Int) (instantAllowed bool, err error) {
  554. if err := c.client.Call(func(ec *ethclient.Client) error {
  555. instantAllowed, err = c.hermez.InstantWithdrawalViewer(c.opts, tokenAddress, amount)
  556. return tracerr.Wrap(err)
  557. }); err != nil {
  558. return false, tracerr.Wrap(err)
  559. }
  560. return instantAllowed, nil
  561. }
  562. // RollupConstants returns the Constants of the Rollup Smart Contract
  563. func (c *RollupClient) RollupConstants() (rollupConstants *common.RollupConstants, err error) {
  564. rollupConstants = new(common.RollupConstants)
  565. if err := c.client.Call(func(ec *ethclient.Client) error {
  566. absoluteMaxL1L2BatchTimeout, err := c.hermez.ABSOLUTEMAXL1L2BATCHTIMEOUT(c.opts)
  567. if err != nil {
  568. return tracerr.Wrap(err)
  569. }
  570. rollupConstants.AbsoluteMaxL1L2BatchTimeout = int64(absoluteMaxL1L2BatchTimeout)
  571. rollupConstants.TokenHEZ, err = c.hermez.TokenHEZ(c.opts)
  572. if err != nil {
  573. return tracerr.Wrap(err)
  574. }
  575. for i := int64(0); i < int64(common.LenVerifiers); i++ {
  576. var newRollupVerifier common.RollupVerifierStruct
  577. rollupVerifier, err := c.hermez.RollupVerifiers(c.opts, big.NewInt(i))
  578. if err != nil {
  579. return tracerr.Wrap(err)
  580. }
  581. newRollupVerifier.MaxTx = rollupVerifier.MaxTx.Int64()
  582. newRollupVerifier.NLevels = rollupVerifier.NLevels.Int64()
  583. rollupConstants.Verifiers = append(rollupConstants.Verifiers, newRollupVerifier)
  584. }
  585. rollupConstants.HermezAuctionContract, err = c.hermez.HermezAuctionContract(c.opts)
  586. if err != nil {
  587. return tracerr.Wrap(err)
  588. }
  589. rollupConstants.HermezGovernanceAddress, err = c.hermez.HermezGovernanceAddress(c.opts)
  590. if err != nil {
  591. return tracerr.Wrap(err)
  592. }
  593. rollupConstants.WithdrawDelayerContract, err = c.hermez.WithdrawDelayerContract(c.opts)
  594. return tracerr.Wrap(err)
  595. }); err != nil {
  596. return nil, tracerr.Wrap(err)
  597. }
  598. return rollupConstants, nil
  599. }
  600. var (
  601. logHermezL1UserTxEvent = crypto.Keccak256Hash([]byte("L1UserTxEvent(uint32,uint8,bytes)"))
  602. logHermezAddToken = crypto.Keccak256Hash([]byte("AddToken(address,uint32)"))
  603. logHermezForgeBatch = crypto.Keccak256Hash([]byte("ForgeBatch(uint32,uint16)"))
  604. logHermezUpdateForgeL1L2BatchTimeout = crypto.Keccak256Hash([]byte("UpdateForgeL1L2BatchTimeout(uint8)"))
  605. logHermezUpdateFeeAddToken = crypto.Keccak256Hash([]byte("UpdateFeeAddToken(uint256)"))
  606. logHermezWithdrawEvent = crypto.Keccak256Hash([]byte("WithdrawEvent(uint48,uint32,bool)"))
  607. logHermezUpdateBucketWithdraw = crypto.Keccak256Hash([]byte("UpdateBucketWithdraw(uint8,uint256,uint256)"))
  608. logHermezUpdateWithdrawalDelay = crypto.Keccak256Hash([]byte("UpdateWithdrawalDelay(uint64)"))
  609. logHermezUpdateBucketsParameters = crypto.Keccak256Hash([]byte("UpdateBucketsParameters(uint256[4][" + strconv.Itoa(common.RollupConstNumBuckets) + "])"))
  610. logHermezUpdateTokenExchange = crypto.Keccak256Hash([]byte("UpdateTokenExchange(address[],uint64[])"))
  611. logHermezSafeMode = crypto.Keccak256Hash([]byte("SafeMode()"))
  612. )
  613. // RollupEventsByBlock returns the events in a block that happened in the Rollup Smart Contract
  614. func (c *RollupClient) RollupEventsByBlock(blockNum int64) (*RollupEvents, *ethCommon.Hash, error) {
  615. var rollupEvents RollupEvents
  616. var blockHash *ethCommon.Hash
  617. query := ethereum.FilterQuery{
  618. FromBlock: big.NewInt(blockNum),
  619. ToBlock: big.NewInt(blockNum),
  620. Addresses: []ethCommon.Address{
  621. c.address,
  622. },
  623. BlockHash: nil,
  624. Topics: [][]ethCommon.Hash{},
  625. }
  626. logs, err := c.client.client.FilterLogs(context.Background(), query)
  627. if err != nil {
  628. return nil, nil, tracerr.Wrap(err)
  629. }
  630. if len(logs) > 0 {
  631. blockHash = &logs[0].BlockHash
  632. }
  633. for _, vLog := range logs {
  634. if vLog.BlockHash != *blockHash {
  635. log.Errorw("Block hash mismatch", "expected", blockHash.String(), "got", vLog.BlockHash.String())
  636. return nil, nil, tracerr.Wrap(ErrBlockHashMismatchEvent)
  637. }
  638. switch vLog.Topics[0] {
  639. case logHermezL1UserTxEvent:
  640. var L1UserTxAux rollupEventL1UserTxAux
  641. var L1UserTx RollupEventL1UserTx
  642. err := c.contractAbi.Unpack(&L1UserTxAux, "L1UserTxEvent", vLog.Data)
  643. if err != nil {
  644. return nil, nil, tracerr.Wrap(err)
  645. }
  646. L1Tx, err := common.L1UserTxFromBytes(L1UserTxAux.L1UserTx)
  647. if err != nil {
  648. return nil, nil, tracerr.Wrap(err)
  649. }
  650. toForgeL1TxsNum := new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
  651. L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
  652. L1Tx.Position = int(new(big.Int).SetBytes(vLog.Topics[2][:]).Int64())
  653. L1Tx.UserOrigin = true
  654. L1UserTx.L1UserTx = *L1Tx
  655. rollupEvents.L1UserTx = append(rollupEvents.L1UserTx, L1UserTx)
  656. case logHermezAddToken:
  657. var addToken RollupEventAddToken
  658. err := c.contractAbi.Unpack(&addToken, "AddToken", vLog.Data)
  659. if err != nil {
  660. return nil, nil, tracerr.Wrap(err)
  661. }
  662. addToken.TokenAddress = ethCommon.BytesToAddress(vLog.Topics[1].Bytes())
  663. rollupEvents.AddToken = append(rollupEvents.AddToken, addToken)
  664. case logHermezForgeBatch:
  665. var forgeBatch RollupEventForgeBatch
  666. err := c.contractAbi.Unpack(&forgeBatch, "ForgeBatch", vLog.Data)
  667. if err != nil {
  668. return nil, nil, tracerr.Wrap(err)
  669. }
  670. forgeBatch.BatchNum = new(big.Int).SetBytes(vLog.Topics[1][:]).Int64()
  671. forgeBatch.EthTxHash = vLog.TxHash
  672. // forgeBatch.Sender = vLog.Address
  673. rollupEvents.ForgeBatch = append(rollupEvents.ForgeBatch, forgeBatch)
  674. case logHermezUpdateForgeL1L2BatchTimeout:
  675. var updateForgeL1L2BatchTimeout struct {
  676. NewForgeL1L2BatchTimeout uint8
  677. }
  678. err := c.contractAbi.Unpack(&updateForgeL1L2BatchTimeout, "UpdateForgeL1L2BatchTimeout", vLog.Data)
  679. if err != nil {
  680. return nil, nil, tracerr.Wrap(err)
  681. }
  682. rollupEvents.UpdateForgeL1L2BatchTimeout = append(rollupEvents.UpdateForgeL1L2BatchTimeout,
  683. RollupEventUpdateForgeL1L2BatchTimeout{
  684. NewForgeL1L2BatchTimeout: int64(updateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout),
  685. })
  686. case logHermezUpdateFeeAddToken:
  687. var updateFeeAddToken RollupEventUpdateFeeAddToken
  688. err := c.contractAbi.Unpack(&updateFeeAddToken, "UpdateFeeAddToken", vLog.Data)
  689. if err != nil {
  690. return nil, nil, tracerr.Wrap(err)
  691. }
  692. rollupEvents.UpdateFeeAddToken = append(rollupEvents.UpdateFeeAddToken, updateFeeAddToken)
  693. case logHermezWithdrawEvent:
  694. var withdraw RollupEventWithdraw
  695. withdraw.Idx = new(big.Int).SetBytes(vLog.Topics[1][:]).Uint64()
  696. withdraw.NumExitRoot = new(big.Int).SetBytes(vLog.Topics[2][:]).Uint64()
  697. instantWithdraw := new(big.Int).SetBytes(vLog.Topics[3][:]).Uint64()
  698. if instantWithdraw == 1 {
  699. withdraw.InstantWithdraw = true
  700. }
  701. withdraw.TxHash = vLog.TxHash
  702. rollupEvents.Withdraw = append(rollupEvents.Withdraw, withdraw)
  703. case logHermezUpdateBucketWithdraw:
  704. var updateBucketWithdrawAux rollupEventUpdateBucketWithdrawAux
  705. var updateBucketWithdraw RollupEventUpdateBucketWithdraw
  706. err := c.contractAbi.Unpack(&updateBucketWithdrawAux, "UpdateBucketWithdraw", vLog.Data)
  707. if err != nil {
  708. return nil, nil, tracerr.Wrap(err)
  709. }
  710. updateBucketWithdraw.Withdrawals = updateBucketWithdrawAux.Withdrawals
  711. updateBucketWithdraw.NumBucket = int(new(big.Int).SetBytes(vLog.Topics[1][:]).Int64())
  712. updateBucketWithdraw.BlockStamp = new(big.Int).SetBytes(vLog.Topics[2][:]).Int64()
  713. rollupEvents.UpdateBucketWithdraw = append(rollupEvents.UpdateBucketWithdraw, updateBucketWithdraw)
  714. case logHermezUpdateWithdrawalDelay:
  715. var withdrawalDelay RollupEventUpdateWithdrawalDelay
  716. err := c.contractAbi.Unpack(&withdrawalDelay, "UpdateWithdrawalDelay", vLog.Data)
  717. if err != nil {
  718. return nil, nil, tracerr.Wrap(err)
  719. }
  720. rollupEvents.UpdateWithdrawalDelay = append(rollupEvents.UpdateWithdrawalDelay, withdrawalDelay)
  721. case logHermezUpdateBucketsParameters:
  722. var bucketsParametersAux rollupEventUpdateBucketsParametersAux
  723. var bucketsParameters RollupEventUpdateBucketsParameters
  724. err := c.contractAbi.Unpack(&bucketsParametersAux, "UpdateBucketsParameters", vLog.Data)
  725. if err != nil {
  726. return nil, nil, tracerr.Wrap(err)
  727. }
  728. for i, bucket := range bucketsParametersAux.ArrayBuckets {
  729. bucketsParameters.ArrayBuckets[i].CeilUSD = bucket[0]
  730. bucketsParameters.ArrayBuckets[i].Withdrawals = bucket[1]
  731. bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = bucket[2]
  732. bucketsParameters.ArrayBuckets[i].MaxWithdrawals = bucket[3]
  733. }
  734. rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters, bucketsParameters)
  735. case logHermezUpdateTokenExchange:
  736. var tokensExchange RollupEventUpdateTokenExchange
  737. err := c.contractAbi.Unpack(&tokensExchange, "UpdateTokenExchange", vLog.Data)
  738. if err != nil {
  739. return nil, nil, tracerr.Wrap(err)
  740. }
  741. rollupEvents.UpdateTokenExchange = append(rollupEvents.UpdateTokenExchange, tokensExchange)
  742. case logHermezSafeMode:
  743. var safeMode RollupEventSafeMode
  744. rollupEvents.SafeMode = append(rollupEvents.SafeMode, safeMode)
  745. // Also add an UpdateBucketsParameter with
  746. // SafeMode=true to keep the order between `safeMode`
  747. // and `UpdateBucketsParameters`
  748. bucketsParameters := RollupEventUpdateBucketsParameters{
  749. SafeMode: true,
  750. }
  751. for i := range bucketsParameters.ArrayBuckets {
  752. bucketsParameters.ArrayBuckets[i].CeilUSD = big.NewInt(0)
  753. bucketsParameters.ArrayBuckets[i].Withdrawals = big.NewInt(0)
  754. bucketsParameters.ArrayBuckets[i].BlockWithdrawalRate = big.NewInt(0)
  755. bucketsParameters.ArrayBuckets[i].MaxWithdrawals = big.NewInt(0)
  756. }
  757. rollupEvents.UpdateBucketsParameters = append(rollupEvents.UpdateBucketsParameters,
  758. bucketsParameters)
  759. }
  760. }
  761. return &rollupEvents, blockHash, nil
  762. }
  763. // RollupForgeBatchArgs returns the arguments used in a ForgeBatch call in the
  764. // Rollup Smart Contract in the given transaction, and the sender address.
  765. func (c *RollupClient) RollupForgeBatchArgs(ethTxHash ethCommon.Hash, l1UserTxsLen uint16) (*RollupForgeBatchArgs, *ethCommon.Address, error) {
  766. tx, _, err := c.client.client.TransactionByHash(context.Background(), ethTxHash)
  767. if err != nil {
  768. return nil, nil, tracerr.Wrap(err)
  769. }
  770. txData := tx.Data()
  771. method, err := c.contractAbi.MethodById(txData[:4])
  772. if err != nil {
  773. return nil, nil, tracerr.Wrap(err)
  774. }
  775. receipt, err := c.client.client.TransactionReceipt(context.Background(), ethTxHash)
  776. if err != nil {
  777. return nil, nil, tracerr.Wrap(err)
  778. }
  779. sender, err := c.client.client.TransactionSender(context.Background(), tx, receipt.Logs[0].BlockHash, receipt.Logs[0].Index)
  780. if err != nil {
  781. return nil, nil, tracerr.Wrap(err)
  782. }
  783. var aux rollupForgeBatchArgsAux
  784. if err := method.Inputs.Unpack(&aux, txData[4:]); err != nil {
  785. return nil, nil, tracerr.Wrap(err)
  786. }
  787. rollupForgeBatchArgs := RollupForgeBatchArgs{
  788. L1Batch: aux.L1Batch,
  789. NewExitRoot: aux.NewExitRoot,
  790. NewLastIdx: aux.NewLastIdx.Int64(),
  791. NewStRoot: aux.NewStRoot,
  792. ProofA: aux.ProofA,
  793. ProofB: aux.ProofB,
  794. ProofC: aux.ProofC,
  795. VerifierIdx: aux.VerifierIdx,
  796. L1CoordinatorTxs: []common.L1Tx{},
  797. L1CoordinatorTxsAuths: [][]byte{},
  798. L2TxsData: []common.L2Tx{},
  799. FeeIdxCoordinator: []common.Idx{},
  800. }
  801. rollupConsts, err := c.RollupConstants()
  802. if err != nil {
  803. return nil, nil, tracerr.Wrap(err)
  804. }
  805. nLevels := rollupConsts.Verifiers[rollupForgeBatchArgs.VerifierIdx].NLevels
  806. lenL1L2TxsBytes := int((nLevels/8)*2 + 2 + 1)
  807. numBytesL1TxUser := int(l1UserTxsLen) * lenL1L2TxsBytes
  808. numTxsL1Coord := len(aux.EncodedL1CoordinatorTx) / common.L1CoordinatorTxBytesLen
  809. numBytesL1TxCoord := numTxsL1Coord * lenL1L2TxsBytes
  810. numBeginL2Tx := numBytesL1TxCoord + numBytesL1TxUser
  811. l1UserTxsData := []byte{}
  812. if l1UserTxsLen > 0 {
  813. l1UserTxsData = aux.L1L2TxsData[:numBytesL1TxUser]
  814. }
  815. for i := 0; i < int(l1UserTxsLen); i++ {
  816. l1Tx, err := common.L1TxFromDataAvailability(l1UserTxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], uint32(nLevels))
  817. if err != nil {
  818. return nil, nil, tracerr.Wrap(err)
  819. }
  820. rollupForgeBatchArgs.L1UserTxs = append(rollupForgeBatchArgs.L1UserTxs, *l1Tx)
  821. }
  822. l2TxsData := []byte{}
  823. if numBeginL2Tx < len(aux.L1L2TxsData) {
  824. l2TxsData = aux.L1L2TxsData[numBeginL2Tx:]
  825. }
  826. numTxsL2 := len(l2TxsData) / lenL1L2TxsBytes
  827. for i := 0; i < numTxsL2; i++ {
  828. l2Tx, err := common.L2TxFromBytesDataAvailability(l2TxsData[i*lenL1L2TxsBytes:(i+1)*lenL1L2TxsBytes], int(nLevels))
  829. if err != nil {
  830. return nil, nil, tracerr.Wrap(err)
  831. }
  832. rollupForgeBatchArgs.L2TxsData = append(rollupForgeBatchArgs.L2TxsData, *l2Tx)
  833. }
  834. for i := 0; i < numTxsL1Coord; i++ {
  835. bytesL1Coordinator := aux.EncodedL1CoordinatorTx[i*common.L1CoordinatorTxBytesLen : (i+1)*common.L1CoordinatorTxBytesLen]
  836. var signature []byte
  837. v := bytesL1Coordinator[0]
  838. s := bytesL1Coordinator[1:33]
  839. r := bytesL1Coordinator[33:65]
  840. signature = append(signature, r[:]...)
  841. signature = append(signature, s[:]...)
  842. signature = append(signature, v)
  843. l1Tx, err := common.L1CoordinatorTxFromBytes(bytesL1Coordinator, c.chainID, c.address)
  844. if err != nil {
  845. return nil, nil, tracerr.Wrap(err)
  846. }
  847. rollupForgeBatchArgs.L1CoordinatorTxs = append(rollupForgeBatchArgs.L1CoordinatorTxs, *l1Tx)
  848. rollupForgeBatchArgs.L1CoordinatorTxsAuths = append(rollupForgeBatchArgs.L1CoordinatorTxsAuths, signature)
  849. }
  850. lenFeeIdxCoordinatorBytes := int(nLevels / 8) //nolint:gomnd
  851. numFeeIdxCoordinator := len(aux.FeeIdxCoordinator) / lenFeeIdxCoordinatorBytes
  852. for i := 0; i < numFeeIdxCoordinator; i++ {
  853. var paddedFeeIdx [6]byte
  854. // TODO: This check is not necessary: the first case will always work. Test it before removing the if.
  855. if lenFeeIdxCoordinatorBytes < common.IdxBytesLen {
  856. copy(paddedFeeIdx[6-lenFeeIdxCoordinatorBytes:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
  857. } else {
  858. copy(paddedFeeIdx[:], aux.FeeIdxCoordinator[i*lenFeeIdxCoordinatorBytes:(i+1)*lenFeeIdxCoordinatorBytes])
  859. }
  860. feeIdxCoordinator, err := common.IdxFromBytes(paddedFeeIdx[:])
  861. if err != nil {
  862. return nil, nil, tracerr.Wrap(err)
  863. }
  864. if feeIdxCoordinator != common.Idx(0) {
  865. rollupForgeBatchArgs.FeeIdxCoordinator = append(rollupForgeBatchArgs.FeeIdxCoordinator, feeIdxCoordinator)
  866. }
  867. }
  868. return &rollupForgeBatchArgs, &sender, nil
  869. }