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.

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