You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

278 lines
9.6 KiB

package api
import (
"encoding/base64"
"math/big"
"strconv"
"time"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/db/historydb"
"github.com/hermeznetwork/hermez-node/eth"
"github.com/iden3/go-iden3-crypto/babyjub"
"github.com/iden3/go-merkletree"
)
type errorMsg struct {
Message string
}
func bjjToString(bjj *babyjub.PublicKey) string {
pkComp := [32]byte(bjj.Compress())
sum := pkComp[0]
for i := 1; i < len(pkComp); i++ {
sum += pkComp[i]
}
bjjSum := append(pkComp[:], sum)
return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
}
func ethAddrToHez(addr ethCommon.Address) string {
return "hez:" + addr.String()
}
func idxToHez(idx common.Idx, tokenSymbol string) string {
return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
}
// History Tx
type historyTxsAPI struct {
Txs []historyTxAPI `json:"transactions"`
Pagination *db.Pagination `json:"pagination"`
}
func (htx *historyTxsAPI) GetPagination() *db.Pagination {
if htx.Txs[0].ItemID < htx.Txs[len(htx.Txs)-1].ItemID {
htx.Pagination.FirstReturnedItem = htx.Txs[0].ItemID
htx.Pagination.LastReturnedItem = htx.Txs[len(htx.Txs)-1].ItemID
} else {
htx.Pagination.LastReturnedItem = htx.Txs[0].ItemID
htx.Pagination.FirstReturnedItem = htx.Txs[len(htx.Txs)-1].ItemID
}
return htx.Pagination
}
func (htx *historyTxsAPI) Len() int { return len(htx.Txs) }
type l1Info struct {
ToForgeL1TxsNum *int64 `json:"toForgeL1TransactionsNum"`
UserOrigin bool `json:"userOrigin"`
FromEthAddr string `json:"fromHezEthereumAddress"`
FromBJJ string `json:"fromBJJ"`
LoadAmount string `json:"loadAmount"`
HistoricLoadAmountUSD *float64 `json:"historicLoadAmountUSD"`
EthBlockNum int64 `json:"ethereumBlockNum"`
}
type l2Info struct {
Fee common.FeeSelector `json:"fee"`
HistoricFeeUSD *float64 `json:"historicFeeUSD"`
Nonce common.Nonce `json:"nonce"`
}
type historyTxAPI struct {
IsL1 string `json:"L1orL2"`
TxID string `json:"id"`
ItemID int `json:"itemId"`
Type common.TxType `json:"type"`
Position int `json:"position"`
FromIdx *string `json:"fromAccountIndex"`
ToIdx string `json:"toAccountIndex"`
Amount string `json:"amount"`
BatchNum *common.BatchNum `json:"batchNum"`
HistoricUSD *float64 `json:"historicUSD"`
Timestamp time.Time `json:"timestamp"`
L1Info *l1Info `json:"L1Info"`
L2Info *l2Info `json:"L2Info"`
Token tokenAPI `json:"token"`
}
func historyTxsToAPI(dbTxs []historydb.HistoryTx) []historyTxAPI {
apiTxs := []historyTxAPI{}
for i := 0; i < len(dbTxs); i++ {
apiTx := historyTxAPI{
TxID: dbTxs[i].TxID.String(),
ItemID: dbTxs[i].ItemID,
Type: dbTxs[i].Type,
Position: dbTxs[i].Position,
ToIdx: idxToHez(dbTxs[i].ToIdx, dbTxs[i].TokenSymbol),
Amount: dbTxs[i].Amount.String(),
HistoricUSD: dbTxs[i].HistoricUSD,
BatchNum: dbTxs[i].BatchNum,
Timestamp: dbTxs[i].Timestamp,
Token: tokenAPI{
TokenID: dbTxs[i].TokenID,
EthBlockNum: dbTxs[i].TokenEthBlockNum,
EthAddr: dbTxs[i].TokenEthAddr,
Name: dbTxs[i].TokenName,
Symbol: dbTxs[i].TokenSymbol,
Decimals: dbTxs[i].TokenDecimals,
USD: dbTxs[i].TokenUSD,
USDUpdate: dbTxs[i].TokenUSDUpdate,
},
L1Info: nil,
L2Info: nil,
}
if dbTxs[i].FromIdx != nil {
fromIdx := new(string)
*fromIdx = idxToHez(*dbTxs[i].FromIdx, dbTxs[i].TokenSymbol)
apiTx.FromIdx = fromIdx
}
if dbTxs[i].IsL1 {
apiTx.IsL1 = "L1"
apiTx.L1Info = &l1Info{
ToForgeL1TxsNum: dbTxs[i].ToForgeL1TxsNum,
UserOrigin: *dbTxs[i].UserOrigin,
FromEthAddr: ethAddrToHez(*dbTxs[i].FromEthAddr),
FromBJJ: bjjToString(dbTxs[i].FromBJJ),
LoadAmount: dbTxs[i].LoadAmount.String(),
HistoricLoadAmountUSD: dbTxs[i].HistoricLoadAmountUSD,
EthBlockNum: dbTxs[i].EthBlockNum,
}
} else {
apiTx.IsL1 = "L2"
apiTx.L2Info = &l2Info{
Fee: *dbTxs[i].Fee,
HistoricFeeUSD: dbTxs[i].HistoricFeeUSD,
Nonce: *dbTxs[i].Nonce,
}
}
apiTxs = append(apiTxs, apiTx)
}
return apiTxs
}
// Exit
type exitsAPI struct {
Exits []exitAPI `json:"exits"`
Pagination *db.Pagination `json:"pagination"`
}
func (e *exitsAPI) GetPagination() *db.Pagination {
if e.Exits[0].ItemID < e.Exits[len(e.Exits)-1].ItemID {
e.Pagination.FirstReturnedItem = e.Exits[0].ItemID
e.Pagination.LastReturnedItem = e.Exits[len(e.Exits)-1].ItemID
} else {
e.Pagination.LastReturnedItem = e.Exits[0].ItemID
e.Pagination.FirstReturnedItem = e.Exits[len(e.Exits)-1].ItemID
}
return e.Pagination
}
func (e *exitsAPI) Len() int { return len(e.Exits) }
type exitAPI struct {
ItemID int `json:"itemId"`
BatchNum common.BatchNum `json:"batchNum"`
AccountIdx string `json:"accountIndex"`
MerkleProof *merkletree.CircomVerifierProof `json:"merkleProof"`
Balance string `json:"balance"`
InstantWithdrawn *int64 `json:"instantWithdrawn"`
DelayedWithdrawRequest *int64 `json:"delayedWithdrawRequest"`
DelayedWithdrawn *int64 `json:"delayedWithdrawn"`
Token tokenAPI `json:"token"`
}
func historyExitsToAPI(dbExits []historydb.HistoryExit) []exitAPI {
apiExits := []exitAPI{}
for i := 0; i < len(dbExits); i++ {
apiExits = append(apiExits, exitAPI{
ItemID: dbExits[i].ItemID,
BatchNum: dbExits[i].BatchNum,
AccountIdx: idxToHez(dbExits[i].AccountIdx, dbExits[i].TokenSymbol),
MerkleProof: dbExits[i].MerkleProof,
Balance: dbExits[i].Balance.String(),
InstantWithdrawn: dbExits[i].InstantWithdrawn,
DelayedWithdrawRequest: dbExits[i].DelayedWithdrawRequest,
DelayedWithdrawn: dbExits[i].DelayedWithdrawn,
Token: tokenAPI{
TokenID: dbExits[i].TokenID,
EthBlockNum: dbExits[i].TokenEthBlockNum,
EthAddr: dbExits[i].TokenEthAddr,
Name: dbExits[i].TokenName,
Symbol: dbExits[i].TokenSymbol,
Decimals: dbExits[i].TokenDecimals,
USD: dbExits[i].TokenUSD,
USDUpdate: dbExits[i].TokenUSDUpdate,
},
})
}
return apiExits
}
// Tokens
type tokensAPI struct {
Tokens []tokenAPI `json:"tokens"`
Pagination *db.Pagination `json:"pagination"`
}
func (t *tokensAPI) GetPagination() *db.Pagination {
if t.Tokens[0].ItemID < t.Tokens[len(t.Tokens)-1].ItemID {
t.Pagination.FirstReturnedItem = t.Tokens[0].ItemID
t.Pagination.LastReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
} else {
t.Pagination.LastReturnedItem = t.Tokens[0].ItemID
t.Pagination.FirstReturnedItem = t.Tokens[len(t.Tokens)-1].ItemID
}
return t.Pagination
}
func (t *tokensAPI) Len() int { return len(t.Tokens) }
type tokenAPI struct {
ItemID int `json:"itemId"`
TokenID common.TokenID `json:"id"`
EthBlockNum int64 `json:"ethereumBlockNum"` // Ethereum block number in which this token was registered
EthAddr ethCommon.Address `json:"ethereumAddress"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint64 `json:"decimals"`
USD *float64 `json:"USD"`
USDUpdate *time.Time `json:"fiatUpdate"`
}
func tokensToAPI(dbTokens []historydb.TokenRead) []tokenAPI {
apiTokens := []tokenAPI{}
for i := 0; i < len(dbTokens); i++ {
apiTokens = append(apiTokens, tokenAPI{
ItemID: dbTokens[i].ItemID,
TokenID: dbTokens[i].TokenID,
EthBlockNum: dbTokens[i].EthBlockNum,
EthAddr: dbTokens[i].EthAddr,
Name: dbTokens[i].Name,
Symbol: dbTokens[i].Symbol,
Decimals: dbTokens[i].Decimals,
USD: dbTokens[i].USD,
USDUpdate: dbTokens[i].USDUpdate,
})
}
return apiTokens
}
// Config
type rollupConstants struct {
PublicConstants eth.RollupPublicConstants `json:"publicConstants"`
MaxFeeIdxCoordinator int `json:"maxFeeIdxCoordinator"`
ReservedIdx int `json:"reservedIdx"`
ExitIdx int `json:"exitIdx"`
LimitLoadAmount *big.Int `json:"limitLoadAmount"`
LimitL2TransferAmount *big.Int `json:"limitL2TransferAmount"`
LimitTokens int `json:"limitTokens"`
L1CoordinatorTotalBytes int `json:"l1CoordinatorTotalBytes"`
L1UserTotalBytes int `json:"l1UserTotalBytes"`
MaxL1UserTx int `json:"maxL1UserTx"`
MaxL1Tx int `json:"maxL1Tx"`
InputSHAConstantBytes int `json:"inputSHAConstantBytes"`
NumBuckets int `json:"numBuckets"`
MaxWithdrawalDelay int `json:"maxWithdrawalDelay"`
ExchangeMultiplier int `json:"exchangeMultiplier"`
}
type configAPI struct {
RollupConstants rollupConstants `json:"hermez"`
AuctionConstants eth.AuctionConstants `json:"auction"`
WDelayerConstants eth.WDelayerConstants `json:"withdrawalDelayer"`
}