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