Skip to content

Commit

Permalink
Merge pull request #2 from CudoVentures/Change-APR-Calc
Browse files Browse the repository at this point in the history
Update APR calculations
  • Loading branch information
avalkov authored Sep 7, 2022
2 parents ebe4089 + 41a5a43 commit 1b934ad
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 30 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@
# Go workspace file
go.work

cmd/stats-service/stats-service
cmd/stats-service/stats-service

/stats-service
6 changes: 4 additions & 2 deletions cmd/stats-service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/CudoVentures/cudos-stats-v2-service/internal/config"
"github.com/CudoVentures/cudos-stats-v2-service/internal/handlers"
"github.com/CudoVentures/cudos-stats-v2-service/internal/rest/bank"
"github.com/CudoVentures/cudos-stats-v2-service/internal/rest/distribution"
"github.com/CudoVentures/cudos-stats-v2-service/internal/storage"
"github.com/CudoVentures/cudos-stats-v2-service/internal/tasks"
"github.com/cosmos/cosmos-sdk/simapp/params"
Expand Down Expand Up @@ -45,20 +46,21 @@ func main() {

stakingClient := stakingtypes.NewQueryClient(source.GrpcConn)
bankingRestClient := bank.NewRestClient(cfg.Cudos.REST.Address)
distributionRestClient := distribution.NewRestClient(cfg.Cudos.REST.Address)

keyValueStorage := storage.NewStorage()

log.Info().Msg("Executing tasks")

if err := tasks.ExecuteTasks(cfg, nodeClient, stakingClient, bankingRestClient, keyValueStorage); err != nil {
if err := tasks.ExecuteTasks(cfg, nodeClient, stakingClient, bankingRestClient, distributionRestClient, keyValueStorage); err != nil {
log.Fatal().Err(fmt.Errorf("error while executing tasks: %s", err)).Send()
return
}

log.Info().Msg("Registering tasks")
scheduler := gocron.NewScheduler(time.UTC)

if err := tasks.RegisterTasks(scheduler, cfg, nodeClient, stakingClient, bankingRestClient, keyValueStorage); err != nil {
if err := tasks.RegisterTasks(scheduler, cfg, nodeClient, stakingClient, bankingRestClient, distributionRestClient, keyValueStorage); err != nil {
log.Fatal().Err(fmt.Errorf("error while registering tasks: %s", err)).Send()
return
}
Expand Down
9 changes: 8 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
port: 3000
genesis:
inflation_genesis:
initial_height: 1
norm_time_passed: 0.53172694105988
blocks_per_day: 17280
mint_denom: acudos
gravity_account_address: cudos16n3lc7cywa68mg50qhp847034w88pntq8823tx
apr_genesis:
initial_height: 1069391
norm_time_passed: 0.701184759708210690
real_blocks_per_day: 14048
blocks_per_day: 12345
mint_denom: acudos
gravity_account_address: cudos16n3lc7cywa68mg50qhp847034w88pntq8823tx
cudos:
node:
rpc:
Expand Down
14 changes: 11 additions & 3 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,22 @@ func NewConfig(configPath string) (Config, error) {
}

type Config struct {
Port int `yaml:"port"`
Genesis struct {
Port int `yaml:"port"`
InflationGenesis struct {
InitialHeight int64 `yaml:"initial_height"`
NormTimePassed string `yaml:"norm_time_passed"`
BlocksPerDay string `yaml:"blocks_per_day"`
MintDenom string `yaml:"mint_denom"`
GravityAccountAddress string `yaml:"gravity_account_address"`
} `yaml:"genesis"`
} `yaml:"inflation_genesis"`
APRGenesis struct {
InitialHeight int64 `yaml:"initial_height"`
NormTimePassed string `yaml:"norm_time_passed"`
RealBlocksPerDay string `yaml:"real_blocks_per_day"`
BlocksPerDay string `yaml:"blocks_per_day"`
MintDenom string `yaml:"mint_denom"`
GravityAccountAddress string `yaml:"gravity_account_address"`
} `yaml:"apr_genesis"`
Cudos struct {
NodeDetails remote.Details `yaml:"node"`
REST struct {
Expand Down
4 changes: 2 additions & 2 deletions internal/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,12 @@ func GetParamsHandler(cfg config.Config) func(http.ResponseWriter, *http.Request

if err := json.NewEncoder(w).Encode(paramsResponse{
Params: params{
MintDenom: cfg.Genesis.MintDenom,
MintDenom: cfg.InflationGenesis.MintDenom,
InflationRateChange: "0.0",
InflationMax: "0.0",
InflationMin: "0.0",
GoalBonded: "0.0",
BlocksPerYear: cfg.Genesis.BlocksPerDay,
BlocksPerYear: cfg.InflationGenesis.BlocksPerDay,
},
}); err != nil {
badRequest(w, err)
Expand Down
59 changes: 59 additions & 0 deletions internal/rest/distribution/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package distribution

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)

type client struct {
Url string
}

func NewRestClient(url string) *client {
return &client{Url: url}
}

func (c client) GetParams(ctx context.Context) (ParametersResponse, error) {
respStr, err := c.get(ctx, "/distribution/parameters")
if err != nil {
return ParametersResponse{}, err
}

var res parametersResult
if err := json.Unmarshal([]byte(respStr), &res); err != nil {
return ParametersResponse{}, err
}

return res.Result, nil
}

func (c client) get(ctx context.Context, uri string) (string, error) {
getReq, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s%s", c.Url, uri), nil)
if err != nil {
return "", err
}

resp, err := http.DefaultClient.Do(getReq)
if err != nil {
return "", err
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}

return string(body), nil
}

type parametersResult struct {
Result ParametersResponse `json:"result"`
}

type ParametersResponse struct {
CommunityTax string `json:"community_tax"`
}
28 changes: 26 additions & 2 deletions internal/tasks/apr.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import (

cudoMintTypes "github.com/CudoVentures/cudos-node/x/cudoMint/types"
"github.com/CudoVentures/cudos-stats-v2-service/internal/config"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/forbole/juno/v2/node/remote"
)

func getCalculateAPRHandler(genesisState cudoMintTypes.GenesisState, cfg config.Config, nodeClient *remote.Node, stakingClient stakingtypes.QueryClient, storage keyValueStorage) func() error {
func getCalculateAPRHandler(genesisState cudoMintTypes.GenesisState, cfg config.Config, nodeClient *remote.Node, stakingClient stakingtypes.QueryClient,
distClient distributionQueryClient, storage keyValueStorage) func() error {

return func() error {
if genesisState.Minter.NormTimePassed.GT(finalNormTimePassed) {
return nil
Expand All @@ -27,7 +30,12 @@ func getCalculateAPRHandler(genesisState cudoMintTypes.GenesisState, cfg config.
return fmt.Errorf("failed to get last block height %s", err)
}

mintAmountInt, err := calculateMintedTokensSinceHeight(genesisState, cfg.Genesis.InitialHeight, latestBlockHeight, 30.43)
realBlocksPerDay, ok := sdk.NewIntFromString(cfg.APRGenesis.RealBlocksPerDay)
if !ok {
return fmt.Errorf("failed to parse RealBlocksPerDay %s", cfg.APRGenesis.RealBlocksPerDay)
}

mintAmountInt, err := calculateMintedTokensSinceHeight(genesisState, cfg.APRGenesis.InitialHeight, latestBlockHeight, 30.43, realBlocksPerDay)
if err != nil {
return fmt.Errorf("failed to calculated minted tokens: %s", err)
}
Expand All @@ -42,6 +50,22 @@ func getCalculateAPRHandler(genesisState cudoMintTypes.GenesisState, cfg config.

apr := mintAmountInt.ToDec().Quo(res.Pool.BondedTokens.ToDec()).MulInt64(int64(12))

parametersResponse, err := distClient.GetParams(ctx)
if err != nil {
return fmt.Errorf("failed to get distribution parameters: %s", err)
}

communityTax, err := sdk.NewDecFromStr(parametersResponse.CommunityTax)
if err != nil {
return fmt.Errorf("failed to parse community tax (%s): %s", parametersResponse.CommunityTax, err)
}

communityTaxPortion := sdk.NewDec(1).Sub(communityTax)

if communityTaxPortion.GT(sdk.NewDec(0)) {
apr = apr.Mul(communityTaxPortion)
}

if err := storage.SetValue(cfg.Storage.APRKey, apr.String()); err != nil {
return fmt.Errorf("failed to set value %s for key %s", apr.String(), cfg.Storage.APRKey)
}
Expand Down
8 changes: 4 additions & 4 deletions internal/tasks/inflation.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func getCalculateInflationHandler(genesisState cudoMintTypes.GenesisState, cfg c
var cudosNetworkTotalSupply sdk.Int

for i := 0; i < len(totalSupply.Supply); i++ {
if totalSupply.Supply[i].Denom == cfg.Genesis.MintDenom {
if totalSupply.Supply[i].Denom == cfg.InflationGenesis.MintDenom {
cudosNetworkTotalSupply = totalSupply.Supply[i].Amount
totalSupply.Supply[i].Amount = currentTotalSupply
}
Expand Down Expand Up @@ -161,9 +161,9 @@ func getCudosNetworkCirculatingSupplyAtHeight(height int64, bankingClient bankQu
var gravityModuleBalance sdk.Coin

for {
gravityModuleBalance, err = bankingClient.GetBalance(ctx, height, cfg.Genesis.GravityAccountAddress, cfg.Genesis.MintDenom)
gravityModuleBalance, err = bankingClient.GetBalance(ctx, height, cfg.InflationGenesis.GravityAccountAddress, cfg.InflationGenesis.MintDenom)
if err != nil {
return sdk.Int{}, fmt.Errorf("error while getting %s balance: %s", cfg.Genesis.GravityAccountAddress, err)
return sdk.Int{}, fmt.Errorf("error while getting %s balance: %s", cfg.InflationGenesis.GravityAccountAddress, err)
}

if !gravityModuleBalance.Amount.IsZero() {
Expand All @@ -174,7 +174,7 @@ func getCudosNetworkCirculatingSupplyAtHeight(height int64, bankingClient bankQu
}

for i := 0; i < len(totalSupply.Supply); i++ {
if totalSupply.Supply[i].Denom == cfg.Genesis.MintDenom {
if totalSupply.Supply[i].Denom == cfg.InflationGenesis.MintDenom {
return totalSupply.Supply[i].Amount.Sub(gravityModuleBalance.Amount), nil
}
}
Expand Down
53 changes: 38 additions & 15 deletions internal/tasks/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/CudoVentures/cudos-stats-v2-service/internal/config"
"github.com/CudoVentures/cudos-stats-v2-service/internal/erc20"
"github.com/CudoVentures/cudos-stats-v2-service/internal/rest/bank"
"github.com/CudoVentures/cudos-stats-v2-service/internal/rest/distribution"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand All @@ -20,32 +21,46 @@ import (
"github.com/rs/zerolog/log"
)

func ExecuteTasks(cfg config.Config, nodeClient *remote.Node, stakingClient stakingtypes.QueryClient, bankingClient bankQueryClient, storage keyValueStorage) error {
genesisState, err := createGenesisState(cfg)
func ExecuteTasks(cfg config.Config, nodeClient *remote.Node, stakingClient stakingtypes.QueryClient, bankingClient bankQueryClient,
distClient distributionQueryClient, storage keyValueStorage) error {

inflationGenesisState, err := createGenesisState(cfg.InflationGenesis.NormTimePassed, cfg.InflationGenesis.BlocksPerDay)
if err != nil {
return err
}

if err := getCalculateInflationHandler(*genesisState, cfg, nodeClient, bankingClient, storage)(); err != nil {
if err := getCalculateInflationHandler(*inflationGenesisState, cfg, nodeClient, bankingClient, storage)(); err != nil {
return fmt.Errorf("inflation calculation failed: %s", err)
}

if err := getCalculateAPRHandler(*genesisState, cfg, nodeClient, stakingClient, storage)(); err != nil {
aprGenesisState, err := createGenesisState(cfg.APRGenesis.NormTimePassed, cfg.APRGenesis.BlocksPerDay)
if err != nil {
return err
}

if err := getCalculateAPRHandler(*aprGenesisState, cfg, nodeClient, stakingClient, distClient, storage)(); err != nil {
return fmt.Errorf("apr calculation failed: %s", err)
}

return nil
}

func RegisterTasks(scheduler *gocron.Scheduler, cfg config.Config, nodeClient *remote.Node, stakingClient stakingtypes.QueryClient, bankingClient bankQueryClient, storage keyValueStorage) error {
genesisState, err := createGenesisState(cfg)
func RegisterTasks(scheduler *gocron.Scheduler, cfg config.Config, nodeClient *remote.Node, stakingClient stakingtypes.QueryClient, bankingClient bankQueryClient,
distClient distributionQueryClient, storage keyValueStorage) error {

inflationGenesisState, err := createGenesisState(cfg.InflationGenesis.NormTimePassed, cfg.InflationGenesis.BlocksPerDay)
if err != nil {
return err
}

aprGenesisState, err := createGenesisState(cfg.APRGenesis.NormTimePassed, cfg.APRGenesis.BlocksPerDay)
if err != nil {
return err
}

if _, err := scheduler.Every(1).Day().At("00:00").Do(func() {
watchMethod(getCalculateInflationHandler(*genesisState, cfg, nodeClient, bankingClient, storage))
watchMethod(getCalculateAPRHandler(*genesisState, cfg, nodeClient, stakingClient, storage))
watchMethod(getCalculateInflationHandler(*inflationGenesisState, cfg, nodeClient, bankingClient, storage))
watchMethod(getCalculateAPRHandler(*aprGenesisState, cfg, nodeClient, stakingClient, distClient, storage))
}); err != nil {
return fmt.Errorf("scheduler failed to register tasks: %s", err)
}
Expand Down Expand Up @@ -89,7 +104,7 @@ func getEthAccountsBalanceAtBlock(client *ethclient.Client, tokenAddress string,
return totalBalance, nil
}

func calculateMintedTokensSinceHeight(mintParams cudoMintTypes.GenesisState, genesisInitialHeight, sinceBlock int64, periodDays float64) (sdk.Int, error) {
func calculateMintedTokensSinceHeight(mintParams cudoMintTypes.GenesisState, genesisInitialHeight, sinceBlock int64, periodDays float64, realBlocksPerDay sdk.Int) (sdk.Int, error) {
minter := mintParams.Minter
params := mintParams.Params

Expand All @@ -100,7 +115,11 @@ func calculateMintedTokensSinceHeight(mintParams cudoMintTypes.GenesisState, gen
minter.NormTimePassed = updateNormTimePassed(mintParams, genesisInitialHeight, sinceBlock)

mintAmountInt := sdk.NewInt(0)
totalBlocks := int64(float64(mintParams.Params.BlocksPerDay.Int64()) * periodDays)

// We have to predict what the block count will be periodDays from now. Because
// mintParams.Params.BlocksPerDay is intentionally wrong, using that would give
// us the wrong result. We use the "real blocks per day" instead.
totalBlocks := int64(float64(realBlocksPerDay.Int64()) * periodDays)

for height := int64(1); height <= totalBlocks; height++ {
if minter.NormTimePassed.GT(finalNormTimePassed) {
Expand Down Expand Up @@ -164,15 +183,15 @@ func calculateMintedCoins(minter cudoMintTypes.Minter, increment sdk.Dec) sdk.De
return (nextStep.Sub(prevStep)).Mul(sdk.NewDec(10).Power(24)) // formula calculates in mil of cudos + converting to acudos
}

func createGenesisState(cfg config.Config) (*cudoMintTypes.GenesisState, error) {
normTimePassed, err := sdk.NewDecFromStr(cfg.Genesis.NormTimePassed)
func createGenesisState(normTimePassedStr, blocksPerDayStr string) (*cudoMintTypes.GenesisState, error) {
normTimePassed, err := sdk.NewDecFromStr(normTimePassedStr)
if err != nil {
return nil, fmt.Errorf("failed to parse NormTimePassed %s: %s", cfg.Genesis.NormTimePassed, err)
return nil, fmt.Errorf("failed to parse NormTimePassed %s: %s", normTimePassedStr, err)
}

blocksPerDay, ok := sdk.NewIntFromString(cfg.Genesis.BlocksPerDay)
blocksPerDay, ok := sdk.NewIntFromString(blocksPerDayStr)
if !ok {
return nil, fmt.Errorf("failed to parse BlocksPerDay %s", cfg.Genesis.BlocksPerDay)
return nil, fmt.Errorf("failed to parse BlocksPerDay %s", blocksPerDayStr)
}

return cudoMintTypes.NewGenesisState(cudoMintTypes.NewMinter(sdk.NewDec(0), normTimePassed), cudoMintTypes.NewParams(blocksPerDay)), nil
Expand Down Expand Up @@ -210,3 +229,7 @@ type bankQueryClient interface {
GetTotalSupply(ctx context.Context, height int64) (bank.TotalSupplyResponse, error)
GetBalance(ctx context.Context, height int64, address, denom string) (sdk.Coin, error)
}

type distributionQueryClient interface {
GetParams(ctx context.Context) (distribution.ParametersResponse, error)
}

0 comments on commit 1b934ad

Please sign in to comment.