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