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