Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Cardano chain #43

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
75 changes: 75 additions & 0 deletions core/chains/cardano.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package chains

import (
"encoding/json"
"fmt"
"log"
"math/big"
"net/http"

utils "github.com/xenowits/nakamoto-coefficient-calculator/core/utils"
)

type ChartData struct {
AvgStake float64 `json:"avgstake"`
DelegateCount int `json:"delegatecount"`
Epoch int `json:"epoch"`
Label string `json:"label"`
Leverage string `json:"leverage"`
MavGroup string `json:"mavgroup"`
Pledge float64 `json:"pledge"`
PoolCount int `json:"poolcount"`
PrctStake float64 `json:"prctstake"`
Stake float64 `json:"stake"`
}

func Cardano() (int, error) {
url := "https://api.balanceanalytics.io/rpc/pool_group_stake_donut"

req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Println("Error creating request:", err)
return 0, err
}

// This is the PUBLIC_BALANCE_API_TOKEN taken from https://www.balanceanalytics.io/chartboards/donut_shop
req.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoid2ViYXBwX3VzZXIifQ.eg3Zb9ZduibYJr1pgUrfqy4PFhkVU1uO_F9gFPBZnBI")
Copy link

@MokhFn MokhFn Jul 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to make this bearer value a param within a params file ? and import it from there ?
Is there and expiration date on the token ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add it as a parameter:

docker run --rm \
-e "SOLANA_API_KEY=<YOUR_SOLANA_API_KEY_HERE>" \
-e "CARDANO_API_KEY=<YOUR_CARDANO_API_KEY_HERE>" \
-e "RATED_API_KEY=<YOUR_RATED_API_KEY_HERE>" \
-p 8080:8080 xenowits/nc-calc:v0.1.4

Anyway, I'm not completely sure about the validity.
While searching for another data source to close this PR, I came across another PR. Here, @ccgarant, suggested to use https://www.balanceanalytics.io/chartboards/donut_shop. I searched the data source in the networking tab and noticed the API call to https://api.balanceanalytics.io/rpc/pool_group_stake_donut, where the bearer token to get authenticated can be found in the page's source code as PUBLIC_BALANCE_API_TOKEN:

__sveltekit_12bou38 = {
  base: new URL("..",location).pathname.slice(0, -1),
  env: {
      "PUBLIC_BALANCE_API_TOKEN": "...",
      "PUBLIC_SUPABASE_ANON_KEY": "...",
  ...
  }
};

So they're apparently loading it from the environment and then using it. Anyway, I'm not really sure if this is intentional or not. I'll try to contact @ccgarant and see if he can help.

req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println("Error making request:", err)
return 0, err
}
defer resp.Body.Close()

var responseData []struct {
Chartdata []ChartData `json:"chartdata"`
}
err = json.NewDecoder(resp.Body).Decode(&responseData)
if err != nil {
log.Println("Error decoding JSON:", err)
return 0, err
}

var votingPowers []big.Int
for _, data := range responseData {
for _, chartData := range data.Chartdata {
stakeInt := big.NewInt(int64(chartData.Stake))
votingPowers = append(votingPowers, *stakeInt)
}
}

// Calculate total voting power
totalVotingPower := utils.CalculateTotalVotingPowerBigNums(votingPowers)

// Calculate Nakamoto coefficient
nakamotoCoefficient := utils.CalcNakamotoCoefficientBigNums51(totalVotingPower, votingPowers)

fmt.Println("Total voting power:", totalVotingPower)
fmt.Println("The Nakamoto coefficient for Cardano is", nakamotoCoefficient)

// Return Nakamoto coefficient
return nakamotoCoefficient, nil
}
7 changes: 6 additions & 1 deletion core/chains/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
AVAX Token = "AVAX"
BLD Token = "BLD"
BNB Token = "BNB"
ADA Token = "ADA"
ETH2 Token = "ETH2"
GRT Token = "GRT"
HBAR Token = "HBAR"
Expand Down Expand Up @@ -52,6 +53,8 @@ func (t Token) ChainName() string {
return "Agoric"
case BNB:
return "Binance"
case ADA:
return "Cardano"
case ETH2:
return "Ethereum Proof-of-Stake"
case GRT:
Expand Down Expand Up @@ -87,7 +90,7 @@ func (t Token) ChainName() string {
}
}

var Tokens = []Token{ATOM, AVAX, BLD, BNB, ETH2, GRT, HBAR, JUNO, MATIC, MINA, NEAR, OSMO, PLS, REGEN, RUNE, SOL, STARS, SUI, TIA}
var Tokens = []Token{ATOM, AVAX, BLD, BNB, ADA, ETH2, GRT, HBAR, JUNO, MATIC, MINA, NEAR, OSMO, PLS, REGEN, RUNE, SOL, STARS, SUI, TIA}

// NewState returns a new fresh state.
func NewState() ChainState {
Expand Down Expand Up @@ -129,6 +132,8 @@ func newValues(token Token) (int, error) {
currVal, err = Agoric()
case BNB:
currVal, err = Binance()
case ADA:
currVal, err = Cardano()
case ETH2:
currVal, err = Eth2()
case GRT:
Expand Down
18 changes: 18 additions & 0 deletions core/utils/calc_nakamoto_coefficient_big_nums.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,23 @@ func CalcNakamotoCoefficientBigNums(totalVotingPower *big.Int, votingPowers []bi
}
}

return nakamotoCoefficient
}

func CalcNakamotoCoefficientBigNums51(totalVotingPower *big.Int, votingPowers []big.Int) int {
thresholdPercent := big.NewFloat(0.51)
thresholdVal := new(big.Float).Mul(new(big.Float).SetInt(totalVotingPower), thresholdPercent)
cumulativeVal := big.NewFloat(0.00)
nakamotoCoefficient := 0

for _, vp := range votingPowers {
z := new(big.Float).Add(cumulativeVal, new(big.Float).SetInt(&vp))
cumulativeVal = z
nakamotoCoefficient += 1
if cumulativeVal.Cmp(thresholdVal) == +1 {
break
}
}

return nakamotoCoefficient
}