Beneficiary cmd in lotus-shed
Add `ProposeChangeBeneficiary` and `ConfirmChangeBeneficiary` to lotus-shed
This commit is contained in:
parent
34576d0c64
commit
51d2a883f0
@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -14,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||
|
||||
@ -35,6 +37,8 @@ var actorCmd = &cli.Command{
|
||||
actorProposeChangeWorker,
|
||||
actorConfirmChangeWorker,
|
||||
actorGetMethodNum,
|
||||
actorProposeChangeBeneficiary,
|
||||
actorConfirmChangeBeneficiary,
|
||||
},
|
||||
}
|
||||
|
||||
@ -831,3 +835,255 @@ var actorGetMethodNum = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var actorProposeChangeBeneficiary = &cli.Command{
|
||||
Name: "propose-change-beneficiary",
|
||||
Usage: "Propose a beneficiary address change",
|
||||
ArgsUsage: "[beneficiaryAddress quota expiration minerID]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "really-do-it",
|
||||
Usage: "Actually send transaction performing the action",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "overwrite-pending-change",
|
||||
Usage: "Overwrite the current beneficiary change proposal",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 4 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting fullnode api: %w", err)
|
||||
}
|
||||
defer acloser()
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
na, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing beneficiary address: %w", err)
|
||||
}
|
||||
|
||||
newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("looking up new beneficiary address: %w", err)
|
||||
}
|
||||
|
||||
quota, err := types.ParseFIL(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing quota: %w", err)
|
||||
}
|
||||
|
||||
expiration, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing expiration: %w", err)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().Get(3))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner address: %w", err)
|
||||
}
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
if mi.Beneficiary == mi.Owner && newAddr == mi.Owner {
|
||||
return fmt.Errorf("beneficiary %s already set to owner address", mi.Beneficiary)
|
||||
}
|
||||
|
||||
if mi.PendingBeneficiaryTerm != nil {
|
||||
fmt.Println("WARNING: replacing Pending Beneficiary Term of:")
|
||||
fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary)
|
||||
fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota)
|
||||
fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration)
|
||||
|
||||
if !cctx.Bool("overwrite-pending-change") {
|
||||
return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY")
|
||||
}
|
||||
}
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please")
|
||||
return nil
|
||||
}
|
||||
|
||||
params := &miner.ChangeBeneficiaryParams{
|
||||
NewBeneficiary: newAddr,
|
||||
NewQuota: abi.TokenAmount(quota),
|
||||
NewExpiration: abi.ChainEpoch(expiration),
|
||||
}
|
||||
|
||||
sp, err := actors.SerializeParams(params)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("serializing params: %w", err)
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
|
||||
From: mi.Owner,
|
||||
To: maddr,
|
||||
Method: builtin.MethodsMiner.ChangeBeneficiary,
|
||||
Value: big.Zero(),
|
||||
Params: sp,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("mpool push: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Propose Message CID:", smsg.Cid())
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("waiting for message to be included in block: %w", err)
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode.IsError() {
|
||||
return fmt.Errorf("propose beneficiary change failed")
|
||||
}
|
||||
|
||||
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, wait.TipSet)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == newAddr {
|
||||
fmt.Println("Beneficiary address successfully changed")
|
||||
} else {
|
||||
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var actorConfirmChangeBeneficiary = &cli.Command{
|
||||
Name: "confirm-change-beneficiary",
|
||||
Usage: "Confirm a beneficiary address change",
|
||||
ArgsUsage: "[minerAddress]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "really-do-it",
|
||||
Usage: "Actually send transaction performing the action",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "existing-beneficiary",
|
||||
Usage: "send confirmation from the existing beneficiary address",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "new-beneficiary",
|
||||
Usage: "send confirmation from the new beneficiary address",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting fullnode api: %w", err)
|
||||
}
|
||||
defer acloser()
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing beneficiary address: %w", err)
|
||||
}
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
if mi.PendingBeneficiaryTerm == nil {
|
||||
return fmt.Errorf("no pending beneficiary term found for miner %s", maddr)
|
||||
}
|
||||
|
||||
if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) {
|
||||
return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --new-beneficiary"))
|
||||
}
|
||||
|
||||
var fromAddr address.Address
|
||||
if cctx.IsSet("existing-beneficiary") {
|
||||
if mi.PendingBeneficiaryTerm.ApprovedByBeneficiary {
|
||||
return fmt.Errorf("beneficiary change already approved by current beneficiary")
|
||||
}
|
||||
fromAddr = mi.Beneficiary
|
||||
} else {
|
||||
if mi.PendingBeneficiaryTerm.ApprovedByNominee {
|
||||
return fmt.Errorf("beneficiary change already approved by new beneficiary")
|
||||
}
|
||||
fromAddr = mi.PendingBeneficiaryTerm.NewBeneficiary
|
||||
}
|
||||
|
||||
fmt.Println("Confirming Pending Beneficiary Term of:")
|
||||
fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary)
|
||||
fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota)
|
||||
fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration)
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please")
|
||||
return nil
|
||||
}
|
||||
|
||||
params := &miner.ChangeBeneficiaryParams{
|
||||
NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary,
|
||||
NewQuota: mi.PendingBeneficiaryTerm.NewQuota,
|
||||
NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration,
|
||||
}
|
||||
|
||||
sp, err := actors.SerializeParams(params)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("serializing params: %w", err)
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
|
||||
From: fromAddr,
|
||||
To: maddr,
|
||||
Method: builtin.MethodsMiner.ChangeBeneficiary,
|
||||
Value: big.Zero(),
|
||||
Params: sp,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("mpool push: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Confirm Message CID:", smsg.Cid())
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("waiting for message to be included in block: %w", err)
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode.IsError() {
|
||||
return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary {
|
||||
fmt.Println("Beneficiary address successfully changed")
|
||||
} else {
|
||||
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user