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.

713 lines
23 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 tokenAPI `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: tokenAPI{
  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 tokenAPI `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: tokenAPI{
  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. // Tokens
  219. type tokensAPI struct {
  220. Tokens []tokenAPI `json:"tokens"`
  221. Pagination *db.Pagination `json:"pagination"`
  222. }
  223. func (t *tokensAPI) GetPagination() *db.Pagination {
  224. if t.Tokens[0].ItemID < t.Tokens[len(t.Tokens)-1].ItemID {
  225. t.Pagination.FirstReturnedItem = t.Tokens[0].ItemID
  226. t.Pagination.LastReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
  227. } else {
  228. t.Pagination.LastReturnedItem = t.Tokens[0].ItemID
  229. t.Pagination.FirstReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
  230. }
  231. return t.Pagination
  232. }
  233. func (t *tokensAPI) Len() int { return len(t.Tokens) }
  234. type tokenAPI struct {
  235. ItemID int `json:"itemId"`
  236. TokenID common.TokenID `json:"id"`
  237. EthBlockNum int64 `json:"ethereumBlockNum"` // Ethereum block number in which this token was registered
  238. EthAddr ethCommon.Address `json:"ethereumAddress"`
  239. Name string `json:"name"`
  240. Symbol string `json:"symbol"`
  241. Decimals uint64 `json:"decimals"`
  242. USD *float64 `json:"USD"`
  243. USDUpdate *time.Time `json:"fiatUpdate"`
  244. }
  245. func tokensToAPI(dbTokens []historydb.TokenRead) []tokenAPI {
  246. apiTokens := []tokenAPI{}
  247. for i := 0; i < len(dbTokens); i++ {
  248. apiTokens = append(apiTokens, tokenAPI{
  249. ItemID: dbTokens[i].ItemID,
  250. TokenID: dbTokens[i].TokenID,
  251. EthBlockNum: dbTokens[i].EthBlockNum,
  252. EthAddr: dbTokens[i].EthAddr,
  253. Name: dbTokens[i].Name,
  254. Symbol: dbTokens[i].Symbol,
  255. Decimals: dbTokens[i].Decimals,
  256. USD: dbTokens[i].USD,
  257. USDUpdate: dbTokens[i].USDUpdate,
  258. })
  259. }
  260. return apiTokens
  261. }
  262. // Config
  263. type rollupConstants struct {
  264. PublicConstants eth.RollupPublicConstants `json:"publicConstants"`
  265. MaxFeeIdxCoordinator int `json:"maxFeeIdxCoordinator"`
  266. ReservedIdx int `json:"reservedIdx"`
  267. ExitIdx int `json:"exitIdx"`
  268. LimitLoadAmount *big.Int `json:"limitLoadAmount"`
  269. LimitL2TransferAmount *big.Int `json:"limitL2TransferAmount"`
  270. LimitTokens int `json:"limitTokens"`
  271. L1CoordinatorTotalBytes int `json:"l1CoordinatorTotalBytes"`
  272. L1UserTotalBytes int `json:"l1UserTotalBytes"`
  273. MaxL1UserTx int `json:"maxL1UserTx"`
  274. MaxL1Tx int `json:"maxL1Tx"`
  275. InputSHAConstantBytes int `json:"inputSHAConstantBytes"`
  276. NumBuckets int `json:"numBuckets"`
  277. MaxWithdrawalDelay int `json:"maxWithdrawalDelay"`
  278. ExchangeMultiplier int `json:"exchangeMultiplier"`
  279. }
  280. type configAPI struct {
  281. RollupConstants rollupConstants `json:"hermez"`
  282. AuctionConstants eth.AuctionConstants `json:"auction"`
  283. WDelayerConstants eth.WDelayerConstants `json:"withdrawalDelayer"`
  284. }
  285. // PoolL2Tx
  286. type receivedPoolTx struct {
  287. TxID common.TxID `json:"id" binding:"required"`
  288. Type common.TxType `json:"type" binding:"required"`
  289. TokenID common.TokenID `json:"tokenId"`
  290. FromIdx string `json:"fromAccountIndex" binding:"required"`
  291. ToIdx *string `json:"toAccountIndex"`
  292. ToEthAddr *string `json:"toHezEthereumAddress"`
  293. ToBJJ *string `json:"toBjj"`
  294. Amount string `json:"amount" binding:"required"`
  295. Fee common.FeeSelector `json:"fee"`
  296. Nonce common.Nonce `json:"nonce"`
  297. Signature babyjub.SignatureComp `json:"signature" binding:"required"`
  298. RqFromIdx *string `json:"requestFromAccountIndex"`
  299. RqToIdx *string `json:"requestToAccountIndex"`
  300. RqToEthAddr *string `json:"requestToHezEthereumAddress"`
  301. RqToBJJ *string `json:"requestToBjj"`
  302. RqTokenID *common.TokenID `json:"requestTokenId"`
  303. RqAmount *string `json:"requestAmount"`
  304. RqFee *common.FeeSelector `json:"requestFee"`
  305. RqNonce *common.Nonce `json:"requestNonce"`
  306. }
  307. func (tx *receivedPoolTx) toDBWritePoolL2Tx() (*l2db.PoolL2TxWrite, error) {
  308. amount := new(big.Int)
  309. amount.SetString(tx.Amount, 10)
  310. txw := &l2db.PoolL2TxWrite{
  311. TxID: tx.TxID,
  312. TokenID: tx.TokenID,
  313. Amount: amount,
  314. Fee: tx.Fee,
  315. Nonce: tx.Nonce,
  316. State: common.PoolL2TxStatePending,
  317. Signature: tx.Signature,
  318. RqTokenID: tx.RqTokenID,
  319. RqFee: tx.RqFee,
  320. RqNonce: tx.RqNonce,
  321. Type: tx.Type,
  322. }
  323. // Check FromIdx (required)
  324. fidx, err := stringToIdx(tx.FromIdx, "fromAccountIndex")
  325. if err != nil {
  326. return nil, err
  327. }
  328. if fidx == nil {
  329. return nil, errors.New("invalid fromAccountIndex")
  330. }
  331. // Set FromIdx
  332. txw.FromIdx = common.Idx(*fidx)
  333. // Set AmountFloat
  334. f := new(big.Float).SetInt(amount)
  335. amountF, _ := f.Float64()
  336. txw.AmountFloat = amountF
  337. if amountF < 0 {
  338. return nil, errors.New("amount must be positive")
  339. }
  340. // Check "to" fields, only one of: ToIdx, ToEthAddr, ToBJJ
  341. if tx.ToIdx != nil { // Case: Tx with ToIdx setted
  342. // Set ToIdx
  343. tidxUint, err := stringToIdx(*tx.ToIdx, "toAccountIndex")
  344. if err != nil || tidxUint == nil {
  345. return nil, errors.New("invalid toAccountIndex")
  346. }
  347. tidx := common.Idx(*tidxUint)
  348. txw.ToIdx = &tidx
  349. } else if tx.ToBJJ != nil { // Case: Tx with ToBJJ setted
  350. // tx.ToEthAddr must be equal to ethAddrWhenBJJLower or ethAddrWhenBJJUpper
  351. if tx.ToEthAddr != nil {
  352. toEthAddr, err := hezStringToEthAddr(*tx.ToEthAddr, "toHezEthereumAddress")
  353. if err != nil || *toEthAddr != common.FFAddr {
  354. return nil, fmt.Errorf("if toBjj is setted, toHezEthereumAddress must be hez:%s", common.FFAddr.Hex())
  355. }
  356. } else {
  357. return nil, fmt.Errorf("if toBjj is setted, toHezEthereumAddress must be hez:%s and toAccountIndex must be null", common.FFAddr.Hex())
  358. }
  359. // Set ToEthAddr and ToBJJ
  360. toBJJ, err := hezStringToBJJ(*tx.ToBJJ, "toBjj")
  361. if err != nil || toBJJ == nil {
  362. return nil, errors.New("invalid toBjj")
  363. }
  364. txw.ToBJJ = toBJJ
  365. txw.ToEthAddr = &common.FFAddr
  366. } else if tx.ToEthAddr != nil { // Case: Tx with ToEthAddr setted
  367. // Set ToEthAddr
  368. toEthAddr, err := hezStringToEthAddr(*tx.ToEthAddr, "toHezEthereumAddress")
  369. if err != nil || toEthAddr == nil {
  370. return nil, errors.New("invalid toHezEthereumAddress")
  371. }
  372. txw.ToEthAddr = toEthAddr
  373. } else {
  374. return nil, errors.New("one of toAccountIndex, toHezEthereumAddress or toBjj must be setted")
  375. }
  376. // Check "rq" fields
  377. if tx.RqFromIdx != nil {
  378. // check and set RqFromIdx
  379. rqfidxUint, err := stringToIdx(tx.FromIdx, "requestFromAccountIndex")
  380. if err != nil || rqfidxUint == nil {
  381. return nil, errors.New("invalid requestFromAccountIndex")
  382. }
  383. // Set RqFromIdx
  384. rqfidx := common.Idx(*rqfidxUint)
  385. txw.RqFromIdx = &rqfidx
  386. // Case: RqTx with RqToIdx setted
  387. if tx.RqToIdx != nil {
  388. // Set ToIdx
  389. tidxUint, err := stringToIdx(*tx.RqToIdx, "requestToAccountIndex")
  390. if err != nil || tidxUint == nil {
  391. return nil, errors.New("invalid requestToAccountIndex")
  392. }
  393. tidx := common.Idx(*tidxUint)
  394. txw.ToIdx = &tidx
  395. } else if tx.RqToBJJ != nil { // Case: Tx with ToBJJ setted
  396. // tx.ToEthAddr must be equal to ethAddrWhenBJJLower or ethAddrWhenBJJUpper
  397. if tx.RqToEthAddr != nil {
  398. rqEthAddr, err := hezStringToEthAddr(*tx.RqToEthAddr, "")
  399. if err != nil || *rqEthAddr != common.FFAddr {
  400. return nil, fmt.Errorf("if requestToBjj is setted, requestToHezEthereumAddress must be hez:%s", common.FFAddr.Hex())
  401. }
  402. } else {
  403. return nil, fmt.Errorf("if requestToBjj is setted, toHezEthereumAddress must be hez:%s and requestToAccountIndex must be null", common.FFAddr.Hex())
  404. }
  405. // Set ToEthAddr and ToBJJ
  406. rqToBJJ, err := hezStringToBJJ(*tx.RqToBJJ, "requestToBjj")
  407. if err != nil || rqToBJJ == nil {
  408. return nil, errors.New("invalid requestToBjj")
  409. }
  410. txw.RqToBJJ = rqToBJJ
  411. txw.RqToEthAddr = &common.FFAddr
  412. } else if tx.RqToEthAddr != nil { // Case: Tx with ToEthAddr setted
  413. // Set ToEthAddr
  414. rqToEthAddr, err := hezStringToEthAddr(*tx.ToEthAddr, "requestToHezEthereumAddress")
  415. if err != nil || rqToEthAddr == nil {
  416. return nil, errors.New("invalid requestToHezEthereumAddress")
  417. }
  418. txw.RqToEthAddr = rqToEthAddr
  419. } else {
  420. return nil, errors.New("one of requestToAccountIndex, requestToHezEthereumAddress or requestToBjj must be setted")
  421. }
  422. if tx.RqAmount == nil {
  423. return nil, errors.New("requestAmount must be provided if other request fields are setted")
  424. }
  425. rqAmount := new(big.Int)
  426. rqAmount.SetString(*tx.RqAmount, 10)
  427. txw.RqAmount = rqAmount
  428. } else if tx.RqToIdx != nil && tx.RqToEthAddr != nil && tx.RqToBJJ != nil &&
  429. tx.RqTokenID != nil && tx.RqAmount != nil && tx.RqNonce != nil && tx.RqFee != nil {
  430. // if tx.RqToIdx is not setted, tx.Rq* must be null as well
  431. return nil, errors.New("if requestFromAccountIndex is setted, the rest of request fields must be null as well")
  432. }
  433. return txw, validatePoolL2TxWrite(txw)
  434. }
  435. func validatePoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
  436. poolTx := common.PoolL2Tx{
  437. TxID: txw.TxID,
  438. FromIdx: txw.FromIdx,
  439. ToBJJ: txw.ToBJJ,
  440. TokenID: txw.TokenID,
  441. Amount: txw.Amount,
  442. Fee: txw.Fee,
  443. Nonce: txw.Nonce,
  444. State: txw.State,
  445. Signature: txw.Signature,
  446. RqToBJJ: txw.RqToBJJ,
  447. RqAmount: txw.RqAmount,
  448. Type: txw.Type,
  449. }
  450. // ToIdx
  451. if txw.ToIdx != nil {
  452. poolTx.ToIdx = *txw.ToIdx
  453. }
  454. // ToEthAddr
  455. if txw.ToEthAddr == nil {
  456. poolTx.ToEthAddr = common.EmptyAddr
  457. } else {
  458. poolTx.ToEthAddr = *txw.ToEthAddr
  459. }
  460. // RqFromIdx
  461. if txw.RqFromIdx != nil {
  462. poolTx.RqFromIdx = *txw.RqFromIdx
  463. }
  464. // RqToIdx
  465. if txw.RqToIdx != nil {
  466. poolTx.RqToIdx = *txw.RqToIdx
  467. }
  468. // RqToEthAddr
  469. if txw.RqToEthAddr == nil {
  470. poolTx.RqToEthAddr = common.EmptyAddr
  471. } else {
  472. poolTx.RqToEthAddr = *txw.RqToEthAddr
  473. }
  474. // RqTokenID
  475. if txw.RqTokenID != nil {
  476. poolTx.RqTokenID = *txw.RqTokenID
  477. }
  478. // RqFee
  479. if txw.RqFee != nil {
  480. poolTx.RqFee = *txw.RqFee
  481. }
  482. // RqNonce
  483. if txw.RqNonce != nil {
  484. poolTx.RqNonce = *txw.RqNonce
  485. }
  486. // Check type and id
  487. _, err := common.NewPoolL2Tx(&poolTx)
  488. if err != nil {
  489. return err
  490. }
  491. // Check signature
  492. // Get public key
  493. account, err := s.GetAccount(poolTx.FromIdx)
  494. if err != nil {
  495. return err
  496. }
  497. if !poolTx.VerifySignature(account.PublicKey) {
  498. return errors.New("wrong signature")
  499. }
  500. return nil
  501. }
  502. type sendPoolTx struct {
  503. TxID common.TxID `json:"id"`
  504. Type common.TxType `json:"type"`
  505. FromIdx string `json:"fromAccountIndex"`
  506. ToIdx *string `json:"toAccountIndex"`
  507. ToEthAddr *string `json:"toHezEthereumAddress"`
  508. ToBJJ *string `json:"toBjj"`
  509. Amount string `json:"amount"`
  510. Fee common.FeeSelector `json:"fee"`
  511. Nonce common.Nonce `json:"nonce"`
  512. State common.PoolL2TxState `json:"state"`
  513. Signature babyjub.SignatureComp `json:"signature"`
  514. Timestamp time.Time `json:"timestamp"`
  515. BatchNum *common.BatchNum `json:"batchNum"`
  516. RqFromIdx *string `json:"requestFromAccountIndex"`
  517. RqToIdx *string `json:"requestToAccountIndex"`
  518. RqToEthAddr *string `json:"requestToHezEthereumAddress"`
  519. RqToBJJ *string `json:"requestToBJJ"`
  520. RqTokenID *common.TokenID `json:"requestTokenId"`
  521. RqAmount *string `json:"requestAmount"`
  522. RqFee *common.FeeSelector `json:"requestFee"`
  523. RqNonce *common.Nonce `json:"requestNonce"`
  524. Token tokenAPI `json:"token"`
  525. }
  526. func poolL2TxReadToSend(dbTx *l2db.PoolL2TxRead) *sendPoolTx {
  527. tx := &sendPoolTx{
  528. TxID: dbTx.TxID,
  529. Type: dbTx.Type,
  530. FromIdx: idxToHez(dbTx.FromIdx, dbTx.TokenSymbol),
  531. Amount: dbTx.Amount.String(),
  532. Fee: dbTx.Fee,
  533. Nonce: dbTx.Nonce,
  534. State: dbTx.State,
  535. Signature: dbTx.Signature,
  536. Timestamp: dbTx.Timestamp,
  537. BatchNum: dbTx.BatchNum,
  538. RqTokenID: dbTx.RqTokenID,
  539. RqFee: dbTx.RqFee,
  540. RqNonce: dbTx.RqNonce,
  541. Token: tokenAPI{
  542. TokenID: dbTx.TokenID,
  543. EthBlockNum: dbTx.TokenEthBlockNum,
  544. EthAddr: dbTx.TokenEthAddr,
  545. Name: dbTx.TokenName,
  546. Symbol: dbTx.TokenSymbol,
  547. Decimals: dbTx.TokenDecimals,
  548. USD: dbTx.TokenUSD,
  549. USDUpdate: dbTx.TokenUSDUpdate,
  550. },
  551. }
  552. // ToIdx
  553. if dbTx.ToIdx != nil {
  554. toIdx := idxToHez(*dbTx.ToIdx, dbTx.TokenSymbol)
  555. tx.ToIdx = &toIdx
  556. }
  557. // ToEthAddr
  558. if dbTx.ToEthAddr != nil {
  559. toEth := ethAddrToHez(*dbTx.ToEthAddr)
  560. tx.ToEthAddr = &toEth
  561. }
  562. // ToBJJ
  563. if dbTx.ToBJJ != nil {
  564. toBJJ := bjjToString(dbTx.ToBJJ)
  565. tx.ToBJJ = &toBJJ
  566. }
  567. // RqFromIdx
  568. if dbTx.RqFromIdx != nil {
  569. rqFromIdx := idxToHez(*dbTx.RqFromIdx, dbTx.TokenSymbol)
  570. tx.RqFromIdx = &rqFromIdx
  571. }
  572. // RqToIdx
  573. if dbTx.RqToIdx != nil {
  574. rqToIdx := idxToHez(*dbTx.RqToIdx, dbTx.TokenSymbol)
  575. tx.RqToIdx = &rqToIdx
  576. }
  577. // RqToEthAddr
  578. if dbTx.RqToEthAddr != nil {
  579. rqToEth := ethAddrToHez(*dbTx.RqToEthAddr)
  580. tx.RqToEthAddr = &rqToEth
  581. }
  582. // RqToBJJ
  583. if dbTx.RqToBJJ != nil {
  584. rqToBJJ := bjjToString(dbTx.RqToBJJ)
  585. tx.RqToBJJ = &rqToBJJ
  586. }
  587. // RqAmount
  588. if dbTx.RqAmount != nil {
  589. rqAmount := dbTx.RqAmount.String()
  590. tx.RqAmount = &rqAmount
  591. }
  592. return tx
  593. }
  594. // Coordinators
  595. type coordinatorAPI struct {
  596. ItemID int `json:"itemId"`
  597. Bidder ethCommon.Address `json:"bidderAddr"`
  598. Forger ethCommon.Address `json:"forgerAddr"`
  599. EthBlockNum int64 `json:"ethereumBlock"`
  600. URL string `json:"URL"`
  601. }
  602. type coordinatorsAPI struct {
  603. Coordinators []coordinatorAPI `json:"coordinators"`
  604. Pagination *db.Pagination `json:"pagination"`
  605. }
  606. func (t *coordinatorsAPI) GetPagination() *db.Pagination {
  607. if t.Coordinators[0].ItemID < t.Coordinators[len(t.Coordinators)-1].ItemID {
  608. t.Pagination.FirstReturnedItem = t.Coordinators[0].ItemID
  609. t.Pagination.LastReturnedItem = t.Coordinators[len(t.Coordinators)-1].ItemID
  610. } else {
  611. t.Pagination.LastReturnedItem = t.Coordinators[0].ItemID
  612. t.Pagination.FirstReturnedItem = t.Coordinators[len(t.Coordinators)-1].ItemID
  613. }
  614. return t.Pagination
  615. }
  616. func (t *coordinatorsAPI) Len() int { return len(t.Coordinators) }
  617. func coordinatorsToAPI(dbCoordinators []historydb.HistoryCoordinator) []coordinatorAPI {
  618. apiCoordinators := []coordinatorAPI{}
  619. for i := 0; i < len(dbCoordinators); i++ {
  620. apiCoordinators = append(apiCoordinators, coordinatorAPI{
  621. ItemID: dbCoordinators[i].ItemID,
  622. Bidder: dbCoordinators[i].Bidder,
  623. Forger: dbCoordinators[i].Forger,
  624. EthBlockNum: dbCoordinators[i].EthBlockNum,
  625. URL: dbCoordinators[i].URL,
  626. })
  627. }
  628. return apiCoordinators
  629. }
  630. // AccountCreationAuth
  631. type accountCreationAuthAPI struct {
  632. EthAddr string `json:"hezEthereumAddress" binding:"required"`
  633. BJJ string `json:"bjj" binding:"required"`
  634. Signature string `json:"signature" binding:"required"`
  635. Timestamp time.Time `json:"timestamp"`
  636. }
  637. func accountCreationAuthToAPI(dbAuth *common.AccountCreationAuth) *accountCreationAuthAPI {
  638. return &accountCreationAuthAPI{
  639. EthAddr: ethAddrToHez(dbAuth.EthAddr),
  640. BJJ: bjjToString(dbAuth.BJJ),
  641. Signature: "0x" + hex.EncodeToString(dbAuth.Signature),
  642. Timestamp: dbAuth.Timestamp,
  643. }
  644. }
  645. func accountCreationAuthAPIToCommon(apiAuth *accountCreationAuthAPI) (*common.AccountCreationAuth, error) {
  646. ethAddr, err := hezStringToEthAddr(apiAuth.EthAddr, "hezEthereumAddress")
  647. if err != nil {
  648. return nil, err
  649. }
  650. bjj, err := hezStringToBJJ(apiAuth.BJJ, "bjj")
  651. if err != nil {
  652. return nil, err
  653. }
  654. without0x := strings.TrimPrefix(apiAuth.Signature, "0x")
  655. s, err := hex.DecodeString(without0x)
  656. if err != nil {
  657. return nil, err
  658. }
  659. auth := &common.AccountCreationAuth{
  660. EthAddr: *ethAddr,
  661. BJJ: bjj,
  662. Signature: s,
  663. Timestamp: apiAuth.Timestamp,
  664. }
  665. if !auth.VerifySignature() {
  666. return nil, errors.New("invalid signature")
  667. }
  668. return auth, nil
  669. }