diff --git a/.gitignore b/.gitignore index f5f5405d..68406f98 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,9 @@ dependency-graph.png *.out *.synctex.gz contract_tests/* + +#Airdrop tool +balance.json +rewards.json +balancenft.json +.env \ No newline at end of file diff --git a/airdrop/akash.go b/airdrop/akash.go new file mode 100644 index 00000000..05b5ed77 --- /dev/null +++ b/airdrop/akash.go @@ -0,0 +1,145 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + "github.com/joho/godotenv" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func akash() ([]banktypes.Balance, []config.Reward) { + block_height := getLatestHeight(config.GetAkashConfig().RPC + "/status") + err := godotenv.Load() + if err != nil { + fmt.Println("Error loading env:", err) + panic("") + } + grpcAddr := config.GetAkashConfig().GRPCAddr + grpcConn, err := grpc.Dial(grpcAddr, grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec()))) + if err != nil { + panic(err) + } + defer grpcConn.Close() + stakingClient := stakingtypes.NewQueryClient(grpcConn) + + delegators := []stakingtypes.DelegationResponse{} + + validators := getValidators(stakingClient, block_height) + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + var header metadata.MD + delegationsResponse, _ := stakingClient.ValidatorDelegations( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, block_height), // Add metadata to request + &stakingtypes.QueryValidatorDelegationsRequest{ + ValidatorAddr: validator.OperatorAddress, + Pagination: &query.PageRequest{ + CountTotal: true, + Limit: LIMIT_PER_PAGE, + }, + }, + grpc.Header(&header), // Retrieve header from response + ) + total := delegationsResponse.Pagination.Total + fmt.Println("Response ", len(delegationsResponse.DelegationResponses)) + fmt.Println("Akash validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegationsResponse.DelegationResponses...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetAkashConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchAkashTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetAkashConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetAkashConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("Akash ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchAkashTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.AkashPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/bostrom.go b/airdrop/bostrom.go new file mode 100644 index 00000000..985758ee --- /dev/null +++ b/airdrop/bostrom.go @@ -0,0 +1,122 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + "strings" + + "github.com/eve-network/eve/airdrop/config" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func bostrom() ([]banktypes.Balance, []config.Reward) { + delegators := []stakingtypes.DelegationResponse{} + + rpc := config.GetBostromConfig().API + "/cosmos/staking/v1beta1/validators?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + validatorsResponse := fetchValidators(rpc) + validators := validatorsResponse.Validators + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + url := config.GetBostromConfig().API + "/cosmos/staking/v1beta1/validators/" + validator.OperatorAddress + "/delegations?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + delegations, total := fetchDelegations(url) + fmt.Println(validator.OperatorAddress) + fmt.Println("Response ", len(delegations)) + fmt.Println("Bostrom validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegations...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetBostromConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchBostromTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetBostromConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetBostromConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("bostrom ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchBostromTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.BostromPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + rawPrice := strings.Split(data.Token.USD.String(), "e-") + base := rawPrice[0] + power := rawPrice[1] + powerInt, _ := strconv.ParseUint(power, 10, 64) + baseDec, _ := math.LegacyNewDecFromStr(base) + tenDec, _ := math.LegacyNewDecFromStr("10") + tokenInUsd := baseDec.Quo(tenDec.Power(powerInt)) + return tokenInUsd +} diff --git a/airdrop/celestia.go b/airdrop/celestia.go new file mode 100644 index 00000000..71f7faa6 --- /dev/null +++ b/airdrop/celestia.go @@ -0,0 +1,132 @@ +package main + +// error max size response +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + "github.com/joho/godotenv" + "google.golang.org/grpc" + + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func celestia() ([]banktypes.Balance, []config.Reward) { + block_height := getLatestHeight(config.GetCelestiaConfig().RPC + "/status") + err := godotenv.Load() + if err != nil { + fmt.Println("Error loading env:", err) + panic("") + } + grpcAddr := config.GetCelestiaConfig().GRPCAddr + grpcConn, err := grpc.Dial(grpcAddr, grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec()))) + if err != nil { + panic(err) + } + defer grpcConn.Close() + stakingClient := stakingtypes.NewQueryClient(grpcConn) + + delegators := []stakingtypes.DelegationResponse{} + + validators := getValidators(stakingClient, block_height) + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + url := config.GetCelestiaConfig().API + "/cosmos/staking/v1beta1/validators/" + validator.OperatorAddress + "/delegations?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + delegations, total := fetchDelegations(url) + fmt.Println(validator.OperatorAddress) + fmt.Println("Response ", len(delegations)) + fmt.Println("Celestia validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegations...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetCelestiaConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchCelestiaTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetCelestiaConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetCelestiaConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("Celestia ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchCelestiaTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.CelestiaPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/composable.go b/airdrop/composable.go new file mode 100644 index 00000000..cb35e500 --- /dev/null +++ b/airdrop/composable.go @@ -0,0 +1,145 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + "github.com/joho/godotenv" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func composable() ([]banktypes.Balance, []config.Reward) { + block_height := getLatestHeight(config.GetComposableConfig().RPC + "/status") + err := godotenv.Load() + if err != nil { + fmt.Println("Error loading env:", err) + panic("") + } + grpcAddr := config.GetComposableConfig().GRPCAddr + grpcConn, err := grpc.Dial(grpcAddr, grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec()))) + if err != nil { + panic(err) + } + defer grpcConn.Close() + stakingClient := stakingtypes.NewQueryClient(grpcConn) + + delegators := []stakingtypes.DelegationResponse{} + + validators := getValidators(stakingClient, block_height) + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + var header metadata.MD + delegationsResponse, _ := stakingClient.ValidatorDelegations( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, block_height), // Add metadata to request + &stakingtypes.QueryValidatorDelegationsRequest{ + ValidatorAddr: validator.OperatorAddress, + Pagination: &query.PageRequest{ + CountTotal: true, + Limit: LIMIT_PER_PAGE, + }, + }, + grpc.Header(&header), // Retrieve header from response + ) + total := delegationsResponse.Pagination.Total + fmt.Println("Response ", len(delegationsResponse.DelegationResponses)) + fmt.Println("Composable validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegationsResponse.DelegationResponses...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetComposableConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchComposableTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetComposableConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetComposableConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("Composable ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchComposableTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.ComposablePrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/config/config.go b/airdrop/config/config.go new file mode 100644 index 00000000..217efec4 --- /dev/null +++ b/airdrop/config/config.go @@ -0,0 +1,146 @@ +package config + +func GetCosmosHubConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "cosmoshub-4", + GRPCAddr: "cosmos-grpc.publicnode.com:443", + AccountPrefix: "cosmos", + CoinId: "cosmos", + Percent: 10, + RPC: "https://cosmos-rpc.polkachu.com", + API: "https://cosmos-rest.publicnode.com", + } +} + +func GetComposableConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "centauri-1", + GRPCAddr: "composable-grpc.polkachu.com:22290", + AccountPrefix: "centauri", + Percent: 10, + CoinId: "picasso", + RPC: "https://composable-rpc.polkachu.com", + } +} + +func GetCelestiaConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "celestia", + GRPCAddr: "celestia-grpc.polkachu.com:11690", + AccountPrefix: "celestia", + Percent: 10, + CoinId: "celestia", + RPC: "https://celestia-rpc.polkachu.com", + API: "https://celestia-rest.publicnode.com", + } +} + +func GetSentinelConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "sentinelhub-2", + GRPCAddr: "sentinel-grpc.polkachu.com:23990", + AccountPrefix: "sent", + Percent: 10, + CoinId: "sentinel", + RPC: "https://sentinel-rpc.polkachu.com", + } +} + +func GetAkashConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "akashnet-2", + GRPCAddr: "akash-grpc.polkachu.com:12890", + AccountPrefix: "akash", + Percent: 10, + CoinId: "akash-network", + RPC: "https://akash-rpc.polkachu.com", + } +} + +func GetStargazeConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "stargaze-1", + GRPCAddr: "stargaze-grpc.polkachu.com:13790", + AccountPrefix: "stars", + Percent: 10, + CoinId: "stargaze", + RPC: "https://stargaze-rpc.polkachu.com", + API: "https://rest.stargaze-apis.com", + } +} + +func GetNeutronConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "neutron-1", + GRPCAddr: "neutron-grpc.polkachu.com:19190", + AccountPrefix: "neutron", + Percent: 10, + CoinId: "neutron-3", + RPC: "https://neutron-rpc.polkachu.com", + } +} + +func GetTerraConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "phoenix-1", + GRPCAddr: "terra-grpc.polkachu.com:11790", + AccountPrefix: "terra", + Percent: 10, + CoinId: "terra-luna-2", + RPC: "https://terra-rpc.polkachu.com", + API: "https://terra-rest.publicnode.com", + } +} + +func GetBostromConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "bostrom", + GRPCAddr: "grpc.cyber.bronbro.io:443", + AccountPrefix: "bostrom", + Percent: 10, + CoinId: "bostrom", + API: "https://lcd.bostrom.cybernode.ai", + } +} + +func GetTerracConfig() *ChainClientConfig { + return &ChainClientConfig{ + Key: "default", + ChainID: "columbus-5", + GRPCAddr: "terra-classic-grpc.publicnode.com:443", + AccountPrefix: "terra", + Percent: 10, + CoinId: "terra-luna", + API: "https://terra-classic-lcd.publicnode.com", + } +} + +func GetBadKidsConfig() *ChainClientConfig { + return &ChainClientConfig{ + ChainID: "stargaze-1", + Percent: 10, + } +} + +func GetCryptoniumConfig() *ChainClientConfig { + return &ChainClientConfig{ + ChainID: "stargaze-1", + Percent: 10, + } +} + +func GetMiladyConfig() *ChainClientConfig { + return &ChainClientConfig{ + ChainID: "0x1", + Percent: 10, + } +} diff --git a/airdrop/config/types.go b/airdrop/config/types.go new file mode 100644 index 00000000..63dddbd6 --- /dev/null +++ b/airdrop/config/types.go @@ -0,0 +1,171 @@ +package config + +import ( + "encoding/json" + + "cosmossdk.io/math" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +type ChainClientConfig struct { + Key string `json:"key" yaml:"key"` + ChainID string `json:"chain-id" yaml:"chain-id"` + GRPCAddr string `json:"grpc-addr" yaml:"grpc-addr"` + AccountPrefix string `json:"account-prefix" yaml:"account-prefix"` + Percent int `json:"percent" yaml:"percent"` + CoinId string `json:"coin-id" yaml:"coin-id"` + RPC string `json:"rpc" yaml:"rpc"` + API string `json:"api" yaml:"api"` +} + +type Reward struct { + Address string `json:"address"` + EveAddress string `json:"eve_address"` + Shares math.LegacyDec `json:"shares"` + Token math.LegacyDec `json:"tokens"` + EveAirdropToken math.LegacyDec `json:"eve"` + ChainId string `json:"chain"` +} + +type ComposablePrice struct { + Token Price `json:"picasso"` +} + +type AkashPrice struct { + Token Price `json:"akash-network"` +} + +type CelestiaPrice struct { + Token Price `json:"celestia"` +} + +type CosmosPrice struct { + Token Price `json:"cosmos"` +} + +type NeutronPrice struct { + Token Price `json:"neutron-3"` +} + +type SentinelPrice struct { + Token Price `json:"sentinel"` +} + +type StargazePrice struct { + Token Price `json:"stargaze"` +} + +type TerraPrice struct { + Token Price `json:"terra-luna-2"` +} + +type TerracPrice struct { + Token Price `json:"terra-luna"` +} + +type BostromPrice struct { + Token Price `json:"bostrom"` +} + +type Price struct { + USD json.Number `json:"usd"` +} + +type NodeResponse struct { + Id json.Number `json:"id"` + JsonRPC string `json:"jsonrpc"` + Result Result `json:"result"` +} + +type Result struct { + NodeInfo NodeInfo `json:"node_info"` + SyncInfo SyncInfo `json:"sync_info"` + ValidatorInfo ValidatorInfo `json:"validator_info"` +} + +type ( + NodeInfo struct{} + SyncInfo struct { + CatchingUp bool `json:"catching_up"` + EarlieastAppHash string `json:"earliest_app_hash"` + EarlieastBlockHash string `json:"earliest_block_hash"` + EarlieastBlockHeight string `json:"earliest_block_height"` + EarlieastBlockTime string `json:"earliest_block_time"` + LatestAppHash string `json:"latest_app_hash"` + LatestBlockHash string `json:"latest_block_hash"` + LatestBlockHeight string `json:"latest_block_height"` + LatestBlockTime string `json:"latest_block_time"` + } +) +type ValidatorInfo struct{} + +type ValidatorResponse struct { + Validators []Validator `json:"validators"` + Pagination Pagination `json:"pagination"` +} + +type Pagination struct { + // next_key is the key to be passed to PageRequest.key to + // query the next page most efficiently + NextKey []byte `protobuf:"bytes,1,opt,name=next_key,json=nextKey,proto3" json:"next_key,omitempty"` + // total is total number of results available if PageRequest.count_total + // was set, its value is undefined otherwise + Total string `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` +} + +type Validator struct { + // operator_address defines the address of the validator's operator; bech encoded in JSON. + OperatorAddress string `protobuf:"bytes,1,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty" yaml:"operator_address"` + // tokens define the delegated tokens (incl. self-delegation). + Tokens math.Int `protobuf:"bytes,5,opt,name=tokens,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"tokens"` + // delegator_shares defines total shares issued to a validator's delegators. + DelegatorShares math.LegacyDec `protobuf:"bytes,6,opt,name=delegator_shares,json=delegatorShares,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"delegator_shares" yaml:"delegator_shares"` +} + +type QueryValidatorDelegationsResponse struct { + DelegationResponses stakingtypes.DelegationResponses `protobuf:"bytes,1,rep,name=delegation_responses,json=delegationResponses,proto3,castrepeated=DelegationResponses" json:"delegation_responses"` + // pagination defines the pagination in the response. + Pagination Pagination `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +type Access struct { + Owner string `json:"owner"` + Approvals []string `json:"approvals"` +} +type Info struct { + TokenUri string `json:"token_uri"` +} +type Data struct { + Access Access `json:"access"` + Info Info `json:"info"` +} +type TokenInfoResponse struct { + Data Data `json:"data"` +} + +type TokenIds struct { + Token []string `json:"tokens"` +} +type TokenIdsResponse struct { + Data TokenIds `json:"data"` +} + +type NftHolder struct { + Address string + TokenId string +} + +type EthResult struct { + TokenId string `json:"token_id"` + TokenAddress string `json:"token_address"` + OwnerOf string `json:"owner_of"` +} + +type NftEthResponse struct { + Status string `json:"status"` + Page int `json:"page"` + PageSize int `json:"page_size"` + Cursor string `json:"cursor"` + Result []EthResult `json:"result"` +} diff --git a/airdrop/cosmos.go b/airdrop/cosmos.go new file mode 100644 index 00000000..28ff7ea2 --- /dev/null +++ b/airdrop/cosmos.go @@ -0,0 +1,116 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func cosmos() ([]banktypes.Balance, []config.Reward) { + delegators := []stakingtypes.DelegationResponse{} + + rpc := config.GetCosmosHubConfig().API + "/cosmos/staking/v1beta1/validators?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + validatorsResponse := fetchValidators(rpc) + validators := validatorsResponse.Validators + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + url := config.GetCosmosHubConfig().API + "/cosmos/staking/v1beta1/validators/" + validator.OperatorAddress + "/delegations?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + delegations, total := fetchDelegations(url) + fmt.Println(validator.OperatorAddress) + fmt.Println("Response ", len(delegations)) + fmt.Println("Cosmos validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegations...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetCosmosHubConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchCosmosTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetCosmosHubConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetCosmosHubConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("Cosmos ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchCosmosTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.CosmosPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/cosmosnft.go b/airdrop/cosmosnft.go new file mode 100644 index 00000000..9cb6a904 --- /dev/null +++ b/airdrop/cosmosnft.go @@ -0,0 +1,118 @@ +package main + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/eve-network/eve/airdrop/config" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func cosmosnft(contract string, percent int64) ([]banktypes.Balance, []config.Reward) { + tokenIds := fetchTokenIds(contract) + allEveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + testAmount, _ := math.LegacyNewDecFromStr("0") + eveAirdrop := (allEveAirdrop.MulInt64(percent)).QuoInt64(100).QuoInt(math.NewInt(int64(len(tokenIds)))) + fmt.Println("balance ", eveAirdrop) + for index, token := range tokenIds { + nftHolders := fetchTokenInfo(token, contract) + fmt.Println(index) + eveBech32Address := convertBech32Address(nftHolders.Address) + rewardInfo = append(rewardInfo, config.Reward{ + Address: nftHolders.Address, + EveAddress: eveBech32Address, + EveAirdropToken: eveAirdrop, + ChainId: config.GetBadKidsConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println(testAmount) + return balanceInfo, rewardInfo +} + +func fetchTokenInfo(token, contract string) config.NftHolder { + queryString := fmt.Sprintf(`{"all_nft_info":{"token_id":%s}}`, token) + encodedQuery := base64.StdEncoding.EncodeToString([]byte(queryString)) + apiUrl := config.GetStargazeConfig().API + "/cosmwasm/wasm/v1/contract/" + contract + "/smart/" + encodedQuery + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + var data config.TokenInfoResponse + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + return config.NftHolder{ + Address: data.Data.Access.Owner, + TokenId: token, + } +} + +func fetchTokenIds(contract string) []string { + // Make a GET request to the API + paginationKey := "0" + index := 0 + tokenIds := []string{} + for { + index += 1 + queryString := fmt.Sprintf(`{"all_tokens":{"limit":1000,"start_after":"%s"}}`, paginationKey) + encodedQuery := base64.StdEncoding.EncodeToString([]byte(queryString)) + apiUrl := config.GetStargazeConfig().API + "/cosmwasm/wasm/v1/contract/" + contract + "/smart/" + encodedQuery + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + var data config.TokenIdsResponse + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + tokenIds = append(tokenIds, data.Data.Token...) + if len(data.Data.Token) == 0 { + break + } else { + paginationKey = data.Data.Token[len(data.Data.Token)-1] + fmt.Println("pagination key:", paginationKey) + if len(paginationKey) == 0 { + break + } + } + } + + fmt.Println(len(tokenIds)) + return tokenIds +} diff --git a/airdrop/ethereumnft.go b/airdrop/ethereumnft.go new file mode 100644 index 00000000..2586973f --- /dev/null +++ b/airdrop/ethereumnft.go @@ -0,0 +1,139 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + + "github.com/ethereum/go-ethereum/common" + "github.com/eve-network/eve/airdrop/config" + "github.com/joho/godotenv" + + "cosmossdk.io/core/address" + "cosmossdk.io/math" + + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +const MILADY = "0x5af0d9827e0c53e4799bb226655a1de152a425a5" + +func ethereumnft() ([]banktypes.Balance, []config.Reward) { + nftOwners := fetchNftOwners() + allEveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + testAmount, _ := math.LegacyNewDecFromStr("0") + eveAirdrop := (allEveAirdrop.MulInt64(int64(config.GetMiladyConfig().Percent))).QuoInt64(100).QuoInt(math.NewInt(int64(len(nftOwners)))) + fmt.Println("balance ", eveAirdrop) + for index, owner := range nftOwners { + fmt.Println(index) + eveBech32Address := convertEvmAddress(owner.OwnerOf) + rewardInfo = append(rewardInfo, config.Reward{ + Address: owner.OwnerOf, + EveAddress: eveBech32Address, + EveAirdropToken: eveAirdrop, + ChainId: config.GetMiladyConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println(testAmount) + return balanceInfo, rewardInfo +} + +func constructMoralisUrl(cursor string) string { + return "https://deep-index.moralis.io/api/v2.2/nft/" + MILADY + "/owners?chain=eth&format=decimal&limit=100&cursor=" + cursor +} + +func fetchNftOwners() []config.EthResult { + err := godotenv.Load() + if err != nil { + fmt.Println("Error loading env:", err) + panic("") + } + API_KEY := os.Getenv("API_KEY") + pageCount := 0 + cursor := "" + nftOwners := []config.EthResult{} + for { + pageCount += 1 + fmt.Println("Page ", pageCount) + url := constructMoralisUrl(cursor) + req, _ := http.NewRequest("GET", url, nil) + + req.Header.Add("Accept", "application/json") + req.Header.Add("X-API-Key", API_KEY) + + res, _ := http.DefaultClient.Do(req) + + body, _ := io.ReadAll(res.Body) + var data config.NftEthResponse + + // Unmarshal the JSON byte slice into the defined struct + err := json.Unmarshal(body, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + defer res.Body.Close() + + nftOwners = append(nftOwners, data.Result...) + if data.Cursor == "" { + break + } else { + cursor = data.Cursor + } + } + return nftOwners +} + +func convertEvmAddress(evmAddress string) string { + addr := common.HexToAddress(evmAddress) + accCodec := addresscodec.NewBech32Codec("eve") + eveAddress, err := StringFromEthAddress(accCodec, addr) + if err != nil { + fmt.Println("err ", err) + } + return eveAddress +} + +// EthAddressFromString converts a Cosmos SDK address string to an Ethereum `Address`. +func EthAddressFromString(codec address.Codec, addr string) (common.Address, error) { + bz, err := codec.StringToBytes(addr) + if err != nil { + return common.Address{}, err + } + return common.BytesToAddress(bz), nil +} + +// MustEthAddressFromString converts a Cosmos SDK address string to an Ethereum `Address`. It +// panics if the conversion fails. +func MustEthAddressFromString(codec address.Codec, addr string) common.Address { + address, err := EthAddressFromString(codec, addr) + if err != nil { + panic(err) + } + return address +} + +// StringFromEthAddress converts an Ethereum `Address` to a Cosmos SDK address string. +func StringFromEthAddress(codec address.Codec, ethAddress common.Address) (string, error) { + return codec.BytesToString(ethAddress.Bytes()) +} + +// MustStringFromEthAddress converts an Ethereum `Address` to a Cosmos SDK address string. It +// panics if the conversion fails. +func MustStringFromEthAddress(codec address.Codec, ethAddress common.Address) string { + addr, err := StringFromEthAddress(codec, ethAddress) + if err != nil { + panic(err) + } + return addr +} diff --git a/airdrop/main.go b/airdrop/main.go new file mode 100644 index 00000000..305c899f --- /dev/null +++ b/airdrop/main.go @@ -0,0 +1,246 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// got to export genesis state from neutron and bostrom chain + +const ( + EVE_AIRDROP = "1000000000" // 1,000,000,000 + LIMIT_PER_PAGE = 100000000 + BADKIDS = "stars19jq6mj84cnt9p7sagjxqf8hxtczwc8wlpuwe4sh62w45aheseues57n420" + CRYPTONIUM = "stars1g2ptrqnky5pu70r3g584zpk76cwqplyc63e8apwayau6l3jr8c0sp9q45u" + API_COINGECKO = "https://api.coingecko.com/api/v3/simple/price?ids=" +) + +func getValidators(stakingClient stakingtypes.QueryClient, block_height string) []stakingtypes.Validator { + // Get validator + var header metadata.MD + var totalValidatorsResponse *stakingtypes.QueryValidatorsResponse + totalValidatorsResponse, err := stakingClient.Validators( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, block_height), // Add metadata to request + &stakingtypes.QueryValidatorsRequest{ + Pagination: &query.PageRequest{ + Limit: LIMIT_PER_PAGE, + }, + }, + grpc.Header(&header), + ) + fmt.Println(err) + validatorsInfo := totalValidatorsResponse.Validators + return validatorsInfo +} + +func main() { + balanceAkashInfo, _ := akash() + akashLength := len(balanceAkashInfo) + + balanceBostromInfo, _ := bostrom() + bostromLength := len(balanceBostromInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceBostromInfo...) + + balanceCelestiaInfo, _ := celestia() + celestiaLength := len(balanceCelestiaInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceCelestiaInfo...) + + balanceComposableInfo, _ := composable() + composableLength := len(balanceComposableInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceComposableInfo...) + + balanceCosmosInfo, _ := cosmos() + cosmosLength := len(balanceCosmosInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceCosmosInfo...) + + balanceNeutronInfo, _ := neutron() + neutronLength := len(balanceNeutronInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceNeutronInfo...) + + balanceSentinelInfo, _ := sentinel() + sentinelLength := len(balanceSentinelInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceSentinelInfo...) + + balanceStargazeInfo, _ := stargaze() + stargazeLength := len(balanceStargazeInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceStargazeInfo...) + + balanceTerraInfo, _ := terra() + terraLength := len(balanceTerraInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceTerraInfo...) + + balanceTerracInfo, _ := terrac() + terracLength := len(balanceTerracInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceTerracInfo...) + + balanceBadKidsInfo, _ := cosmosnft(BADKIDS, int64(config.GetBadKidsConfig().Percent)) + badkidsLength := len(balanceBadKidsInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceBadKidsInfo...) + + balanceCryptoniumInfo, _ := cosmosnft(CRYPTONIUM, int64(config.GetCryptoniumConfig().Percent)) + cryptoniumLength := len(balanceCryptoniumInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceCryptoniumInfo...) + + // need set coin type on Eve + balanceMiladyInfo, _ := ethereumnft() + miladyLength := len(balanceMiladyInfo) + balanceAkashInfo = append(balanceAkashInfo, balanceMiladyInfo...) + + total := akashLength + bostromLength + celestiaLength + composableLength + cosmosLength + neutronLength + sentinelLength + stargazeLength + terraLength + terracLength + badkidsLength + cryptoniumLength + miladyLength + fmt.Println("total: ", total) + fmt.Println(len(balanceAkashInfo)) + + airdropMap := make(map[string]int) + for _, info := range balanceAkashInfo { + amount := airdropMap[info.Address] + airdropMap[info.Address] = amount + int(info.Coins.AmountOf("eve").Int64()) + } + + balanceInfo := []banktypes.Balance{} + checkBalance := 0 + for address, amount := range airdropMap { + checkBalance += amount + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", math.NewInt(int64(amount)))), + }) + } + + fmt.Println("Check balance: ", checkBalance) + + // // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardComposableInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + _ = os.WriteFile("balance.json", fileBalance, 0o600) +} + +func findValidatorInfo(validators []stakingtypes.Validator, address string) int { + for key, v := range validators { + if v.OperatorAddress == address { + return key + } + } + return -1 +} + +func getLatestHeight(apiUrl string) string { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + // Print the response body + var data config.NodeResponse + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + fmt.Println("Block height: ", data.Result.SyncInfo.LatestBlockHeight) + return data.Result.SyncInfo.LatestBlockHeight +} + +func convertBech32Address(otherChainAddress string) string { + _, bz, _ := bech32.DecodeAndConvert(otherChainAddress) + newBech32DelAddr, _ := bech32.ConvertAndEncode("eve", bz) + return newBech32DelAddr +} + +func fetchValidators(rpcUrl string) config.ValidatorResponse { + // Make a GET request to the API + response, err := http.Get(rpcUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.ValidatorResponse + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + fmt.Println(data.Pagination.Total) + return data +} + +func findValidatorInfoCustomType(validators []config.Validator, address string) int { + for key, v := range validators { + if v.OperatorAddress == address { + return key + } + } + return -1 +} + +func fetchDelegations(rpcUrl string) (stakingtypes.DelegationResponses, uint64) { + // Make a GET request to the API + response, err := http.Get(rpcUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.QueryValidatorDelegationsResponse + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + fmt.Println(data.Pagination.Total) + total, _ := strconv.ParseUint(data.Pagination.Total, 10, 64) + return data.DelegationResponses, total +} diff --git a/airdrop/neutron.go b/airdrop/neutron.go new file mode 100644 index 00000000..ed77c43a --- /dev/null +++ b/airdrop/neutron.go @@ -0,0 +1,147 @@ +package main + +// code = Unimplemented desc = unknown service cosmos.staking.v1beta1.Query +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/eve-network/eve/airdrop/config" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func neutron() ([]banktypes.Balance, []config.Reward) { + block_height := getLatestHeight(config.GetNeutronConfig().RPC + "/status") + addresses, total := fetchBalance(block_height) + fmt.Println("Response ", len(addresses)) + fmt.Println("Total ", total) + + usd, _ := math.LegacyNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetNeutronConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchNeutronTokenPrice(apiUrl) + tokenIn20Usd := usd.Quo(tokenInUsd) + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenBalance, _ := math.NewIntFromString("0") + for _, address := range addresses { + if math.LegacyNewDecFromInt(address.Balance.Amount).LT(tokenIn20Usd) { + continue + } + totalTokenBalance = totalTokenBalance.Add(address.Balance.Amount) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, address := range addresses { + if math.LegacyNewDecFromInt(address.Balance.Amount).LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetNeutronConfig().Percent))).QuoInt64(100).MulInt(address.Balance.Amount).QuoInt(totalTokenBalance) + eveBech32Address := convertBech32Address(address.Address) + rewardInfo = append(rewardInfo, config.Reward{ + Address: address.Address, + EveAddress: eveBech32Address, + Token: address.Balance.Amount.ToLegacyDec(), + EveAirdropToken: eveAirdrop, + ChainId: config.GetNeutronConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("Neutron ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchBalance(block_height string) ([]*banktypes.DenomOwner, uint64) { + grpcAddr := config.GetNeutronConfig().GRPCAddr + grpcConn, err := grpc.Dial(grpcAddr, grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec()))) + if err != nil { + panic(err) + } + defer grpcConn.Close() + bankClient := banktypes.NewQueryClient(grpcConn) + var header metadata.MD + var addresses *banktypes.QueryDenomOwnersResponse // QueryValidatorDelegationsResponse + var paginationKey []byte + addressInfo := []*banktypes.DenomOwner{} + step := 5000 + total := uint64(0) + // Fetch addresses, 5000 at a time + i := 0 + for { + i += 1 + fmt.Println("Fetching addresses", step*i, "to", step*(i+1)) + addresses, err = bankClient.DenomOwners( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, block_height), // Add metadata to request + &banktypes.QueryDenomOwnersRequest{ + Denom: "untrn", + Pagination: &query.PageRequest{ + Limit: uint64(step), + Key: paginationKey, + CountTotal: true, + }, + }, + grpc.Header(&header), // Retrieve header from response + ) + fmt.Println("err: ", err) + if total != 0 { + total = addresses.Pagination.Total + } + addressInfo = append(addressInfo, addresses.DenomOwners...) + paginationKey = addresses.Pagination.NextKey + if len(paginationKey) == 0 { + break + } + } + return addressInfo, total +} + +func fetchNeutronTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.NeutronPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/sentinel.go b/airdrop/sentinel.go new file mode 100644 index 00000000..01ca0a63 --- /dev/null +++ b/airdrop/sentinel.go @@ -0,0 +1,145 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + "github.com/joho/godotenv" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func sentinel() ([]banktypes.Balance, []config.Reward) { + block_height := getLatestHeight(config.GetSentinelConfig().RPC + "/status") + err := godotenv.Load() + if err != nil { + fmt.Println("Error loading env:", err) + panic("") + } + grpcAddr := config.GetSentinelConfig().GRPCAddr + grpcConn, err := grpc.Dial(grpcAddr, grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec()))) + if err != nil { + panic(err) + } + defer grpcConn.Close() + stakingClient := stakingtypes.NewQueryClient(grpcConn) + + delegators := []stakingtypes.DelegationResponse{} + + validators := getValidators(stakingClient, block_height) + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + var header metadata.MD + delegationsResponse, _ := stakingClient.ValidatorDelegations( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, block_height), // Add metadata to request + &stakingtypes.QueryValidatorDelegationsRequest{ + ValidatorAddr: validator.OperatorAddress, + Pagination: &query.PageRequest{ + CountTotal: true, + Limit: LIMIT_PER_PAGE, + }, + }, + grpc.Header(&header), // Retrieve header from response + ) + total := delegationsResponse.Pagination.Total + fmt.Println("Response ", len(delegationsResponse.DelegationResponses)) + fmt.Println("Sentinel validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegationsResponse.DelegationResponses...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetSentinelConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchSentinelTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetSentinelConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetSentinelConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("Sentinel ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchSentinelTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.SentinelPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/stargaze.go b/airdrop/stargaze.go new file mode 100644 index 00000000..8cda6fd3 --- /dev/null +++ b/airdrop/stargaze.go @@ -0,0 +1,145 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + "github.com/joho/godotenv" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/query" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func stargaze() ([]banktypes.Balance, []config.Reward) { + block_height := getLatestHeight(config.GetStargazeConfig().RPC + "/status") + err := godotenv.Load() + if err != nil { + fmt.Println("Error loading env:", err) + panic("") + } + grpcAddr := config.GetStargazeConfig().GRPCAddr + grpcConn, err := grpc.Dial(grpcAddr, grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec()))) + if err != nil { + panic(err) + } + defer grpcConn.Close() + stakingClient := stakingtypes.NewQueryClient(grpcConn) + + delegators := []stakingtypes.DelegationResponse{} + + validators := getValidators(stakingClient, block_height) + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + var header metadata.MD + delegationsResponse, _ := stakingClient.ValidatorDelegations( + metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, block_height), // Add metadata to request + &stakingtypes.QueryValidatorDelegationsRequest{ + ValidatorAddr: validator.OperatorAddress, + Pagination: &query.PageRequest{ + CountTotal: true, + Limit: LIMIT_PER_PAGE, + }, + }, + grpc.Header(&header), // Retrieve header from response + ) + total := delegationsResponse.Pagination.Total + fmt.Println("Response ", len(delegationsResponse.DelegationResponses)) + fmt.Println("Stargaze validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegationsResponse.DelegationResponses...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetStargazeConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchStargazeTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfo(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetStargazeConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetStargazeConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("stargaze ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchStargazeTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.StargazePrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/terra.go b/airdrop/terra.go new file mode 100644 index 00000000..964e3632 --- /dev/null +++ b/airdrop/terra.go @@ -0,0 +1,116 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func terra() ([]banktypes.Balance, []config.Reward) { + delegators := []stakingtypes.DelegationResponse{} + + rpc := config.GetTerraConfig().API + "/cosmos/staking/v1beta1/validators?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + validatorsResponse := fetchValidators(rpc) + validators := validatorsResponse.Validators + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + url := config.GetTerraConfig().API + "/cosmos/staking/v1beta1/validators/" + validator.OperatorAddress + "/delegations?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + delegations, total := fetchDelegations(url) + fmt.Println(validator.OperatorAddress) + fmt.Println("Response ", len(delegations)) + fmt.Println("Terra alidator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegations...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetTerraConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchTerraTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetTerraConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetTerraConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("terra ", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchTerraTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.TerraPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/airdrop/terrac.go b/airdrop/terrac.go new file mode 100644 index 00000000..4b6d75c7 --- /dev/null +++ b/airdrop/terrac.go @@ -0,0 +1,116 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/eve-network/eve/airdrop/config" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func terrac() ([]banktypes.Balance, []config.Reward) { + delegators := []stakingtypes.DelegationResponse{} + + rpc := config.GetTerracConfig().API + "/cosmos/staking/v1beta1/validators?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + validatorsResponse := fetchValidators(rpc) + validators := validatorsResponse.Validators + fmt.Println("Validators: ", len(validators)) + for validatorIndex, validator := range validators { + url := config.GetTerracConfig().API + "/cosmos/staking/v1beta1/validators/" + validator.OperatorAddress + "/delegations?pagination.limit=" + strconv.Itoa(LIMIT_PER_PAGE) + "&pagination.count_total=true" + delegations, total := fetchDelegations(url) + fmt.Println(validator.OperatorAddress) + fmt.Println("Response ", len(delegations)) + fmt.Println("Terrac validator "+strconv.Itoa(validatorIndex)+" ", total) + delegators = append(delegators, delegations...) + } + + usd := math.LegacyMustNewDecFromStr("20") + + apiUrl := API_COINGECKO + config.GetTerracConfig().CoinId + "&vs_currencies=usd" + tokenInUsd := fetchTerracTokenPrice(apiUrl) + tokenIn20Usd := usd.QuoTruncate(tokenInUsd) + + rewardInfo := []config.Reward{} + balanceInfo := []banktypes.Balance{} + + totalTokenDelegate := math.LegacyMustNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + totalTokenDelegate = totalTokenDelegate.Add(token) + } + eveAirdrop := math.LegacyMustNewDecFromStr(EVE_AIRDROP) + testAmount, _ := math.LegacyNewDecFromStr("0") + for _, delegator := range delegators { + validatorIndex := findValidatorInfoCustomType(validators, delegator.Delegation.ValidatorAddress) + validatorInfo := validators[validatorIndex] + token := (delegator.Delegation.Shares.MulInt(validatorInfo.Tokens)).QuoTruncate(validatorInfo.DelegatorShares) + if token.LT(tokenIn20Usd) { + continue + } + eveAirdrop := (eveAirdrop.MulInt64(int64(config.GetTerracConfig().Percent))).QuoInt64(100).Mul(token).QuoTruncate(totalTokenDelegate) + eveBech32Address := convertBech32Address(delegator.Delegation.DelegatorAddress) + rewardInfo = append(rewardInfo, config.Reward{ + Address: delegator.Delegation.DelegatorAddress, + EveAddress: eveBech32Address, + Shares: delegator.Delegation.Shares, + Token: token, + EveAirdropToken: eveAirdrop, + ChainId: config.GetTerracConfig().ChainID, + }) + testAmount = eveAirdrop.Add(testAmount) + balanceInfo = append(balanceInfo, banktypes.Balance{ + Address: eveBech32Address, + Coins: sdk.NewCoins(sdk.NewCoin("eve", eveAirdrop.TruncateInt())), + }) + } + fmt.Println("terrac", testAmount) + // Write delegations to file + // fileForDebug, _ := json.MarshalIndent(rewardInfo, "", " ") + // _ = os.WriteFile("rewards.json", fileForDebug, 0644) + + // fileBalance, _ := json.MarshalIndent(balanceInfo, "", " ") + // _ = os.WriteFile("balance.json", fileBalance, 0644) + return balanceInfo, rewardInfo +} + +func fetchTerracTokenPrice(apiUrl string) math.LegacyDec { + // Make a GET request to the API + response, err := http.Get(apiUrl) //nolint + if err != nil { + fmt.Println("Error making GET request:", err) + panic("") + } + defer response.Body.Close() + + // Read the response body + responseBody, err := io.ReadAll(response.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + panic("") + } + + var data config.TerracPrice + + // Unmarshal the JSON byte slice into the defined struct + err = json.Unmarshal(responseBody, &data) + if err != nil { + fmt.Println("Error unmarshalling JSON:", err) + panic("") + } + + tokenInUsd := math.LegacyMustNewDecFromStr(data.Token.USD.String()) + return tokenInUsd +} diff --git a/go.mod b/go.mod index a7d60b4b..6939d982 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/grpc v1.62.1 // indirect + google.golang.org/grpc v1.62.1 gopkg.in/yaml.v2 v2.4.0 // indirect ) @@ -51,6 +51,8 @@ require ( github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/cosmos/ibc-go/modules/light-clients/08-wasm v0.0.0-20240314094315-e89424c5bf2e github.com/cosmos/ibc-go/v8 v8.1.1 + github.com/ethereum/go-ethereum v1.13.14 + github.com/joho/godotenv v1.5.1 github.com/osmosis-labs/tokenfactory v0.0.0-20240310155926-981fbeb0fe42 github.com/spf13/viper v1.18.2 ) @@ -73,7 +75,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.8.0 // indirect + github.com/bits-and-blooms/bitset v1.11.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect @@ -125,7 +127,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -140,6 +142,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect @@ -163,6 +166,7 @@ require ( github.com/mtibben/percent v0.2.1 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect + github.com/onsi/gomega v1.30.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect @@ -172,7 +176,7 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.8.3 // indirect + github.com/rs/cors v1.10.1 // indirect github.com/rs/zerolog v1.32.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect diff --git a/go.sum b/go.sum index bfd894c8..ebc7b6c1 100644 --- a/go.sum +++ b/go.sum @@ -278,8 +278,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= -github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.11.0 h1:RMyy2mBBShArUAhfVRZJ2xyBO58KCBCtZFShw3umo6k= +github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= @@ -442,6 +442,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/ethereum/go-ethereum v1.13.14 h1:EwiY3FZP94derMCIam1iW4HFVrSgIcpsu0HwTQtm6CQ= +github.com/ethereum/go-ethereum v1.13.14/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= @@ -631,8 +633,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -691,6 +693,8 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -716,6 +720,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -840,8 +846,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -934,8 +940,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=