arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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// AccountCreationAuth
582
583type accountCreationAuthAPI struct {
584	EthAddr   string    `json:"hezEthereumAddress" binding:"required"`
585	BJJ       string    `json:"bjj" binding:"required"`
586	Signature string    `json:"signature" binding:"required"`
587	Timestamp time.Time `json:"timestamp"`
588}
589
590func accountCreationAuthToAPI(dbAuth *common.AccountCreationAuth) *accountCreationAuthAPI {
591	return &accountCreationAuthAPI{
592		EthAddr:   ethAddrToHez(dbAuth.EthAddr),
593		BJJ:       bjjToString(dbAuth.BJJ),
594		Signature: "0x" + hex.EncodeToString(dbAuth.Signature),
595		Timestamp: dbAuth.Timestamp,
596	}
597}
598
599func accountCreationAuthAPIToCommon(apiAuth *accountCreationAuthAPI) (*common.AccountCreationAuth, error) {
600	ethAddr, err := hezStringToEthAddr(apiAuth.EthAddr, "hezEthereumAddress")
601	if err != nil {
602		return nil, err
603	}
604	bjj, err := hezStringToBJJ(apiAuth.BJJ, "bjj")
605	if err != nil {
606		return nil, err
607	}
608	without0x := strings.TrimPrefix(apiAuth.Signature, "0x")
609	s, err := hex.DecodeString(without0x)
610	if err != nil {
611		return nil, err
612	}
613	auth := &common.AccountCreationAuth{
614		EthAddr:   *ethAddr,
615		BJJ:       bjj,
616		Signature: s,
617		Timestamp: apiAuth.Timestamp,
618	}
619	if !auth.VerifySignature() {
620		return nil, errors.New("invalid signature")
621	}
622	return auth, nil
623}