github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/newcmd/node/nodereward.go (about) 1 // Copyright (c) 2022 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package node 7 8 import ( 9 "context" 10 "math/big" 11 12 "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" 13 "github.com/iotexproject/iotex-proto/golang/iotexapi" 14 "github.com/pkg/errors" 15 "github.com/spf13/cobra" 16 "google.golang.org/grpc/codes" 17 "google.golang.org/grpc/status" 18 19 "github.com/iotexproject/iotex-core/ioctl" 20 "github.com/iotexproject/iotex-core/ioctl/config" 21 "github.com/iotexproject/iotex-core/ioctl/util" 22 ) 23 24 // Multi-language support 25 var ( 26 _rewardCmdUses = map[config.Language]string{ 27 config.English: "reward unclaimed|pool [ALIAS|DELEGATE_ADDRESS]", 28 config.Chinese: "reward 未支取|奖金池 [别名|委托地址]", 29 } 30 _rewardCmdShorts = map[config.Language]string{ 31 config.English: "Query rewards", 32 config.Chinese: "查询奖励", 33 } 34 _rewardPoolLong = map[config.Language]string{ 35 config.English: "ioctl node reward pool returns unclaimed and available Rewards in fund pool.\nTotalUnclaimed is the amount of all delegates that have been issued but are not claimed;\nTotalAvailable is the amount of balance that has not been issued to anyone.\n\nioctl node reward unclaimed [ALIAS|DELEGATE_ADDRESS] returns unclaimed rewards of a specific delegate.", 36 config.Chinese: "ioctl node reward 返回奖金池中的未支取奖励和可获取的奖励. TotalUnclaimed是所有代表已被发放但未支取的奖励的总和; TotalAvailable 是奖金池中未被发放的奖励的总和.\n\nioctl node [ALIAS|DELEGATE_ADDRESS] 返回特定代表的已被发放但未支取的奖励.", 37 } 38 ) 39 40 // NewNodeRewardCmd represents the node reward command 41 func NewNodeRewardCmd(client ioctl.Client) *cobra.Command { 42 use, _ := client.SelectTranslation(_rewardCmdUses) 43 short, _ := client.SelectTranslation(_rewardCmdShorts) 44 long, _ := client.SelectTranslation(_rewardPoolLong) 45 46 return &cobra.Command{ 47 Use: use, 48 Short: short, 49 Args: cobra.RangeArgs(1, 2), 50 Long: long, 51 RunE: func(cmd *cobra.Command, args []string) error { 52 cmd.SilenceUsage = true 53 switch args[0] { 54 case "pool": 55 if len(args) != 1 { 56 return errors.New("wrong number of arg(s) for ioctl node reward pool command. \nRun 'ioctl node reward --help' for usage") 57 } 58 totalUnclaimed, totalAvailable, totalBalance, err := rewardPool(client) 59 if err != nil { 60 return err 61 } 62 cmd.Printf("Total Unclaimed:\t %s IOTX\nTotal Available:\t %s IOTX\nTotal Balance:\t\t %s IOTX\n", 63 totalUnclaimed, totalAvailable, totalBalance) 64 case "unclaimed": 65 if len(args) != 2 { 66 return errors.New("wrong number of arg(s) for ioctl node reward unclaimed [ALIAS|DELEGATE_ADDRESS] command. \nRun 'ioctl node reward --help' for usage") 67 } 68 address, reward, err := reward(client, args[1]) 69 if err != nil { 70 return err 71 } 72 cmd.Printf("%s: %s IOTX\n", address, reward) 73 default: 74 return errors.New("unknown command. \nRun 'ioctl node reward --help' for usage") 75 } 76 return nil 77 }, 78 } 79 } 80 81 func rewardPool(client ioctl.Client) (string, string, string, error) { 82 apiClient, err := client.APIServiceClient() 83 if err != nil { 84 return "", "", "", err 85 } 86 ctx := context.Background() 87 jwtMD, err := util.JwtAuth() 88 if err == nil { 89 ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) 90 } 91 response, err := apiClient.ReadState( 92 ctx, 93 &iotexapi.ReadStateRequest{ 94 ProtocolID: []byte("rewarding"), 95 MethodName: []byte("AvailableBalance"), 96 }, 97 ) 98 if err != nil { 99 if sta, ok := status.FromError(err); ok { 100 if sta.Code() == codes.Unavailable { 101 return "", "", "", ioctl.ErrInvalidEndpointOrInsecure 102 } 103 return "", "", "", errors.New(sta.Message()) 104 } 105 return "", "", "", errors.Wrap(err, "failed to invoke ReadState api") 106 } 107 108 availableRewardRau, ok := new(big.Int).SetString(string(response.Data), 10) 109 if !ok { 110 return "", "", "", errors.New("failed to convert string into big int") 111 } 112 113 response, err = apiClient.ReadState( 114 context.Background(), 115 &iotexapi.ReadStateRequest{ 116 ProtocolID: []byte("rewarding"), 117 MethodName: []byte("TotalBalance"), 118 }, 119 ) 120 if err != nil { 121 if sta, ok := status.FromError(err); ok { 122 if sta.Code() == codes.Unavailable { 123 return "", "", "", ioctl.ErrInvalidEndpointOrInsecure 124 } 125 return "", "", "", errors.New(sta.Message()) 126 } 127 return "", "", "", errors.Wrap(err, "failed to invoke ReadState api") 128 } 129 totalRewardRau, ok := new(big.Int).SetString(string(response.Data), 10) 130 if !ok { 131 return "", "", "", errors.New("failed to convert string into big int") 132 } 133 134 totalUnclaimedRewardRau := big.NewInt(0) 135 totalUnclaimedRewardRau.Sub(totalRewardRau, availableRewardRau) 136 137 return util.RauToString(totalUnclaimedRewardRau, util.IotxDecimalNum), 138 util.RauToString(availableRewardRau, util.IotxDecimalNum), 139 util.RauToString(totalRewardRau, util.IotxDecimalNum), 140 err 141 } 142 143 func reward(client ioctl.Client, arg string) (string, string, error) { 144 address, err := client.Address(arg) 145 if err != nil { 146 return "", "", errors.Wrap(err, "failed to get address") 147 } 148 apiClient, err := client.APIServiceClient() 149 if err != nil { 150 return "", "", errors.Wrap(err, "failed to connect to endpoint") 151 } 152 ctx := context.Background() 153 jwtMD, err := util.JwtAuth() 154 if err == nil { 155 ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx) 156 } 157 response, err := apiClient.ReadState( 158 ctx, 159 &iotexapi.ReadStateRequest{ 160 ProtocolID: []byte("rewarding"), 161 MethodName: []byte("UnclaimedBalance"), 162 Arguments: [][]byte{[]byte(address)}, 163 }, 164 ) 165 if err != nil { 166 if sta, ok := status.FromError(err); ok { 167 if sta.Code() == codes.Unavailable { 168 return "", "", ioctl.ErrInvalidEndpointOrInsecure 169 } 170 return "", "", errors.New(sta.Message()) 171 } 172 return "", "", errors.Wrap(err, "failed to get version from server") 173 } 174 rewardRau, ok := new(big.Int).SetString(string(response.Data), 10) 175 if !ok { 176 return "", "", errors.New("failed to convert string into big int") 177 } 178 return address, util.RauToString(rewardRau, util.IotxDecimalNum), err 179 }