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.

665 lines
22 KiB

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