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.

643 lines
21 KiB

  1. package api
  2. import (
  3. "encoding/base64"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "strconv"
  8. "time"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/hermeznetwork/hermez-node/db"
  12. "github.com/hermeznetwork/hermez-node/db/historydb"
  13. "github.com/hermeznetwork/hermez-node/db/l2db"
  14. "github.com/hermeznetwork/hermez-node/eth"
  15. "github.com/iden3/go-iden3-crypto/babyjub"
  16. "github.com/iden3/go-merkletree"
  17. )
  18. const exitIdx = "hez:EXIT:1"
  19. type errorMsg struct {
  20. Message string
  21. }
  22. func bjjToString(bjj *babyjub.PublicKey) string {
  23. pkComp := [32]byte(bjj.Compress())
  24. sum := pkComp[0]
  25. for i := 1; i < len(pkComp); i++ {
  26. sum += pkComp[i]
  27. }
  28. bjjSum := append(pkComp[:], sum)
  29. return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
  30. }
  31. func ethAddrToHez(addr ethCommon.Address) string {
  32. return "hez:" + addr.String()
  33. }
  34. func idxToHez(idx common.Idx, tokenSymbol string) string {
  35. if idx == 1 {
  36. return exitIdx
  37. }
  38. return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
  39. }
  40. // History Tx
  41. type historyTxsAPI struct {
  42. Txs []historyTxAPI `json:"transactions"`
  43. Pagination *db.Pagination `json:"pagination"`
  44. }
  45. func (htx *historyTxsAPI) GetPagination() *db.Pagination {
  46. if htx.Txs[0].ItemID < htx.Txs[len(htx.Txs)-1].ItemID {
  47. htx.Pagination.FirstReturnedItem = htx.Txs[0].ItemID
  48. htx.Pagination.LastReturnedItem = htx.Txs[len(htx.Txs)-1].ItemID
  49. } else {
  50. htx.Pagination.LastReturnedItem = htx.Txs[0].ItemID
  51. htx.Pagination.FirstReturnedItem = htx.Txs[len(htx.Txs)-1].ItemID
  52. }
  53. return htx.Pagination
  54. }
  55. func (htx *historyTxsAPI) Len() int { return len(htx.Txs) }
  56. type l1Info struct {
  57. ToForgeL1TxsNum *int64 `json:"toForgeL1TransactionsNum"`
  58. UserOrigin bool `json:"userOrigin"`
  59. FromEthAddr string `json:"fromHezEthereumAddress"`
  60. FromBJJ string `json:"fromBJJ"`
  61. LoadAmount string `json:"loadAmount"`
  62. HistoricLoadAmountUSD *float64 `json:"historicLoadAmountUSD"`
  63. EthBlockNum int64 `json:"ethereumBlockNum"`
  64. }
  65. type l2Info struct {
  66. Fee common.FeeSelector `json:"fee"`
  67. HistoricFeeUSD *float64 `json:"historicFeeUSD"`
  68. Nonce common.Nonce `json:"nonce"`
  69. }
  70. type historyTxAPI struct {
  71. IsL1 string `json:"L1orL2"`
  72. TxID common.TxID `json:"id"`
  73. ItemID int `json:"itemId"`
  74. Type common.TxType `json:"type"`
  75. Position int `json:"position"`
  76. FromIdx *string `json:"fromAccountIndex"`
  77. ToIdx string `json:"toAccountIndex"`
  78. Amount string `json:"amount"`
  79. BatchNum *common.BatchNum `json:"batchNum"`
  80. HistoricUSD *float64 `json:"historicUSD"`
  81. Timestamp time.Time `json:"timestamp"`
  82. L1Info *l1Info `json:"L1Info"`
  83. L2Info *l2Info `json:"L2Info"`
  84. Token tokenAPI `json:"token"`
  85. }
  86. func historyTxsToAPI(dbTxs []historydb.HistoryTx) []historyTxAPI {
  87. apiTxs := []historyTxAPI{}
  88. for i := 0; i < len(dbTxs); i++ {
  89. apiTx := historyTxAPI{
  90. TxID: dbTxs[i].TxID,
  91. ItemID: dbTxs[i].ItemID,
  92. Type: dbTxs[i].Type,
  93. Position: dbTxs[i].Position,
  94. ToIdx: idxToHez(dbTxs[i].ToIdx, dbTxs[i].TokenSymbol),
  95. Amount: dbTxs[i].Amount.String(),
  96. HistoricUSD: dbTxs[i].HistoricUSD,
  97. BatchNum: dbTxs[i].BatchNum,
  98. Timestamp: dbTxs[i].Timestamp,
  99. Token: tokenAPI{
  100. TokenID: dbTxs[i].TokenID,
  101. EthBlockNum: dbTxs[i].TokenEthBlockNum,
  102. EthAddr: dbTxs[i].TokenEthAddr,
  103. Name: dbTxs[i].TokenName,
  104. Symbol: dbTxs[i].TokenSymbol,
  105. Decimals: dbTxs[i].TokenDecimals,
  106. USD: dbTxs[i].TokenUSD,
  107. USDUpdate: dbTxs[i].TokenUSDUpdate,
  108. },
  109. L1Info: nil,
  110. L2Info: nil,
  111. }
  112. if dbTxs[i].FromIdx != nil {
  113. fromIdx := new(string)
  114. *fromIdx = idxToHez(*dbTxs[i].FromIdx, dbTxs[i].TokenSymbol)
  115. apiTx.FromIdx = fromIdx
  116. }
  117. if dbTxs[i].IsL1 {
  118. apiTx.IsL1 = "L1"
  119. apiTx.L1Info = &l1Info{
  120. ToForgeL1TxsNum: dbTxs[i].ToForgeL1TxsNum,
  121. UserOrigin: *dbTxs[i].UserOrigin,
  122. FromEthAddr: ethAddrToHez(*dbTxs[i].FromEthAddr),
  123. FromBJJ: bjjToString(dbTxs[i].FromBJJ),
  124. LoadAmount: dbTxs[i].LoadAmount.String(),
  125. HistoricLoadAmountUSD: dbTxs[i].HistoricLoadAmountUSD,
  126. EthBlockNum: dbTxs[i].EthBlockNum,
  127. }
  128. } else {
  129. apiTx.IsL1 = "L2"
  130. apiTx.L2Info = &l2Info{
  131. Fee: *dbTxs[i].Fee,
  132. HistoricFeeUSD: dbTxs[i].HistoricFeeUSD,
  133. Nonce: *dbTxs[i].Nonce,
  134. }
  135. }
  136. apiTxs = append(apiTxs, apiTx)
  137. }
  138. return apiTxs
  139. }
  140. // Exit
  141. type exitsAPI struct {
  142. Exits []exitAPI `json:"exits"`
  143. Pagination *db.Pagination `json:"pagination"`
  144. }
  145. func (e *exitsAPI) GetPagination() *db.Pagination {
  146. if e.Exits[0].ItemID < e.Exits[len(e.Exits)-1].ItemID {
  147. e.Pagination.FirstReturnedItem = e.Exits[0].ItemID
  148. e.Pagination.LastReturnedItem = e.Exits[len(e.Exits)-1].ItemID
  149. } else {
  150. e.Pagination.LastReturnedItem = e.Exits[0].ItemID
  151. e.Pagination.FirstReturnedItem = e.Exits[len(e.Exits)-1].ItemID
  152. }
  153. return e.Pagination
  154. }
  155. func (e *exitsAPI) Len() int { return len(e.Exits) }
  156. type exitAPI struct {
  157. ItemID int `json:"itemId"`
  158. BatchNum common.BatchNum `json:"batchNum"`
  159. AccountIdx string `json:"accountIndex"`
  160. MerkleProof *merkletree.CircomVerifierProof `json:"merkleProof"`
  161. Balance string `json:"balance"`
  162. InstantWithdrawn *int64 `json:"instantWithdrawn"`
  163. DelayedWithdrawRequest *int64 `json:"delayedWithdrawRequest"`
  164. DelayedWithdrawn *int64 `json:"delayedWithdrawn"`
  165. Token tokenAPI `json:"token"`
  166. }
  167. func historyExitsToAPI(dbExits []historydb.HistoryExit) []exitAPI {
  168. apiExits := []exitAPI{}
  169. for i := 0; i < len(dbExits); i++ {
  170. apiExits = append(apiExits, exitAPI{
  171. ItemID: dbExits[i].ItemID,
  172. BatchNum: dbExits[i].BatchNum,
  173. AccountIdx: idxToHez(dbExits[i].AccountIdx, dbExits[i].TokenSymbol),
  174. MerkleProof: dbExits[i].MerkleProof,
  175. Balance: dbExits[i].Balance.String(),
  176. InstantWithdrawn: dbExits[i].InstantWithdrawn,
  177. DelayedWithdrawRequest: dbExits[i].DelayedWithdrawRequest,
  178. DelayedWithdrawn: dbExits[i].DelayedWithdrawn,
  179. Token: tokenAPI{
  180. TokenID: dbExits[i].TokenID,
  181. EthBlockNum: dbExits[i].TokenEthBlockNum,
  182. EthAddr: dbExits[i].TokenEthAddr,
  183. Name: dbExits[i].TokenName,
  184. Symbol: dbExits[i].TokenSymbol,
  185. Decimals: dbExits[i].TokenDecimals,
  186. USD: dbExits[i].TokenUSD,
  187. USDUpdate: dbExits[i].TokenUSDUpdate,
  188. },
  189. })
  190. }
  191. return apiExits
  192. }
  193. // Tokens
  194. type tokensAPI struct {
  195. Tokens []tokenAPI `json:"tokens"`
  196. Pagination *db.Pagination `json:"pagination"`
  197. }
  198. func (t *tokensAPI) GetPagination() *db.Pagination {
  199. if t.Tokens[0].ItemID < t.Tokens[len(t.Tokens)-1].ItemID {
  200. t.Pagination.FirstReturnedItem = t.Tokens[0].ItemID
  201. t.Pagination.LastReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
  202. } else {
  203. t.Pagination.LastReturnedItem = t.Tokens[0].ItemID
  204. t.Pagination.FirstReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
  205. }
  206. return t.Pagination
  207. }
  208. func (t *tokensAPI) Len() int { return len(t.Tokens) }
  209. type tokenAPI struct {
  210. ItemID int `json:"itemId"`
  211. TokenID common.TokenID `json:"id"`
  212. EthBlockNum int64 `json:"ethereumBlockNum"` // Ethereum block number in which this token was registered
  213. EthAddr ethCommon.Address `json:"ethereumAddress"`
  214. Name string `json:"name"`
  215. Symbol string `json:"symbol"`
  216. Decimals uint64 `json:"decimals"`
  217. USD *float64 `json:"USD"`
  218. USDUpdate *time.Time `json:"fiatUpdate"`
  219. }
  220. func tokensToAPI(dbTokens []historydb.TokenRead) []tokenAPI {
  221. apiTokens := []tokenAPI{}
  222. for i := 0; i < len(dbTokens); i++ {
  223. apiTokens = append(apiTokens, tokenAPI{
  224. ItemID: dbTokens[i].ItemID,
  225. TokenID: dbTokens[i].TokenID,
  226. EthBlockNum: dbTokens[i].EthBlockNum,
  227. EthAddr: dbTokens[i].EthAddr,
  228. Name: dbTokens[i].Name,
  229. Symbol: dbTokens[i].Symbol,
  230. Decimals: dbTokens[i].Decimals,
  231. USD: dbTokens[i].USD,
  232. USDUpdate: dbTokens[i].USDUpdate,
  233. })
  234. }
  235. return apiTokens
  236. }
  237. // Config
  238. type rollupConstants struct {
  239. PublicConstants eth.RollupPublicConstants `json:"publicConstants"`
  240. MaxFeeIdxCoordinator int `json:"maxFeeIdxCoordinator"`
  241. ReservedIdx int `json:"reservedIdx"`
  242. ExitIdx int `json:"exitIdx"`
  243. LimitLoadAmount *big.Int `json:"limitLoadAmount"`
  244. LimitL2TransferAmount *big.Int `json:"limitL2TransferAmount"`
  245. LimitTokens int `json:"limitTokens"`
  246. L1CoordinatorTotalBytes int `json:"l1CoordinatorTotalBytes"`
  247. L1UserTotalBytes int `json:"l1UserTotalBytes"`
  248. MaxL1UserTx int `json:"maxL1UserTx"`
  249. MaxL1Tx int `json:"maxL1Tx"`
  250. InputSHAConstantBytes int `json:"inputSHAConstantBytes"`
  251. NumBuckets int `json:"numBuckets"`
  252. MaxWithdrawalDelay int `json:"maxWithdrawalDelay"`
  253. ExchangeMultiplier int `json:"exchangeMultiplier"`
  254. }
  255. type configAPI struct {
  256. RollupConstants rollupConstants `json:"hermez"`
  257. AuctionConstants eth.AuctionConstants `json:"auction"`
  258. WDelayerConstants eth.WDelayerConstants `json:"withdrawalDelayer"`
  259. }
  260. // PoolL2Tx
  261. type receivedPoolTx struct {
  262. TxID common.TxID `json:"id" binding:"required"`
  263. Type common.TxType `json:"type" binding:"required"`
  264. TokenID common.TokenID `json:"tokenId"`
  265. FromIdx string `json:"fromAccountIndex" binding:"required"`
  266. ToIdx *string `json:"toAccountIndex"`
  267. ToEthAddr *string `json:"toHezEthereumAddress"`
  268. ToBJJ *string `json:"toBjj"`
  269. Amount string `json:"amount" binding:"required"`
  270. Fee common.FeeSelector `json:"fee"`
  271. Nonce common.Nonce `json:"nonce"`
  272. Signature babyjub.SignatureComp `json:"signature" binding:"required"`
  273. RqFromIdx *string `json:"requestFromAccountIndex"`
  274. RqToIdx *string `json:"requestToAccountIndex"`
  275. RqToEthAddr *string `json:"requestToHezEthereumAddress"`
  276. RqToBJJ *string `json:"requestToBjj"`
  277. RqTokenID *common.TokenID `json:"requestTokenId"`
  278. RqAmount *string `json:"requestAmount"`
  279. RqFee *common.FeeSelector `json:"requestFee"`
  280. RqNonce *common.Nonce `json:"requestNonce"`
  281. }
  282. func (tx *receivedPoolTx) toDBWritePoolL2Tx() (*l2db.PoolL2TxWrite, error) {
  283. amount := new(big.Int)
  284. amount.SetString(tx.Amount, 10)
  285. txw := &l2db.PoolL2TxWrite{
  286. TxID: tx.TxID,
  287. TokenID: tx.TokenID,
  288. Amount: amount,
  289. Fee: tx.Fee,
  290. Nonce: tx.Nonce,
  291. State: common.PoolL2TxStatePending,
  292. Signature: tx.Signature,
  293. RqTokenID: tx.RqTokenID,
  294. RqFee: tx.RqFee,
  295. RqNonce: tx.RqNonce,
  296. Type: tx.Type,
  297. }
  298. // Check FromIdx (required)
  299. fidx, err := stringToIdx(tx.FromIdx, "fromAccountIndex")
  300. if err != nil {
  301. return nil, err
  302. }
  303. if fidx == nil {
  304. return nil, errors.New("invalid fromAccountIndex")
  305. }
  306. // Set FromIdx
  307. txw.FromIdx = common.Idx(*fidx)
  308. // Set AmountFloat
  309. f := new(big.Float).SetInt(amount)
  310. amountF, _ := f.Float64()
  311. txw.AmountFloat = amountF
  312. if amountF < 0 {
  313. return nil, errors.New("amount must be positive")
  314. }
  315. // Check "to" fields, only one of: ToIdx, ToEthAddr, ToBJJ
  316. if tx.ToIdx != nil { // Case: Tx with ToIdx setted
  317. // Set ToIdx
  318. tidxUint, err := stringToIdx(*tx.ToIdx, "toAccountIndex")
  319. if err != nil || tidxUint == nil {
  320. return nil, errors.New("invalid toAccountIndex")
  321. }
  322. tidx := common.Idx(*tidxUint)
  323. txw.ToIdx = &tidx
  324. } else if tx.ToBJJ != nil { // Case: Tx with ToBJJ setted
  325. // tx.ToEthAddr must be equal to ethAddrWhenBJJLower or ethAddrWhenBJJUpper
  326. if tx.ToEthAddr != nil {
  327. toEthAddr, err := hezStringToEthAddr(*tx.ToEthAddr, "toHezEthereumAddress")
  328. if err != nil || *toEthAddr != common.FFAddr {
  329. return nil, fmt.Errorf("if toBjj is setted, toHezEthereumAddress must be hez:%s", common.FFAddr.Hex())
  330. }
  331. } else {
  332. return nil, fmt.Errorf("if toBjj is setted, toHezEthereumAddress must be hez:%s and toAccountIndex must be null", common.FFAddr.Hex())
  333. }
  334. // Set ToEthAddr and ToBJJ
  335. toBJJ, err := hezStringToBJJ(*tx.ToBJJ, "toBjj")
  336. if err != nil || toBJJ == nil {
  337. return nil, errors.New("invalid toBjj")
  338. }
  339. txw.ToBJJ = toBJJ
  340. txw.ToEthAddr = &common.FFAddr
  341. } else if tx.ToEthAddr != nil { // Case: Tx with ToEthAddr setted
  342. // Set ToEthAddr
  343. toEthAddr, err := hezStringToEthAddr(*tx.ToEthAddr, "toHezEthereumAddress")
  344. if err != nil || toEthAddr == nil {
  345. return nil, errors.New("invalid toHezEthereumAddress")
  346. }
  347. txw.ToEthAddr = toEthAddr
  348. } else {
  349. return nil, errors.New("one of toAccountIndex, toHezEthereumAddress or toBjj must be setted")
  350. }
  351. // Check "rq" fields
  352. if tx.RqFromIdx != nil {
  353. // check and set RqFromIdx
  354. rqfidxUint, err := stringToIdx(tx.FromIdx, "requestFromAccountIndex")
  355. if err != nil || rqfidxUint == nil {
  356. return nil, errors.New("invalid requestFromAccountIndex")
  357. }
  358. // Set RqFromIdx
  359. rqfidx := common.Idx(*rqfidxUint)
  360. txw.RqFromIdx = &rqfidx
  361. // Case: RqTx with RqToIdx setted
  362. if tx.RqToIdx != nil {
  363. // Set ToIdx
  364. tidxUint, err := stringToIdx(*tx.RqToIdx, "requestToAccountIndex")
  365. if err != nil || tidxUint == nil {
  366. return nil, errors.New("invalid requestToAccountIndex")
  367. }
  368. tidx := common.Idx(*tidxUint)
  369. txw.ToIdx = &tidx
  370. } else if tx.RqToBJJ != nil { // Case: Tx with ToBJJ setted
  371. // tx.ToEthAddr must be equal to ethAddrWhenBJJLower or ethAddrWhenBJJUpper
  372. if tx.RqToEthAddr != nil {
  373. rqEthAddr, err := hezStringToEthAddr(*tx.RqToEthAddr, "")
  374. if err != nil || *rqEthAddr != common.FFAddr {
  375. return nil, fmt.Errorf("if requestToBjj is setted, requestToHezEthereumAddress must be hez:%s", common.FFAddr.Hex())
  376. }
  377. } else {
  378. return nil, fmt.Errorf("if requestToBjj is setted, toHezEthereumAddress must be hez:%s and requestToAccountIndex must be null", common.FFAddr.Hex())
  379. }
  380. // Set ToEthAddr and ToBJJ
  381. rqToBJJ, err := hezStringToBJJ(*tx.RqToBJJ, "requestToBjj")
  382. if err != nil || rqToBJJ == nil {
  383. return nil, errors.New("invalid requestToBjj")
  384. }
  385. txw.RqToBJJ = rqToBJJ
  386. txw.RqToEthAddr = &common.FFAddr
  387. } else if tx.RqToEthAddr != nil { // Case: Tx with ToEthAddr setted
  388. // Set ToEthAddr
  389. rqToEthAddr, err := hezStringToEthAddr(*tx.ToEthAddr, "requestToHezEthereumAddress")
  390. if err != nil || rqToEthAddr == nil {
  391. return nil, errors.New("invalid requestToHezEthereumAddress")
  392. }
  393. txw.RqToEthAddr = rqToEthAddr
  394. } else {
  395. return nil, errors.New("one of requestToAccountIndex, requestToHezEthereumAddress or requestToBjj must be setted")
  396. }
  397. if tx.RqAmount == nil {
  398. return nil, errors.New("requestAmount must be provided if other request fields are setted")
  399. }
  400. rqAmount := new(big.Int)
  401. rqAmount.SetString(*tx.RqAmount, 10)
  402. txw.RqAmount = rqAmount
  403. } else if tx.RqToIdx != nil && tx.RqToEthAddr != nil && tx.RqToBJJ != nil &&
  404. tx.RqTokenID != nil && tx.RqAmount != nil && tx.RqNonce != nil && tx.RqFee != nil {
  405. // if tx.RqToIdx is not setted, tx.Rq* must be null as well
  406. return nil, errors.New("if requestFromAccountIndex is setted, the rest of request fields must be null as well")
  407. }
  408. return txw, validatePoolL2TxWrite(txw)
  409. }
  410. func validatePoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
  411. poolTx := common.PoolL2Tx{
  412. TxID: txw.TxID,
  413. FromIdx: txw.FromIdx,
  414. ToBJJ: txw.ToBJJ,
  415. TokenID: txw.TokenID,
  416. Amount: txw.Amount,
  417. Fee: txw.Fee,
  418. Nonce: txw.Nonce,
  419. State: txw.State,
  420. Signature: txw.Signature,
  421. RqToBJJ: txw.RqToBJJ,
  422. RqAmount: txw.RqAmount,
  423. Type: txw.Type,
  424. }
  425. // ToIdx
  426. if txw.ToIdx != nil {
  427. poolTx.ToIdx = *txw.ToIdx
  428. }
  429. // ToEthAddr
  430. if txw.ToEthAddr == nil {
  431. poolTx.ToEthAddr = common.EmptyAddr
  432. } else {
  433. poolTx.ToEthAddr = *txw.ToEthAddr
  434. }
  435. // RqFromIdx
  436. if txw.RqFromIdx != nil {
  437. poolTx.RqFromIdx = *txw.RqFromIdx
  438. }
  439. // RqToIdx
  440. if txw.RqToIdx != nil {
  441. poolTx.RqToIdx = *txw.RqToIdx
  442. }
  443. // RqToEthAddr
  444. if txw.RqToEthAddr == nil {
  445. poolTx.RqToEthAddr = common.EmptyAddr
  446. } else {
  447. poolTx.RqToEthAddr = *txw.RqToEthAddr
  448. }
  449. // RqTokenID
  450. if txw.RqTokenID != nil {
  451. poolTx.RqTokenID = *txw.RqTokenID
  452. }
  453. // RqFee
  454. if txw.RqFee != nil {
  455. poolTx.RqFee = *txw.RqFee
  456. }
  457. // RqNonce
  458. if txw.RqNonce != nil {
  459. poolTx.RqNonce = *txw.RqNonce
  460. }
  461. // Check type and id
  462. _, err := common.NewPoolL2Tx(&poolTx)
  463. if err != nil {
  464. return err
  465. }
  466. // Check signature
  467. // Get public key
  468. account, err := s.GetAccount(poolTx.FromIdx)
  469. if err != nil {
  470. return err
  471. }
  472. if !poolTx.VerifySignature(account.PublicKey) {
  473. return errors.New("wrong signature")
  474. }
  475. return nil
  476. }
  477. type sendPoolTx struct {
  478. TxID common.TxID `json:"id"`
  479. Type common.TxType `json:"type"`
  480. FromIdx string `json:"fromAccountIndex"`
  481. ToIdx *string `json:"toAccountIndex"`
  482. ToEthAddr *string `json:"toHezEthereumAddress"`
  483. ToBJJ *string `json:"toBjj"`
  484. Amount string `json:"amount"`
  485. Fee common.FeeSelector `json:"fee"`
  486. Nonce common.Nonce `json:"nonce"`
  487. State common.PoolL2TxState `json:"state"`
  488. Signature babyjub.SignatureComp `json:"signature"`
  489. Timestamp time.Time `json:"timestamp"`
  490. BatchNum *common.BatchNum `json:"batchNum"`
  491. RqFromIdx *string `json:"requestFromAccountIndex"`
  492. RqToIdx *string `json:"requestToAccountIndex"`
  493. RqToEthAddr *string `json:"requestToHezEthereumAddress"`
  494. RqToBJJ *string `json:"requestToBJJ"`
  495. RqTokenID *common.TokenID `json:"requestTokenId"`
  496. RqAmount *string `json:"requestAmount"`
  497. RqFee *common.FeeSelector `json:"requestFee"`
  498. RqNonce *common.Nonce `json:"requestNonce"`
  499. Token tokenAPI `json:"token"`
  500. }
  501. func poolL2TxReadToSend(dbTx *l2db.PoolL2TxRead) *sendPoolTx {
  502. tx := &sendPoolTx{
  503. TxID: dbTx.TxID,
  504. Type: dbTx.Type,
  505. FromIdx: idxToHez(dbTx.FromIdx, dbTx.TokenSymbol),
  506. Amount: dbTx.Amount.String(),
  507. Fee: dbTx.Fee,
  508. Nonce: dbTx.Nonce,
  509. State: dbTx.State,
  510. Signature: dbTx.Signature,
  511. Timestamp: dbTx.Timestamp,
  512. BatchNum: dbTx.BatchNum,
  513. RqTokenID: dbTx.RqTokenID,
  514. RqFee: dbTx.RqFee,
  515. RqNonce: dbTx.RqNonce,
  516. Token: tokenAPI{
  517. TokenID: dbTx.TokenID,
  518. EthBlockNum: dbTx.TokenEthBlockNum,
  519. EthAddr: dbTx.TokenEthAddr,
  520. Name: dbTx.TokenName,
  521. Symbol: dbTx.TokenSymbol,
  522. Decimals: dbTx.TokenDecimals,
  523. USD: dbTx.TokenUSD,
  524. USDUpdate: dbTx.TokenUSDUpdate,
  525. },
  526. }
  527. // ToIdx
  528. if dbTx.ToIdx != nil {
  529. toIdx := idxToHez(*dbTx.ToIdx, dbTx.TokenSymbol)
  530. tx.ToIdx = &toIdx
  531. }
  532. // ToEthAddr
  533. if dbTx.ToEthAddr != nil {
  534. toEth := ethAddrToHez(*dbTx.ToEthAddr)
  535. tx.ToEthAddr = &toEth
  536. }
  537. // ToBJJ
  538. if dbTx.ToBJJ != nil {
  539. toBJJ := bjjToString(dbTx.ToBJJ)
  540. tx.ToBJJ = &toBJJ
  541. }
  542. // RqFromIdx
  543. if dbTx.RqFromIdx != nil {
  544. rqFromIdx := idxToHez(*dbTx.RqFromIdx, dbTx.TokenSymbol)
  545. tx.RqFromIdx = &rqFromIdx
  546. }
  547. // RqToIdx
  548. if dbTx.RqToIdx != nil {
  549. rqToIdx := idxToHez(*dbTx.RqToIdx, dbTx.TokenSymbol)
  550. tx.RqToIdx = &rqToIdx
  551. }
  552. // RqToEthAddr
  553. if dbTx.RqToEthAddr != nil {
  554. rqToEth := ethAddrToHez(*dbTx.RqToEthAddr)
  555. tx.RqToEthAddr = &rqToEth
  556. }
  557. // RqToBJJ
  558. if dbTx.RqToBJJ != nil {
  559. rqToBJJ := bjjToString(dbTx.RqToBJJ)
  560. tx.RqToBJJ = &rqToBJJ
  561. }
  562. // RqAmount
  563. if dbTx.RqAmount != nil {
  564. rqAmount := dbTx.RqAmount.String()
  565. tx.RqAmount = &rqAmount
  566. }
  567. return tx
  568. }
  569. // Coordinators
  570. type coordinatorAPI struct {
  571. ItemID int `json:"itemId"`
  572. Bidder ethCommon.Address `json:"bidderAddr"`
  573. Forger ethCommon.Address `json:"forgerAddr"`
  574. EthBlockNum int64 `json:"ethereumBlock"`
  575. URL string `json:"URL"`
  576. }
  577. type coordinatorsAPI struct {
  578. Coordinators []coordinatorAPI `json:"coordinators"`
  579. Pagination *db.Pagination `json:"pagination"`
  580. }
  581. func (t *coordinatorsAPI) GetPagination() *db.Pagination {
  582. if t.Coordinators[0].ItemID < t.Coordinators[len(t.Coordinators)-1].ItemID {
  583. t.Pagination.FirstReturnedItem = t.Coordinators[0].ItemID
  584. t.Pagination.LastReturnedItem = t.Coordinators[len(t.Coordinators)-1].ItemID
  585. } else {
  586. t.Pagination.LastReturnedItem = t.Coordinators[0].ItemID
  587. t.Pagination.FirstReturnedItem = t.Coordinators[len(t.Coordinators)-1].ItemID
  588. }
  589. return t.Pagination
  590. }
  591. func (t *coordinatorsAPI) Len() int { return len(t.Coordinators) }
  592. func coordinatorsToAPI(dbCoordinators []historydb.HistoryCoordinator) []coordinatorAPI {
  593. apiCoordinators := []coordinatorAPI{}
  594. for i := 0; i < len(dbCoordinators); i++ {
  595. apiCoordinators = append(apiCoordinators, coordinatorAPI{
  596. ItemID: dbCoordinators[i].ItemID,
  597. Bidder: dbCoordinators[i].Bidder,
  598. Forger: dbCoordinators[i].Forger,
  599. EthBlockNum: dbCoordinators[i].EthBlockNum,
  600. URL: dbCoordinators[i].URL,
  601. })
  602. }
  603. return apiCoordinators
  604. }