Skip to content

Commit

Permalink
Add Cardano chain (#43)
Browse files Browse the repository at this point in the history
**Description**: added Cardano chain.

**Ticket(s)**: #1 (closed but should be the actual one) and #16.

**Contribution Details**:
I used the [Cexplorer APIs](https://cexplorer.io/devs) to get the list
of pools and staked amount.

From Cexplorer, the Nakamoto coefficient is [something like
36](https://cexplorer.io/nakamoto). In the PR, anyway, the value you
will get is expected to be higher (the last time I tried was 112) as the
single pools are used instead of the
[groups](https://cexplorer.io/groups); that is what they used (confirmed
by an admin on Discord).
  • Loading branch information
FilippoScaramuzza authored Dec 28, 2024
1 parent f8d764e commit 67b8b7c
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 24 deletions.
48 changes: 25 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -39,29 +40,30 @@ NOTE: You can get your API Key by signing up [here](https://www.validators.app/u

### Chains currently supported

1. [Cosmos](https://cosmos.network/)
2. [Polygon](https://polygon.technology/)
3. [BNB Smart Chain](https://www.bnbchain.org)
4. [Osmosis Zone](https://osmosis.zone/)
5. [Mina](https://minaprotocol.com/)
6. [Solana](https://solana.com/)
7. [Avalanche](https://www.avax.network/)
8. [Terra](https://www.terra.money/)
9. [Graph Protocol](https://thegraph.com/)
10. [Thorchain](https://www.thorchain.com/)
11. [Near](https://near.org/)
12. [Juno](https://www.junonetwork.io/)
13. [Regen Network](https://www.regen.network/)
14. [Agoric](https://agoric.com/)
15. [Stargaze](https://stargaze.zone/)
16. [Hedera](https://hedera.com/)
17. [Sui](https://sui.io/)
18. [Pulsechain](https://pulsechain.com/)
19. [Celestia](https://celestia.org/)
20. [MultiversX](https://multiversx.com/)
21. [Polkadot](https://polkadot.network/)
22. [Aptos](https://aptosfoundation.org/)
23. [Sei](https://sei.io/)
1. [Agoric](https://agoric.com/)
2. [Aptos](https://aptosfoundation.org/)
3. [Avalanche](https://www.avax.network/)
4. [BNB Smart Chain](https://www.bnbchain.org)
5. [Cardano](https://cardano.org/)
6. [Celestia](https://celestia.org/)
7. [Cosmos](https://cosmos.network/)
8. [Graph Protocol](https://thegraph.com/)
9. [Hedera](https://hedera.com/)
10. [Juno](https://www.junonetwork.io/)
11. [Mina](https://minaprotocol.com/)
12. [MultiversX](https://multiversx.com/)
13. [Near](https://near.org/)
14. [Osmosis Zone](https://osmosis.zone/)
15. [Polygon](https://polygon.technology/)
16. [Polkadot](https://polkadot.network/)
17. [Pulsechain](https://pulsechain.com/)
18. [Regen Network](https://www.regen.network/)
19. [Sei](https://sei.io/)
20. [Solana](https://solana.com/)
21. [Stargaze](https://stargaze.zone/)
22. [Sui](https://sui.io/)
23. [Terra](https://www.terra.money/)
24. [Thorchain](https://www.thorchain.com/)

### Notes

Expand Down
69 changes: 69 additions & 0 deletions core/chains/cardano.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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 {
ApiData []CardanoResponse `json:"api_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.ApiData {
stakeInt := big.NewInt(int64(data.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 {
return votingPowers[i].Cmp(&votingPowers[j]) > 0
})

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

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

fmt.Println("The total voting power for Cardano is: ", 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 @@ -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"
Expand Down Expand Up @@ -49,6 +50,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:
Expand Down Expand Up @@ -100,7 +103,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, SEI, 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, SEI, SOL, STARS, SUI, TIA}

// NewState returns a new fresh state.
func NewState() ChainState {
Expand Down Expand Up @@ -136,6 +139,8 @@ func newValues(token Token) (int, error) {
log.Printf("Calculating Nakamoto coefficient for %s", token.ChainName())

switch token {
case ADA:
currVal, err = Cardano()
case ALGO:
currVal, err = Algorand()
case APT:
Expand Down
21 changes: 21 additions & 0 deletions core/utils/calc_nakamoto_coefficient_big_nums.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,24 @@ func CalcNakamotoCoefficientBigNums(totalVotingPower *big.Int, votingPowers []bi

return nakamotoCoefficient
}

// CalcNakamotoCoefficientBigNums51 calculates the Nakamoto Coefficient for a given voting power distribution.
// This function is used for chains that require at least > 50% of the total voting power to be controlled,
// that therefore cannot use the 33% threshold with the CalcNakamotoCoefficientBigNums function.
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
}

0 comments on commit 67b8b7c

Please sign in to comment.