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