Skip to content

Commit

Permalink
add cli to withdraw validator rewards on eth mainchain (#457)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaozhou authored Mar 5, 2021
1 parent bb14352 commit b497862
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 19 deletions.
2 changes: 1 addition & 1 deletion cmd/sgnops.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func GetSgnopsExecutor() cli.Executor {
ops.SnapshotMainchainCommand(),
ops.InitCandidateCommand(),
ops.DelegateCommand(),
ops.WithdrawCommand(),
ops.WithdrawCommand(cdc),
ops.ClaimValidatorCommand(),
ops.ConfirmUnbondedCandidateCommand(),
ops.UpdateMinSelfStakeCommand(),
Expand Down
15 changes: 7 additions & 8 deletions docs/sgncli/sgncli_tx_validator_edit-candidate-description.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ sgncli tx validator edit-candidate-description [flags]
### Options

```
--contact string The candidate's security contact email (default "[do-not-modify]")
--details string The candidate's details (default "[do-not-modify]")
-h, --help help for edit-candidate-description
--identity string The identity signature (ex. UPort or Keybase) (default "[do-not-modify]")
--indent Add indent to JSON response
--moniker string The candidate's name (default "[do-not-modify]")
--trust-node Trust connected full node (don't verify proofs for responses) (default true)
--website string The candidate's website (default "[do-not-modify]")
--contact string The candidate's security contact email (default "[do-not-modify]")
--details string The candidate's details (default "[do-not-modify]")
-h, --help help for edit-candidate-description
--indent Add indent to JSON response
--moniker string The candidate's name (default "[do-not-modify]")
--trust-node Trust connected full node (don't verify proofs for responses) (default true)
--website string The candidate's website (default "[do-not-modify]")
```

### Options inherited from parent commands
Expand Down
1 change: 1 addition & 0 deletions docs/sgnops/sgnops_withdraw.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Withdraw delegated stake
* [sgnops](sgnops.md) - sgn ops utility
* [sgnops withdraw confirm](sgnops_withdraw_confirm.md) - Confirm withdrawal intents for the stake delegated to a candidate
* [sgnops withdraw intend](sgnops_withdraw_intend.md) - Send a withdrawal intent for the stake delegated to a candidate
* [sgnops withdraw reward](sgnops_withdraw_reward.md) - Withdraw reward on mainchain
* [sgnops withdraw unbonded-candidate](sgnops_withdraw_unbonded-candidate.md) - Withdraw delegated stake from an unbonded candidate

###### Auto generated by spf13/cobra
33 changes: 33 additions & 0 deletions docs/sgnops/sgnops_withdraw_reward.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## sgnops withdraw reward

Withdraw reward on mainchain

### Synopsis

Withdraw reward on mainchain

```
sgnops withdraw reward [eth-address] [flags]
```

### Options

```
-h, --help help for reward
```

### Options inherited from parent commands

```
--config string Path to SGN-specific configs (default "$HOME/.sgncli/config/sgn.toml")
-e, --encoding string Binary encoding (hex|b64|btc) (default "hex")
--home string directory for config and data (default "$HOME/.sgncli")
-o, --output string Output format (text|json) (default "text")
--trace print out full stack trace on errors
```

### SEE ALSO

* [sgnops withdraw](sgnops_withdraw.md) - Withdraw delegated stake

###### Auto generated by spf13/cobra
103 changes: 102 additions & 1 deletion ops/withdraw.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package ops

import (
"math/big"

"github.com/celer-network/goutils/log"
"github.com/celer-network/sgn/common"
"github.com/celer-network/sgn/mainchain"
"github.com/celer-network/sgn/proto/sgn"
"github.com/celer-network/sgn/x/validator"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
ethcommon "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/golang/protobuf/proto"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func WithdrawCommand() *cobra.Command {
func WithdrawCommand(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw",
Short: "Withdraw delegated stake",
Expand All @@ -19,6 +26,7 @@ func WithdrawCommand() *cobra.Command {
intendWithdrawCommand(),
confirmWithdrawCommand(),
withdrawFromUnbondedCandidateCommand(),
withdrawReward(cdc),
)
return cmd
}
Expand Down Expand Up @@ -126,3 +134,96 @@ func withdrawFromUnbondedCandidateCommand() *cobra.Command {
cmd.MarkFlagRequired(amountFlag)
return cmd
}

func withdrawReward(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "reward [eth-address]",
Short: "Withdraw reward on mainchain",
RunE: func(cmd *cobra.Command, args []string) error {
ethClient, err := common.NewEthClientFromConfig()
if err != nil {
return err
}

cliCtx := common.NewQueryCLIContext(cdc)
reward, err := validator.CLIQueryReward(cliCtx, validator.RouterKey, ethClient.Address.Hex())
if err != nil {
log.Errorln("query reward error", err)
return err
}

if len(reward.RewardProtoBytes) == 0 {
log.Info("no signed reward")
return nil
}

var mingingReward, serviceReward *big.Int
var pbReward sgn.Reward
err = proto.Unmarshal(reward.RewardProtoBytes, &pbReward)
if err != nil {
log.Errorln("proto umarshal err", err, reward.RewardProtoBytes)
} else {
mingingReward = new(big.Int).SetBytes(pbReward.CumulativeMiningReward)
serviceReward = new(big.Int).SetBytes(pbReward.CumulativeServiceReward)
}

var signers []mainchain.Addr
for _, sigs := range reward.Sigs {
signers = append(signers, mainchain.Hex2Addr(sigs.Signer))
}
signerStakes, _, quorumStakes, err := ethClient.CheckVotingPower(signers)
if err != nil {
log.Errorln("check signers voting power error", err)
return err
}
if quorumStakes.Cmp(signerStakes) > 0 {
log.Infof("signer stakes %s smaller than quorum stakes %s", signerStakes, quorumStakes)
return nil
}

redeemedMiningReward, err := ethClient.DPoS.RedeemedMiningReward(&bind.CallOpts{}, ethClient.Address)
if err != nil {
log.Errorln("query RedeemedMiningReward err", err)
return err
}
redeemedServiceReward, err := ethClient.SGN.RedeemedServiceReward(&bind.CallOpts{}, ethClient.Address)
if err != nil {
log.Errorln("query RedeemedServiceReward err", err)
return err
}
if mingingReward.Cmp(redeemedMiningReward) <= 0 && serviceReward.Cmp(redeemedServiceReward) <= 0 {
log.Info("no new reward")
return nil
}

log.Infof("Withdrawing mining reward %s service reward %s",
mingingReward.Sub(mingingReward, redeemedMiningReward), serviceReward.Sub(serviceReward, redeemedServiceReward))

_, err = ethClient.Transactor.TransactWaitMined(
"RedeemReward",
func(transactor bind.ContractTransactor, opts *bind.TransactOpts) (*ethtypes.Transaction, error) {
return ethClient.SGN.RedeemReward(opts, reward.GetRewardRequest())
},
)
if err != nil {
return err
}

redeemedMiningReward, err = ethClient.DPoS.RedeemedMiningReward(&bind.CallOpts{}, ethClient.Address)
if err != nil {
log.Errorln("query RedeemedMiningReward err", err)
return err
}
redeemedServiceReward, err = ethClient.SGN.RedeemedServiceReward(&bind.CallOpts{}, ethClient.Address)
if err != nil {
log.Errorln("query RedeemedServiceReward err", err)
return err
}
log.Infof("Total withdrawn mining reward %s service reward %s", redeemedMiningReward, redeemedServiceReward)

return nil
},
}

return cmd
}
6 changes: 5 additions & 1 deletion testing/common/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,13 @@ func DeployCommand() *cobra.Command {

if ethurl == LocalGeth {
amt := new(big.Int)
amt.SetString("1"+strings.Repeat("0", 19), 10)
amt.SetString("1"+strings.Repeat("0", 20), 10)
tx, err := erc20.Approve(EtherBaseAuth, dposAddr, amt)
ChkErr(err, "failed to approve erc20")
WaitMinedWithChk(context.Background(), EthClient, tx, BlockDelay, PollingInterval, "approve erc20")
DposContract, err = mainchain.NewDPoS(dposAddr, EthClient)
_, err = DposContract.ContributeToMiningPool(EtherBaseAuth, amt)
ChkErr(err, "failed to call ContributeToMiningPool of DPoS contract")
err = FundAddrsErc20(erc20Addr,
[]mainchain.Addr{
mainchain.Hex2Addr(ClientEthAddrs[0]),
Expand All @@ -157,6 +160,7 @@ func DeployCommand() *cobra.Command {
"1"+strings.Repeat("0", 20),
)
ChkErr(err, "fund test CELR to clients")

}

return nil
Expand Down
13 changes: 5 additions & 8 deletions x/validator/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ import (
)

const (
flagMoniker = "moniker"
flagIdentity = "identity"
flagWebsite = "website"
flagContact = "contact"
flagDetails = "details"
flagMoniker = "moniker"
flagWebsite = "website"
flagContact = "contact"
flagDetails = "details"
)

func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
Expand Down Expand Up @@ -80,11 +79,10 @@ func GetCmdEditCandidateDescription(cdc *codec.Codec) *cobra.Command {
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
moniker, _ := cmd.Flags().GetString(flagMoniker)
identity, _ := cmd.Flags().GetString(flagIdentity)
website, _ := cmd.Flags().GetString(flagWebsite)
contact, _ := cmd.Flags().GetString(flagContact)
details, _ := cmd.Flags().GetString(flagDetails)
description := staking.NewDescription(moniker, identity, website, contact, details)
description := staking.NewDescription(moniker, staking.DoNotModifyDesc, website, contact, details)

txr, err := transactor.NewCliTransactor(cdc, viper.GetString(flags.FlagHome))
if err != nil {
Expand Down Expand Up @@ -114,7 +112,6 @@ func GetCmdEditCandidateDescription(cdc *codec.Codec) *cobra.Command {
}

cmd.Flags().String(flagMoniker, staking.DoNotModifyDesc, "The candidate's name")
cmd.Flags().String(flagIdentity, staking.DoNotModifyDesc, "The identity signature (ex. UPort or Keybase)")
cmd.Flags().String(flagWebsite, staking.DoNotModifyDesc, "The candidate's website")
cmd.Flags().String(flagContact, staking.DoNotModifyDesc, "The candidate's security contact email")
cmd.Flags().String(flagDetails, staking.DoNotModifyDesc, "The candidate's details")
Expand Down

0 comments on commit b497862

Please sign in to comment.