diff --git a/README.md b/README.md index e622469..93c2c8b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ we simply calculate: nakamoto-coefficient: no of validators controlling 33% of the total network stake ``` +Note that the threshold may be different for some blockchains, for example, 50%. So, I would suggest users to understand the context, cross-verify and examine the results. For any feedback, please join this [discord](https://discord.gg/Una8qmFg). ### Programming Languages @@ -61,6 +62,7 @@ NOTE: You can get your API Key by signing up [here](https://www.validators.app/u 20. [MultiversX](https://multiversx.com/) 21. [Polkadot](https://polkadot.network/) 22. [Aptos](https://aptosfoundation.org/) +23. [Cardano](https://cardano.org/) ### Notes diff --git a/core/chains/cardano.go b/core/chains/cardano.go new file mode 100644 index 0000000..0415780 --- /dev/null +++ b/core/chains/cardano.go @@ -0,0 +1,75 @@ +package chains + +import ( + "encoding/json" + "fmt" + "log" + "math/big" + "net/http" + "sort" + + utils "github.com/xenowits/nakamoto-coefficient-calculator/core/utils" +) + +type CardanoResponse struct { + Label string `json:"label"` + Class string `json:"class"` + Epoch int `json:"epoch"` + Stake float64 `json:"stake"` +} + +func Cardano() (int, error) { + url := "https://www.balanceanalytics.io/api/mavdata.json" + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + log.Println("Error creating request:", err) + return 0, err + } + + 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 { + CardanoResponse []CardanoResponse `json:"mav_data"` + } + 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 _, mavData := range data.CardanoResponse { + stakeInt := big.NewInt(int64(mavData.Stake)) + votingPowers = append(votingPowers, *stakeInt) + } + } + + // need to sort the powers in descending order since they are in random order + sort.Slice(votingPowers, func(i, j int) bool { + res := (&votingPowers[i]).Cmp(&votingPowers[j]) + if res == 1 { + return true + } + return false + }) + + // 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 +} diff --git a/core/chains/chain.go b/core/chains/chain.go index fe9f195..9d59722 100644 --- a/core/chains/chain.go +++ b/core/chains/chain.go @@ -21,6 +21,7 @@ type ChainState map[Token]Chain // Append new chains in alphabetical order only. const ( + ADA Token = "ADA" ALGO Token = "ALGO" APT Token = "APT" ATOM Token = "ATOM" @@ -48,6 +49,8 @@ const ( // ChainName returns the name of the chain given the token name. func (t Token) ChainName() string { switch t { + case ADA: + return "Cardano" case ALGO: return "Algo" case APT: @@ -97,7 +100,7 @@ func (t Token) ChainName() string { } } -var Tokens = []Token{ALGO, APT, ATOM, AVAX, BLD, BNB, DOT, EGLD, GRT, HBAR, JUNO, MATIC, MINA, NEAR, OSMO, PLS, REGEN, RUNE, SOL, STARS, SUI, TIA} +var Tokens = []Token{ADA, ALGO, APT, ATOM, AVAX, BLD, BNB, DOT, EGLD, GRT, HBAR, JUNO, MATIC, MINA, NEAR, OSMO, PLS, REGEN, RUNE, SOL, STARS, SUI, TIA} // NewState returns a new fresh state. func NewState() ChainState { @@ -131,6 +134,8 @@ func newValues(token Token) (int, error) { ) switch token { + case ADA: + currVal, err = Cardano() case ALGO: currVal, err = Algorand() case APT: diff --git a/core/utils/calc_nakamoto_coefficient_big_nums.go b/core/utils/calc_nakamoto_coefficient_big_nums.go index e720a06..c344c00 100644 --- a/core/utils/calc_nakamoto_coefficient_big_nums.go +++ b/core/utils/calc_nakamoto_coefficient_big_nums.go @@ -26,3 +26,21 @@ func CalcNakamotoCoefficientBigNums(totalVotingPower *big.Int, votingPowers []bi return nakamotoCoefficient } + +func CalcNakamotoCoefficientBigNums51(totalVotingPower *big.Int, votingPowers []big.Int) int { + thresholdPercent := big.NewFloat(0.50) + 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 +} \ No newline at end of file