Add support of staking pools
This commit is contained in:
parent
f03c625def
commit
ac46385f49
16
api/types.go
16
api/types.go
@ -316,6 +316,20 @@ type AddressFilter struct {
|
|||||||
OnlyConfirmed bool
|
OnlyConfirmed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StakingPool holds data about address participation in a staking pool contract
|
||||||
|
type StakingPool struct {
|
||||||
|
Contract string `json:"contract"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PendingBalance *Amount `json:"pendingBalance"`
|
||||||
|
PendingDepositedBalance *Amount `json:"pendingDepositedBalance"`
|
||||||
|
DepositedBalance *Amount `json:"depositedBalance"`
|
||||||
|
WithdrawTotalAmount *Amount `json:"withdrawTotalAmount"`
|
||||||
|
ClaimableAmount *Amount `json:"claimableAmount"`
|
||||||
|
PendingRestakedReward *Amount `json:"pendingRestakedReward"`
|
||||||
|
RestakedReward *Amount `json:"restakedReward"`
|
||||||
|
AutocompoundBalance *Amount `json:"autocompoundBalance"`
|
||||||
|
}
|
||||||
|
|
||||||
// Address holds information about address and its transactions
|
// Address holds information about address and its transactions
|
||||||
type Address struct {
|
type Address struct {
|
||||||
Paging
|
Paging
|
||||||
@ -342,6 +356,7 @@ type Address struct {
|
|||||||
ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
|
ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
|
||||||
Erc20Contract *bchain.ContractInfo `json:"erc20Contract,omitempty"` // deprecated
|
Erc20Contract *bchain.ContractInfo `json:"erc20Contract,omitempty"` // deprecated
|
||||||
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
||||||
|
StakingPools []StakingPool `json:"stakingPools,omitempty"`
|
||||||
// helpers for explorer
|
// helpers for explorer
|
||||||
Filter string `json:"-"`
|
Filter string `json:"-"`
|
||||||
XPubAddresses map[string]struct{} `json:"-"`
|
XPubAddresses map[string]struct{} `json:"-"`
|
||||||
@ -504,6 +519,7 @@ type BlockbookInfo struct {
|
|||||||
CurrentFiatRatesTime *time.Time `json:"currentFiatRatesTime,omitempty"`
|
CurrentFiatRatesTime *time.Time `json:"currentFiatRatesTime,omitempty"`
|
||||||
HistoricalFiatRatesTime *time.Time `json:"historicalFiatRatesTime,omitempty"`
|
HistoricalFiatRatesTime *time.Time `json:"historicalFiatRatesTime,omitempty"`
|
||||||
HistoricalTokenFiatRatesTime *time.Time `json:"historicalTokenFiatRatesTime,omitempty"`
|
HistoricalTokenFiatRatesTime *time.Time `json:"historicalTokenFiatRatesTime,omitempty"`
|
||||||
|
SupportedStakingPools []string `json:"supportedStakingPools,omitempty"`
|
||||||
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
|
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
|
||||||
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
|
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
|
||||||
About string `json:"about"`
|
About string `json:"about"`
|
||||||
|
|||||||
@ -1058,6 +1058,7 @@ type ethereumTypeAddressData struct {
|
|||||||
totalResults int
|
totalResults int
|
||||||
tokensBaseValue float64
|
tokensBaseValue float64
|
||||||
tokensSecondaryValue float64
|
tokensSecondaryValue float64
|
||||||
|
stakingPools []StakingPool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter, secondaryCoin string) (*db.AddrBalance, *ethereumTypeAddressData, error) {
|
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter, secondaryCoin string) (*db.AddrBalance, *ethereumTypeAddressData, error) {
|
||||||
@ -1157,9 +1158,42 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
|||||||
filter.Vout = AddressFilterVoutQueryNotNecessary
|
filter.Vout = AddressFilterVoutQueryNotNecessary
|
||||||
d.totalResults = -1
|
d.totalResults = -1
|
||||||
}
|
}
|
||||||
|
// if staking pool enabled, fetch the staking pool details
|
||||||
|
if details >= AccountDetailsTokenBalances {
|
||||||
|
d.stakingPools, err = w.getStakingPoolsData(addrDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return ba, &d, nil
|
return ba, &d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Worker) getStakingPoolsData(addrDesc bchain.AddressDescriptor) ([]StakingPool, error) {
|
||||||
|
var pools []StakingPool
|
||||||
|
if len(w.chain.EthereumTypeGetSupportedStakingPools()) > 0 {
|
||||||
|
sp, err := w.chain.EthereumTypeGetStakingPoolsData(addrDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range sp {
|
||||||
|
p := &sp[i]
|
||||||
|
pools = append(pools, StakingPool{
|
||||||
|
Contract: p.Contract,
|
||||||
|
Name: p.Name,
|
||||||
|
PendingBalance: (*Amount)(&p.PendingBalance),
|
||||||
|
PendingDepositedBalance: (*Amount)(&p.PendingDepositedBalance),
|
||||||
|
DepositedBalance: (*Amount)(&p.DepositedBalance),
|
||||||
|
WithdrawTotalAmount: (*Amount)(&p.WithdrawTotalAmount),
|
||||||
|
ClaimableAmount: (*Amount)(&p.ClaimableAmount),
|
||||||
|
PendingRestakedReward: (*Amount)(&p.PendingRestakedReward),
|
||||||
|
RestakedReward: (*Amount)(&p.RestakedReward),
|
||||||
|
AutocompoundBalance: (*Amount)(&p.AutocompoundBalance),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pools, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Worker) txFromTxid(txid string, bestHeight uint32, option AccountDetails, blockInfo *db.BlockInfo, addresses map[string]struct{}) (*Tx, error) {
|
func (w *Worker) txFromTxid(txid string, bestHeight uint32, option AccountDetails, blockInfo *db.BlockInfo, addresses map[string]struct{}) (*Tx, error) {
|
||||||
var tx *Tx
|
var tx *Tx
|
||||||
var err error
|
var err error
|
||||||
@ -1401,6 +1435,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||||||
ContractInfo: ed.contractInfo,
|
ContractInfo: ed.contractInfo,
|
||||||
Nonce: ed.nonce,
|
Nonce: ed.nonce,
|
||||||
AddressAliases: w.getAddressAliases(addresses),
|
AddressAliases: w.getAddressAliases(addresses),
|
||||||
|
StakingPools: ed.stakingPools,
|
||||||
}
|
}
|
||||||
// keep address backward compatible, set deprecated Erc20Contract value if ERC20 token
|
// keep address backward compatible, set deprecated Erc20Contract value if ERC20 token
|
||||||
if ed.contractInfo != nil && ed.contractInfo.Type == bchain.ERC20TokenType {
|
if ed.contractInfo != nil && ed.contractInfo.Type == bchain.ERC20TokenType {
|
||||||
@ -2379,6 +2414,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
|||||||
CurrentFiatRatesTime: nonZeroTime(currentFiatRatesTime),
|
CurrentFiatRatesTime: nonZeroTime(currentFiatRatesTime),
|
||||||
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
||||||
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
||||||
|
SupportedStakingPools: w.chain.EthereumTypeGetSupportedStakingPools(),
|
||||||
DbSize: w.db.DatabaseSizeOnDisk(),
|
DbSize: w.db.DatabaseSizeOnDisk(),
|
||||||
DbSizeFromColumns: internalDBSize,
|
DbSizeFromColumns: internalDBSize,
|
||||||
DbColumns: columnStats,
|
DbColumns: columnStats,
|
||||||
|
|||||||
@ -41,30 +41,38 @@ func (b *BaseChain) GetMempoolEntry(txid string) (*MempoolEntry, error) {
|
|||||||
|
|
||||||
// EthereumTypeGetBalance is not supported
|
// EthereumTypeGetBalance is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetNonce is not supported
|
// EthereumTypeGetNonce is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error) {
|
func (b *BaseChain) EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error) {
|
||||||
return 0, errors.New("Not supported")
|
return 0, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeEstimateGas is not supported
|
// EthereumTypeEstimateGas is not supported
|
||||||
func (b *BaseChain) EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error) {
|
func (b *BaseChain) EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error) {
|
||||||
return 0, errors.New("Not supported")
|
return 0, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractInfo is not supported
|
// GetContractInfo is not supported
|
||||||
func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
|
func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetErc20ContractBalance is not supported
|
// EthereumTypeGetErc20ContractBalance is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error) {
|
func (b *BaseChain) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
||||||
func (p *BaseChain) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) {
|
func (p *BaseChain) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) {
|
||||||
return "", errors.New("Not supported")
|
return "", errors.New("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseChain) EthereumTypeGetSupportedStakingPools() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseChain) EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error) {
|
||||||
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -332,6 +332,15 @@ func (c *blockChainWithMetrics) GetTokenURI(contractDesc bchain.AddressDescripto
|
|||||||
return c.b.GetTokenURI(contractDesc, tokenID)
|
return c.b.GetTokenURI(contractDesc, tokenID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) EthereumTypeGetSupportedStakingPools() []string {
|
||||||
|
return c.b.EthereumTypeGetSupportedStakingPools()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) EthereumTypeGetStakingPoolsData(addrDesc bchain.AddressDescriptor) (v []bchain.StakingPoolData, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeStakingPoolsData", s, err) }(time.Now())
|
||||||
|
return c.b.EthereumTypeGetStakingPoolsData(addrDesc)
|
||||||
|
}
|
||||||
|
|
||||||
type mempoolWithMetrics struct {
|
type mempoolWithMetrics struct {
|
||||||
mempool bchain.Mempool
|
mempool bchain.Mempool
|
||||||
m *common.Metrics
|
m *common.Metrics
|
||||||
|
|||||||
@ -337,9 +337,9 @@ func (b *EthereumRPC) GetContractInfo(contractDesc bchain.AddressDescriptor) (*b
|
|||||||
|
|
||||||
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
||||||
func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) {
|
func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) {
|
||||||
addr := hexutil.Encode(addrDesc)
|
addr := hexutil.Encode(addrDesc)[2:]
|
||||||
contract := hexutil.Encode(contractDesc)
|
contract := hexutil.Encode(contractDesc)
|
||||||
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr)-2:] + addr[2:]
|
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
|
||||||
data, err := b.ethCall(req, contract)
|
data, err := b.ethCall(req, contract)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -56,23 +56,26 @@ type Configuration struct {
|
|||||||
// EthereumRPC is an interface to JSON-RPC eth service.
|
// EthereumRPC is an interface to JSON-RPC eth service.
|
||||||
type EthereumRPC struct {
|
type EthereumRPC struct {
|
||||||
*bchain.BaseChain
|
*bchain.BaseChain
|
||||||
Client bchain.EVMClient
|
Client bchain.EVMClient
|
||||||
RPC bchain.EVMRPCClient
|
RPC bchain.EVMRPCClient
|
||||||
MainNetChainID Network
|
MainNetChainID Network
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
Parser *EthereumParser
|
Parser *EthereumParser
|
||||||
PushHandler func(bchain.NotificationType)
|
PushHandler func(bchain.NotificationType)
|
||||||
OpenRPC func(string) (bchain.EVMRPCClient, bchain.EVMClient, error)
|
OpenRPC func(string) (bchain.EVMRPCClient, bchain.EVMClient, error)
|
||||||
Mempool *bchain.MempoolEthereumType
|
Mempool *bchain.MempoolEthereumType
|
||||||
mempoolInitialized bool
|
mempoolInitialized bool
|
||||||
bestHeaderLock sync.Mutex
|
bestHeaderLock sync.Mutex
|
||||||
bestHeader bchain.EVMHeader
|
bestHeader bchain.EVMHeader
|
||||||
bestHeaderTime time.Time
|
bestHeaderTime time.Time
|
||||||
NewBlock bchain.EVMNewBlockSubscriber
|
NewBlock bchain.EVMNewBlockSubscriber
|
||||||
newBlockSubscription bchain.EVMClientSubscription
|
newBlockSubscription bchain.EVMClientSubscription
|
||||||
NewTx bchain.EVMNewTxSubscriber
|
NewTx bchain.EVMNewTxSubscriber
|
||||||
newTxSubscription bchain.EVMClientSubscription
|
newTxSubscription bchain.EVMClientSubscription
|
||||||
ChainConfig *Configuration
|
ChainConfig *Configuration
|
||||||
|
supportedStakingPools []string
|
||||||
|
stakingPoolNames []string
|
||||||
|
stakingPoolContracts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessInternalTransactions specifies if internal transactions are processed
|
// ProcessInternalTransactions specifies if internal transactions are processed
|
||||||
@ -155,6 +158,12 @@ func (b *EthereumRPC) Initialize() error {
|
|||||||
default:
|
default:
|
||||||
return errors.Errorf("Unknown network id %v", id)
|
return errors.Errorf("Unknown network id %v", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = b.initStakingPools(b.ChainConfig.CoinShortcut)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
glog.Info("rpc: block chain ", b.Network)
|
glog.Info("rpc: block chain ", b.Network)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
150
bchain/coins/eth/stakingpool.go
Normal file
150
bchain/coins/eth/stakingpool.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *EthereumRPC) initStakingPools(coinShortcut string) error {
|
||||||
|
// for now only single staking pool
|
||||||
|
envVar := strings.ToUpper(coinShortcut) + "_STAKING_POOL_CONTRACT"
|
||||||
|
envValue := os.Getenv(envVar)
|
||||||
|
if envValue != "" {
|
||||||
|
parts := strings.Split(envValue, "/")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
glog.Errorf("Wrong format of environment variable %s=%s, expecting value '<pool name>/<pool contract>', staking pools not enabled", envVar, envValue)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
b.supportedStakingPools = []string{envValue}
|
||||||
|
b.stakingPoolNames = []string{parts[0]}
|
||||||
|
b.stakingPoolContracts = []string{parts[1]}
|
||||||
|
glog.Info("Support of staking pools enabled with these pools: ", b.supportedStakingPools)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) EthereumTypeGetSupportedStakingPools() []string {
|
||||||
|
return b.supportedStakingPools
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) EthereumTypeGetStakingPoolsData(addrDesc bchain.AddressDescriptor) ([]bchain.StakingPoolData, error) {
|
||||||
|
// for now only single staking pool - Everstake
|
||||||
|
addr := hexutil.Encode(addrDesc)[2:]
|
||||||
|
if len(b.supportedStakingPools) == 1 {
|
||||||
|
data, err := b.everstakePoolData(addr, b.stakingPoolContracts[0], b.stakingPoolNames[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if data != nil {
|
||||||
|
return []bchain.StakingPoolData{*data}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const everstakePendingBalanceOfMethodSignature = "0x59b8c763" // pendingBalanceOf(address)
|
||||||
|
const everstakePendingDepositedBalanceOfMethodSignature = "0x80f14ecc" // pendingDepositedBalanceOf(address)
|
||||||
|
const everstakeDepositedBalanceOfMethodSignature = "0x68b48254" // depositedBalanceOf(address)
|
||||||
|
const everstakeWithdrawRequestMethodSignature = "0x14cbc46a" // withdrawRequest(address)
|
||||||
|
const everstakePendingRestakedRewardOfMethodSignature = "0x376d1884" // pendingRestakedRewardOf(address)
|
||||||
|
const everstakeRestakedRewardOfMethodSignature = "0x0c98929a" // restakedRewardOf(address)
|
||||||
|
const everstakeAutocompoundBalanceOfMethodSignature = "0x2fec7966" // autocompoundBalanceOf(address)
|
||||||
|
|
||||||
|
func isZeroBigInt(b *big.Int) bool {
|
||||||
|
return len(b.Bits()) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) everstakeBalanceTypeContractCall(signature, addr, contract string) (string, error) {
|
||||||
|
req := signature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
|
||||||
|
return b.ethCall(req, contract)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) everstakeContractCallSimpleNumeric(signature, addr, contract string) (*big.Int, error) {
|
||||||
|
data, err := b.everstakeBalanceTypeContractCall(signature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := parseSimpleNumericProperty(data)
|
||||||
|
if r == nil {
|
||||||
|
return nil, errors.New("Invalid balance")
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) everstakePoolData(addr, contract, name string) (*bchain.StakingPoolData, error) {
|
||||||
|
poolData := bchain.StakingPoolData{
|
||||||
|
Contract: contract,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
allZeros := true
|
||||||
|
|
||||||
|
value, err := b.everstakeContractCallSimpleNumeric(everstakePendingBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.PendingBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakePendingDepositedBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.PendingDepositedBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakeDepositedBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.DepositedBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
data, err := b.everstakeBalanceTypeContractCall(everstakeWithdrawRequestMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
value = parseSimpleNumericProperty(data)
|
||||||
|
if value == nil {
|
||||||
|
return nil, errors.New("Invalid balance")
|
||||||
|
}
|
||||||
|
poolData.WithdrawTotalAmount = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
value = parseSimpleNumericProperty(data[64+2:])
|
||||||
|
if value == nil {
|
||||||
|
return nil, errors.New("Invalid balance")
|
||||||
|
}
|
||||||
|
poolData.ClaimableAmount = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakePendingRestakedRewardOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.PendingRestakedReward = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakeRestakedRewardOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.RestakedReward = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakeAutocompoundBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.AutocompoundBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
if allZeros {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &poolData, nil
|
||||||
|
}
|
||||||
@ -333,6 +333,8 @@ type BlockChain interface {
|
|||||||
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
||||||
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
|
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
|
||||||
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
|
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
|
||||||
|
EthereumTypeGetSupportedStakingPools() []string
|
||||||
|
EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error)
|
||||||
GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error)
|
GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -146,3 +146,17 @@ type EthereumBlockSpecificData struct {
|
|||||||
AddressAliasRecords []AddressAliasRecord
|
AddressAliasRecords []AddressAliasRecord
|
||||||
Contracts []ContractInfo
|
Contracts []ContractInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StakingPool holds data about address participation in a staking pool contract
|
||||||
|
type StakingPoolData struct {
|
||||||
|
Contract string `json:"contract"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PendingBalance big.Int `json:"pendingBalance"` // pendingBalanceOf method
|
||||||
|
PendingDepositedBalance big.Int `json:"pendingDepositedBalance"` // pendingDepositedBalanceOf method
|
||||||
|
DepositedBalance big.Int `json:"depositedBalance"` // depositedBalanceOf method
|
||||||
|
WithdrawTotalAmount big.Int `json:"withdrawTotalAmount"` // withdrawRequest method, return value [0]
|
||||||
|
ClaimableAmount big.Int `json:"claimableAmount"` // withdrawRequest method, return value [1]
|
||||||
|
PendingRestakedReward big.Int `json:"pendingRestakedReward"` // pendingRestakedRewardOf method
|
||||||
|
RestakedReward big.Int `json:"restakedReward"` // restakedRewardOf method
|
||||||
|
AutocompoundBalance big.Int `json:"autocompoundBalance"` // autocompoundBalanceOf method
|
||||||
|
}
|
||||||
|
|||||||
@ -109,6 +109,17 @@ export interface FeeStats {
|
|||||||
averageFeePerKb: number;
|
averageFeePerKb: number;
|
||||||
decilesFeePerKb: number[];
|
decilesFeePerKb: number[];
|
||||||
}
|
}
|
||||||
|
export interface StakingPool {
|
||||||
|
contract: string;
|
||||||
|
pendingBalance: string;
|
||||||
|
pendingDepositedBalance: string;
|
||||||
|
depositedBalance: string;
|
||||||
|
withdrawTotalAmount: string;
|
||||||
|
claimableAmount: string;
|
||||||
|
pendingRestakedReward: string;
|
||||||
|
restakedReward: string;
|
||||||
|
autocompoundBalance: string;
|
||||||
|
}
|
||||||
export interface ContractInfo {
|
export interface ContractInfo {
|
||||||
type: string;
|
type: string;
|
||||||
contract: string;
|
contract: string;
|
||||||
@ -161,6 +172,7 @@ export interface Address {
|
|||||||
contractInfo?: ContractInfo;
|
contractInfo?: ContractInfo;
|
||||||
erc20Contract?: ContractInfo;
|
erc20Contract?: ContractInfo;
|
||||||
addressAliases?: { [key: string]: AddressAlias };
|
addressAliases?: { [key: string]: AddressAlias };
|
||||||
|
stakingPools?: StakingPool[];
|
||||||
}
|
}
|
||||||
export interface Utxo {
|
export interface Utxo {
|
||||||
txid: string;
|
txid: string;
|
||||||
@ -264,6 +276,7 @@ export interface BlockbookInfo {
|
|||||||
currentFiatRatesTime?: string;
|
currentFiatRatesTime?: string;
|
||||||
historicalFiatRatesTime?: string;
|
historicalFiatRatesTime?: string;
|
||||||
historicalTokenFiatRatesTime?: string;
|
historicalTokenFiatRatesTime?: string;
|
||||||
|
stakingPoolContracts?: string[];
|
||||||
dbSizeFromColumns?: number;
|
dbSizeFromColumns?: number;
|
||||||
dbColumns?: InternalStateColumn[];
|
dbColumns?: InternalStateColumn[];
|
||||||
about: string;
|
about: string;
|
||||||
|
|||||||
@ -221,6 +221,64 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if $addr.StakingPools }}
|
||||||
|
<div class="accordion mt-2 mb-2" id="stakingPools">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<div class="accordion-header" id="stakingPoolsHeading">
|
||||||
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#stakingPoolsBody" aria-expanded="false" aria-controls="stakingPoolsBody">
|
||||||
|
<div class="row g-0 w-100">
|
||||||
|
<h5 class="col-12 mb-md-0">Staking Pools <span class="badge bg-secondary">{{len $addr.StakingPools}}</span></span></h5>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="stakingPoolsBody" class="accordion-collapse collapse" aria-labelledby="stakingPoolsHeading" data-bs-parent="#stakingPools">
|
||||||
|
<div class="accordion-body">
|
||||||
|
{{range $sp := $addr.StakingPools}}
|
||||||
|
<table class="table data-table info-table mt-0 mb-2 ml-0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="white-space: nowrap;"><span class="h5" style="color: var(--bs-body-color);">{{$sp.Name}}</span> {{$sp.Contract}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%;">Pending Balance</td>
|
||||||
|
<td>{{amountSpan $sp.PendingBalance $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Pending Deposited Balance</td>
|
||||||
|
<td>{{amountSpan $sp.PendingDepositedBalance $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%;">Deposited Balance</td>
|
||||||
|
<td>{{amountSpan $sp.DepositedBalance $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Withdrawal Total Amount</td>
|
||||||
|
<td>{{amountSpan $sp.WithdrawTotalAmount $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="width: 25%;">Claimable Amount</td>
|
||||||
|
<td>{{amountSpan $sp.ClaimableAmount $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Pending Restaked Reward</td>
|
||||||
|
<td>{{amountSpan $sp.PendingRestakedReward $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Restaked Reward</td>
|
||||||
|
<td>{{amountSpan $sp.RestakedReward $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Autocompound Balance</td>
|
||||||
|
<td>{{amountSpan $sp.AutocompoundBalance $data "copyable"}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if or $addr.Transactions $addr.Filter}}
|
{{if or $addr.Transactions $addr.Filter}}
|
||||||
<div class="row pt-3 pb-1">
|
<div class="row pt-3 pb-1">
|
||||||
|
|||||||
@ -64,6 +64,12 @@
|
|||||||
<td>Size On Disk</td>
|
<td>Size On Disk</td>
|
||||||
<td>{{formatInt64 $bb.DbSize}}</td>
|
<td>{{formatInt64 $bb.DbSize}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{{if $bb.SupportedStakingPools}}
|
||||||
|
<tr>
|
||||||
|
<td>Supported Staking Pools</td>
|
||||||
|
<td>{{$bb.SupportedStakingPools}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user