Skip to content

Commit

Permalink
Merge pull request #48 from terra-money/feat/initial/delegations
Browse files Browse the repository at this point in the history
feat: alliance initial delegations
  • Loading branch information
emidev98 authored Aug 10, 2023
2 parents 93fe9c6 + 87f27c3 commit 73dec5f
Show file tree
Hide file tree
Showing 15 changed files with 505 additions and 331 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
#################################################
### START ###
#################################################
start-alliance-initial-delegation:
go run ./cmd/feeder/feeder.go alliance-initial-delegation

start-alliance-oracle-feeder:
go run ./cmd/feeder/feeder.go alliance-oracle-feeder

Expand Down
8 changes: 8 additions & 0 deletions cmd/price-server/price_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ func main() {
}
c.JSON(http.StatusOK, allianceRebalanceVals)
})
r.GET("/alliance/delegations", func(c *gin.Context) {
allianceDelegatios, err := allianceProvider.GetAllianceInitialDelegations(ctx)
if err != nil {
c.JSON(http.StatusInternalServerError, err)
return
}
c.JSON(http.StatusOK, allianceDelegatios)
})
if os.Getenv("PRICE_SERVER_PORT") == "" {
os.Setenv("PORT", "8532") // use 8532 by default
} else {
Expand Down
2 changes: 1 addition & 1 deletion config/alliance_default_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package config
var PHOENIX_GRPC = "terra-grpc.polkachu.com:11790"
var MIGALOO_GRPC = "migaloo-grpc.polkachu.com:20790"
var KUJIRA_GRPC = "kujira-grpc.polkachu.com:11890"
var CARBON_GRPC = "query-grpc.carbon.network:443"
var CARBON_GRPC = "carbon-grpc.terra.dev:443"

var AllianceDefaultConfig = AllianceConfig{
GRPCUrls: []string{MIGALOO_GRPC, KUJIRA_GRPC, CARBON_GRPC},
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/terra-money/oracle-feeder-go
go 1.20

require (
cosmossdk.io/math v1.0.0-rc.0
github.com/CosmWasm/wasmd v1.0.0
github.com/cosmos/cosmos-sdk v0.46.13
github.com/gin-gonic/gin v1.9.0
Expand All @@ -18,6 +17,7 @@ require (

require (
cosmossdk.io/errors v1.0.0-beta.7 // indirect
cosmossdk.io/math v1.0.0-rc.0 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
Expand Down
286 changes: 0 additions & 286 deletions go.sum

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions internal/provider/alliance/alliance_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ func (p *allianceProvider) GetProtocolsInfo(ctx context.Context) (*types.MsgUpda
func (p *allianceProvider) GetAllianceRedelegateReq(ctx context.Context) (*types.MsgAllianceRedelegate, error) {
return p.allianceValidatorsProvider.GetAllianceRedelegateReq(ctx)
}

func (p *allianceProvider) GetAllianceInitialDelegations(ctx context.Context) (*types.MsgAllianceDelegations, error) {
return p.allianceValidatorsProvider.GetAllianceInitialDelegations(ctx)
}
180 changes: 142 additions & 38 deletions internal/provider/alliance/alliance_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"
"os"
"sort"
"strconv"
"strings"

Expand All @@ -21,7 +22,6 @@ import (
"github.com/cosmos/cosmos-sdk/types/query"

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
alliancetypes "github.com/terra-money/alliance/x/alliance/types"
)
Expand All @@ -31,13 +31,19 @@ type allianceValidatorsProvider struct {
config *config.AllianceConfig
providerManager *provider.ProviderManager
nodeGrpcUrl string
terraLcdUrl string
stationApiUrl string
allianceHubContractAddress string
blocksToBeSeniorValidator int64
voteOnProposalsToBeSeniorValidator int64
}

func NewAllianceValidatorsProvider(config *config.AllianceConfig, providerManager *provider.ProviderManager) *allianceValidatorsProvider {
var terraLcdUrl string
if terraLcdUrl = os.Getenv("TERRA_LCD_URL"); len(terraLcdUrl) == 0 {
panic("TERRA_LCD_URL env variable is not set!")
}

var nodeGrpcUrl string
if nodeGrpcUrl = os.Getenv("NODE_GRPC_URL"); len(nodeGrpcUrl) == 0 {
panic("NODE_GRPC_URL env variable is not set!")
Expand Down Expand Up @@ -78,6 +84,7 @@ func NewAllianceValidatorsProvider(config *config.AllianceConfig, providerManage
return &allianceValidatorsProvider{
BaseGrpc: *internal.NewBaseGrpc(),
config: config,
terraLcdUrl: terraLcdUrl,
nodeGrpcUrl: nodeGrpcUrl,
stationApiUrl: stationApiUrl,
providerManager: providerManager,
Expand All @@ -87,6 +94,47 @@ func NewAllianceValidatorsProvider(config *config.AllianceConfig, providerManage
}
}

// Query Terra GRPC, station API and return the list of alliance
// redelegations that can be submitted to Alliance Hub applying
// the following rules:
// (1) - be part of the active validator set,
// (2) - to do not be jailed,
// (3) - commission rate to be lower than 10%,
// (4) - Participate in the latest 3 gov proposals,
// (5) - have been in the active validator set 100 000 blocks before the current one, (1 week approx)
func (p *allianceValidatorsProvider) GetAllianceInitialDelegations(ctx context.Context) (*pkgtypes.MsgAllianceDelegations, error) {
smartContractRes, err := p.querySmartContractConfig(ctx)
if err != nil {
return nil, err
}

stakingValidators, seniorValidators, proposalsVotes, _, err := p.queryValidatorsData(ctx)
if err != nil {
return nil, err
}
compliantVals := p.GetCompliantValidators(stakingValidators, proposalsVotes, seniorValidators)
allianceTokenSupply, err := strconv.ParseInt(smartContractRes.AllianceTokenSupply, 10, 64)
if err != nil {
panic(err)
}
tokensPerVal := allianceTokenSupply / int64(len(compliantVals))

var delegations []types.Delegation
for i := 0; i < len(compliantVals); i++ {
delegations = append(
delegations,
types.NewDelegation(
compliantVals[i].OperatorAddress,
fmt.Sprint(tokensPerVal),
),
)
}

res := pkgtypes.NewMsgAllianceDelegations(delegations)

return &res, nil
}

// Query Terra GRPC, station API and return the list of alliance
// redelegations that can be submitted to Alliance Hub applying
// the following rules:
Expand All @@ -106,11 +154,38 @@ func (p *allianceValidatorsProvider) GetAllianceRedelegateReq(ctx context.Contex
return nil, err
}

// Apply the previous rules to filter the list of validators
compliantVals := p.GetCompliantValidators(stakingValidators, proposalsVotes, seniorValidators)

valsWithAllianceTokens, totalAllianceStakedTokens := FilterAllianceValsWithStake(allianceVals, smartContractRes.AllianceTokenDenom)
compliantValsWithAllianceTokens,
nonCompliantValsWithAllianceTokens := ParseAllianceValsByCompliance(compliantVals, valsWithAllianceTokens, smartContractRes.AllianceTokenDenom)
avgTokensPerCompliantVal := totalAllianceStakedTokens.Quo(sdktypes.NewDec(int64(len(compliantVals))))

redelegations := RebalanceVals(
compliantValsWithAllianceTokens,
nonCompliantValsWithAllianceTokens,
avgTokensPerCompliantVal,
)

res := pkgtypes.NewMsgAllianceRedelegate(redelegations)

return &res, nil
}

// Apply the rules to filter the list of validators
// (1) - be part of the active validator set,
// (2) - to do not be jailed,
// (3) - commission rate to be lower than 10%,
// (4) - Participate in the latest 3 gov proposals,
// (5) - have been in the active validator set 100 000 blocks before the current one, (1 week approx)
func (p *allianceValidatorsProvider) GetCompliantValidators(stakingValidators []stakingtypes.Validator, proposalsVotes []types.StationVote, seniorValidators []*tmservice.Validator) []stakingtypes.Validator {
var compliantVals []stakingtypes.Validator
// Apply the previous rules to filter the list

// of all blockchain validators to keep the ones
// that are compliant
for _, val := range stakingValidators {

// (1) skip if status is not bonded (again in case the api have a bug with the query)
if val.GetStatus() != stakingtypes.Bonded {
continue
Expand All @@ -131,30 +206,16 @@ func (p *allianceValidatorsProvider) GetAllianceRedelegateReq(ctx context.Contex
continue
}

// (5) skip if it have not been in the active validator set 100 000 blocks before the current one
for _, seniorValidator := range seniorValidators {
if val.OperatorAddress != seniorValidator.Address {
// (5) if the validator is a senior one add to the array
if seniorValidator.PubKey.Equal(val.ConsensusPubkey) {
compliantVals = append(compliantVals, val)
continue
}
}

compliantVals = append(compliantVals, val)
}

valsWithAllianceTokens, totalAllianceStakedTokens := FilterAllianceValsWithStake(allianceVals, smartContractRes.AllianceTokenDenom)
compliantValsWithAllianceTokens,
nonCompliantValsWithAllianceTokens := ParseAllianceValsByCompliance(compliantVals, valsWithAllianceTokens, smartContractRes.AllianceTokenDenom)
avgTokensPerCompliantVal := totalAllianceStakedTokens.Quo(sdktypes.NewDec(int64(len(compliantVals))))

redelegations := RebalanceVals(
compliantValsWithAllianceTokens,
nonCompliantValsWithAllianceTokens,
avgTokensPerCompliantVal,
)

res := pkgtypes.NewMsgAllianceRedelegate(redelegations)

return &res, nil
return compliantVals
}

// In charge of rebalancing the stake from non-compliant validators to compliant ones.
Expand Down Expand Up @@ -366,7 +427,6 @@ func (p *allianceValidatorsProvider) queryValidatorsData(ctx context.Context) (
defer grpcConn.Close()

nodeClient := tmservice.NewServiceClient(grpcConn)
govClient := govtypes.NewQueryClient(grpcConn)
stakingClient := stakingtypes.NewQueryClient(grpcConn)
allianceClient := alliancetypes.NewQueryClient(grpcConn)

Expand All @@ -381,17 +441,6 @@ func (p *allianceValidatorsProvider) queryValidatorsData(ctx context.Context) (
return nil, nil, nil, nil, err
}

govPropsRes, err := govClient.Proposals(ctx, &govtypes.QueryProposalsRequest{
Pagination: &query.PageRequest{
Limit: 3,
Reverse: true,
},
})
if err != nil {
fmt.Printf("govPropsRes: %v \n", err)
return nil, nil, nil, nil, err
}

latestHeightRes, err := nodeClient.GetLatestBlock(ctx, &tmservice.GetLatestBlockRequest{})
if err != nil {
fmt.Printf("latestHeightRes: %v \n", err)
Expand All @@ -406,7 +455,7 @@ func (p *allianceValidatorsProvider) queryValidatorsData(ctx context.Context) (
return nil, nil, nil, nil, err
}

proposalsVotesRes, err := p.getProposalsVotesFromStationAPI(ctx, govPropsRes.Proposals)
proposalsVotesRes, err := p.getProposals(ctx)
if err != nil {
fmt.Printf("proposalsVotesRes: %v \n", err)
return nil, nil, nil, nil, err
Expand All @@ -429,19 +478,74 @@ func (p *allianceValidatorsProvider) queryValidatorsData(ctx context.Context) (
nil
}

func (p *allianceValidatorsProvider) getProposalsVotesFromStationAPI(ctx context.Context, proposals []*govtypes.Proposal) (stationProposals []types.StationVote, err error) {
for _, proposal := range proposals {
stationProposalsRes, err := p.queryStation(proposal.Id)
func (p *allianceValidatorsProvider) getProposals(ctx context.Context) (stationProposals []types.StationVote, err error) {
passedProposalsUrl := "/cosmos/gov/v1/proposals?proposal_status=3&pagination.limit=2&pagination.reverse=true"
rejectedProposalsUrl := "/cosmos/gov/v1/proposals?proposal_status=4&pagination.limit=2&pagination.reverse=true"
passedProposalsIDs, err := p.queryProposalIDs(passedProposalsUrl)
if err != nil {
return stationProposals, err
}
rejectedProposalsIDs, err := p.queryProposalIDs(rejectedProposalsUrl)
if err != nil {
return stationProposals, err
}

// Merge the passed and rejected proposals IDs
// and sort them to get the latest 3 proposals
proposalsIDs := append(passedProposalsIDs, rejectedProposalsIDs...)
sort.Slice(proposalsIDs, func(i, j int) bool {
return proposalsIDs[i] > proposalsIDs[j]
})
proposalsIDs = proposalsIDs[:3]

// Iterate over the proposals and request the latest votes
for _, proposalID := range proposalsIDs {
stationProposalsRes, err := p.queryStation(proposalID)
if err != nil {
return stationProposals, err
}
stationProposals = append(stationProposals, *stationProposalsRes...)
}

return stationProposals, err
}

func (p allianceValidatorsProvider) queryStation(propId uint64) (res *[]types.StationVote, err error) {
func (p allianceValidatorsProvider) queryProposalIDs(urlSuffix string) (proposalIDs []int64, err error) {
url := p.terraLcdUrl + urlSuffix

// Send GET request
res, err := http.Get(url)
if err != nil {
return nil, err
}
defer res.Body.Close()

// Read response body
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
var resGov *types.GovRes

// Parse JSON response into struct
err = json.Unmarshal(body, &resGov)
if err != nil {
return nil, err
}

for _, proposal := range resGov.Proposals {
propID, err := strconv.ParseInt(proposal.Id, 10, 64)
if err != nil {
fmt.Println("Error:", err)
return nil, err
}
proposalIDs = append(proposalIDs, propID)
}

// Access parsed data
return proposalIDs, nil
}

func (p allianceValidatorsProvider) queryStation(propId int64) (res *[]types.StationVote, err error) {
url := p.stationApiUrl + "/proposals/" + fmt.Sprint(propId)
// Send GET request
resp, err := http.Get(url)
Expand Down
Loading

0 comments on commit 73dec5f

Please sign in to comment.