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.
 
 
 

198 lines
6.4 KiB

package api
import (
"encoding/base64"
"encoding/hex"
"errors"
"math/big"
"strconv"
"strings"
"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"
)
const exitIdx = "hez:EXIT:1"
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 {
if idx == 1 {
return exitIdx
}
return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
}
// 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 merkleProofAPI struct {
Root string
Siblings []string
OldKey string
OldValue string
IsOld0 bool
Key string
Value string
Fnc int
}
type exitAPI struct {
ItemID int `json:"itemId"`
BatchNum common.BatchNum `json:"batchNum"`
AccountIdx string `json:"accountIndex"`
MerkleProof merkleProofAPI `json:"merkleProof"`
Balance string `json:"balance"`
InstantWithdrawn *int64 `json:"instantWithdrawn"`
DelayedWithdrawRequest *int64 `json:"delayedWithdrawRequest"`
DelayedWithdrawn *int64 `json:"delayedWithdrawn"`
Token historydb.TokenWithUSD `json:"token"`
}
func historyExitsToAPI(dbExits []historydb.HistoryExit) []exitAPI {
apiExits := []exitAPI{}
for i := 0; i < len(dbExits); i++ {
exit := exitAPI{
ItemID: dbExits[i].ItemID,
BatchNum: dbExits[i].BatchNum,
AccountIdx: idxToHez(dbExits[i].AccountIdx, dbExits[i].TokenSymbol),
MerkleProof: merkleProofAPI{
Root: dbExits[i].MerkleProof.Root.String(),
OldKey: dbExits[i].MerkleProof.OldKey.String(),
OldValue: dbExits[i].MerkleProof.OldValue.String(),
IsOld0: dbExits[i].MerkleProof.IsOld0,
Key: dbExits[i].MerkleProof.Key.String(),
Value: dbExits[i].MerkleProof.Value.String(),
Fnc: dbExits[i].MerkleProof.Fnc,
},
Balance: dbExits[i].Balance.String(),
InstantWithdrawn: dbExits[i].InstantWithdrawn,
DelayedWithdrawRequest: dbExits[i].DelayedWithdrawRequest,
DelayedWithdrawn: dbExits[i].DelayedWithdrawn,
Token: historydb.TokenWithUSD{
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,
},
}
siblings := []string{}
for j := 0; j < len(dbExits[i].MerkleProof.Siblings); j++ {
siblings = append(siblings, dbExits[i].MerkleProof.Siblings[j].String())
}
exit.MerkleProof.Siblings = siblings
apiExits = append(apiExits, exit)
}
return apiExits
}
// 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"`
}
// AccountCreationAuth
type accountCreationAuthAPI struct {
EthAddr string `json:"hezEthereumAddress" binding:"required"`
BJJ string `json:"bjj" binding:"required"`
Signature string `json:"signature" binding:"required"`
Timestamp time.Time `json:"timestamp"`
}
func accountCreationAuthToAPI(dbAuth *common.AccountCreationAuth) *accountCreationAuthAPI {
return &accountCreationAuthAPI{
EthAddr: ethAddrToHez(dbAuth.EthAddr),
BJJ: bjjToString(dbAuth.BJJ),
Signature: "0x" + hex.EncodeToString(dbAuth.Signature),
Timestamp: dbAuth.Timestamp,
}
}
func accountCreationAuthAPIToCommon(apiAuth *accountCreationAuthAPI) (*common.AccountCreationAuth, error) {
ethAddr, err := hezStringToEthAddr(apiAuth.EthAddr, "hezEthereumAddress")
if err != nil {
return nil, err
}
bjj, err := hezStringToBJJ(apiAuth.BJJ, "bjj")
if err != nil {
return nil, err
}
without0x := strings.TrimPrefix(apiAuth.Signature, "0x")
s, err := hex.DecodeString(without0x)
if err != nil {
return nil, err
}
auth := &common.AccountCreationAuth{
EthAddr: *ethAddr,
BJJ: bjj,
Signature: s,
Timestamp: apiAuth.Timestamp,
}
if !auth.VerifySignature() {
return nil, errors.New("invalid signature")
}
return auth, nil
}