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