abstract multisig calls
This commit is contained in:
parent
2e9915ac28
commit
b01a1d457a
70
chain/actors/builtin/multisig/message.go
Normal file
70
chain/actors/builtin/multisig/message.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/minio/blake2b-simd"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Message(version actors.Version, from address.Address) MessageBuilder {
|
||||||
|
switch version {
|
||||||
|
case actors.Version0:
|
||||||
|
return message0{from}
|
||||||
|
case actors.Version2:
|
||||||
|
return message2{message0{from}}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unsupported actors version: %d", version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageBuilder interface {
|
||||||
|
// Create a new multisig with the specified parameters.
|
||||||
|
Create(signers []address.Address, threshold uint64,
|
||||||
|
vestingStart, vestingDuration abi.ChainEpoch,
|
||||||
|
initialAmount abi.TokenAmount) (*types.Message, error)
|
||||||
|
|
||||||
|
// Propose a transaction to the given multisig.
|
||||||
|
Propose(msig, target address.Address, amt abi.TokenAmount,
|
||||||
|
method abi.MethodNum, params []byte) (*types.Message, error)
|
||||||
|
|
||||||
|
// Approve a multisig transaction. The "hash" is optional.
|
||||||
|
Approve(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error)
|
||||||
|
|
||||||
|
// Cancel a multisig transaction. The "hash" is optional.
|
||||||
|
Cancel(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this type is the same between v0 and v2
|
||||||
|
type ProposalHashData = multisig2.ProposalHashData
|
||||||
|
|
||||||
|
func txnParams(id uint64, data *ProposalHashData) ([]byte, error) {
|
||||||
|
params := multisig2.TxnIDParams{ID: multisig2.TxnID(id)}
|
||||||
|
if data != nil {
|
||||||
|
if data.Requester.Protocol() != address.ID {
|
||||||
|
return nil, xerrors.Errorf("proposer address must be an ID address, was %s", data.Requester)
|
||||||
|
}
|
||||||
|
if data.Value.Sign() == -1 {
|
||||||
|
return nil, xerrors.Errorf("proposal value must be non-negative, was %s", data.Value)
|
||||||
|
}
|
||||||
|
if data.To == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("proposed destination address must be set")
|
||||||
|
}
|
||||||
|
pser, err := data.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hash := blake2b.Sum256(pser)
|
||||||
|
params.ProposalHash = hash[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return actors.SerializeParams(¶ms)
|
||||||
|
}
|
142
chain/actors/builtin/multisig/message0.go
Normal file
142
chain/actors/builtin/multisig/message0.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||||
|
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message0 struct{ from address.Address }
|
||||||
|
|
||||||
|
func (m message0) Create(
|
||||||
|
signers []address.Address, threshold uint64,
|
||||||
|
unlockStart, unlockDuration abi.ChainEpoch,
|
||||||
|
initialAmount abi.TokenAmount,
|
||||||
|
) (*types.Message, error) {
|
||||||
|
|
||||||
|
lenAddrs := uint64(len(signers))
|
||||||
|
|
||||||
|
if lenAddrs < threshold {
|
||||||
|
return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
||||||
|
}
|
||||||
|
|
||||||
|
if threshold == 0 {
|
||||||
|
threshold = lenAddrs
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.from == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
if unlockStart != 0 {
|
||||||
|
return nil, xerrors.Errorf("actors v0 does not support a non-zero vesting start time")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up constructor parameters for multisig
|
||||||
|
msigParams := &multisig0.ConstructorParams{
|
||||||
|
Signers: signers,
|
||||||
|
NumApprovalsThreshold: threshold,
|
||||||
|
UnlockDuration: unlockDuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr := actors.SerializeParams(msigParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||||
|
execParams := &init0.ExecParams{
|
||||||
|
CodeCID: builtin0.MultisigActorCodeID,
|
||||||
|
ConstructorParams: enc,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr = actors.SerializeParams(execParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: init_.Address,
|
||||||
|
From: m.from,
|
||||||
|
Method: builtin0.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
Value: initialAmount,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Propose(msig, to address.Address, amt abi.TokenAmount,
|
||||||
|
method abi.MethodNum, params []byte) (*types.Message, error) {
|
||||||
|
|
||||||
|
if msig == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide a multisig address for proposal")
|
||||||
|
}
|
||||||
|
|
||||||
|
if to == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide a target address for proposal")
|
||||||
|
}
|
||||||
|
|
||||||
|
if amt.Sign() == -1 {
|
||||||
|
return nil, xerrors.Errorf("must provide a non-negative amount for proposed send")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.from == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{
|
||||||
|
To: to,
|
||||||
|
Value: amt,
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
})
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to serialize parameters: %w", actErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: msig,
|
||||||
|
From: m.from,
|
||||||
|
Value: abi.NewTokenAmount(0),
|
||||||
|
Method: builtin0.MethodsMultisig.Propose,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Approve(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) {
|
||||||
|
enc, err := txnParams(txID, hashData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: msig,
|
||||||
|
From: m.from,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
Method: builtin0.MethodsMultisig.Approve,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m message0) Cancel(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) {
|
||||||
|
enc, err := txnParams(txID, hashData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: msig,
|
||||||
|
From: m.from,
|
||||||
|
Value: types.NewInt(0),
|
||||||
|
Method: builtin0.MethodsMultisig.Cancel,
|
||||||
|
Params: enc,
|
||||||
|
}, nil
|
||||||
|
}
|
71
chain/actors/builtin/multisig/message2.go
Normal file
71
chain/actors/builtin/multisig/message2.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package multisig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||||
|
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||||
|
multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type message2 struct{ message0 }
|
||||||
|
|
||||||
|
func (m message2) Create(
|
||||||
|
signers []address.Address, threshold uint64,
|
||||||
|
unlockStart, unlockDuration abi.ChainEpoch,
|
||||||
|
initialAmount abi.TokenAmount,
|
||||||
|
) (*types.Message, error) {
|
||||||
|
|
||||||
|
lenAddrs := uint64(len(signers))
|
||||||
|
|
||||||
|
if lenAddrs < threshold {
|
||||||
|
return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
||||||
|
}
|
||||||
|
|
||||||
|
if threshold == 0 {
|
||||||
|
threshold = lenAddrs
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.from == address.Undef {
|
||||||
|
return nil, xerrors.Errorf("must provide source address")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up constructor parameters for multisig
|
||||||
|
msigParams := &multisig2.ConstructorParams{
|
||||||
|
Signers: signers,
|
||||||
|
NumApprovalsThreshold: threshold,
|
||||||
|
UnlockDuration: unlockDuration,
|
||||||
|
StartEpoch: unlockStart,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr := actors.SerializeParams(msigParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||||
|
execParams := &init2.ExecParams{
|
||||||
|
CodeCID: builtin2.MultisigActorCodeID,
|
||||||
|
ConstructorParams: enc,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, actErr = actors.SerializeParams(execParams)
|
||||||
|
if actErr != nil {
|
||||||
|
return nil, actErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Message{
|
||||||
|
To: init_.Address,
|
||||||
|
From: m.from,
|
||||||
|
Method: builtin2.MethodsInit.Exec,
|
||||||
|
Params: enc,
|
||||||
|
Value: initialAmount,
|
||||||
|
}, nil
|
||||||
|
}
|
@ -9,15 +9,13 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/minio/blake2b-simd"
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
@ -30,58 +28,31 @@ type MsigAPI struct {
|
|||||||
MpoolAPI MpoolAPI
|
MpoolAPI MpoolAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *MsigAPI) messageBuilder(ctx context.Context, from address.Address) (multisig.MessageBuilder, error) {
|
||||||
|
nver, err := a.StateAPI.StateNetworkVersion(ctx, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return multisig.Message(actors.VersionForNetwork(nver), from), nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remove gp (gasPrice) from arguments
|
// TODO: remove gp (gasPrice) from arguments
|
||||||
|
// TODO: Add "vesting start" to arguments.
|
||||||
func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) {
|
||||||
|
|
||||||
lenAddrs := uint64(len(addrs))
|
mb, err := a.messageBuilder(ctx, src)
|
||||||
|
if err != nil {
|
||||||
if lenAddrs < req {
|
return cid.Undef, err
|
||||||
return cid.Undef, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if req == 0 {
|
msg, err := mb.Create(addrs, req, 0, duration, val)
|
||||||
req = lenAddrs
|
if err != nil {
|
||||||
}
|
return cid.Undef, err
|
||||||
|
|
||||||
if src == address.Undef {
|
|
||||||
return cid.Undef, xerrors.Errorf("must provide source address")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up constructor parameters for multisig
|
|
||||||
msigParams := &multisig0.ConstructorParams{
|
|
||||||
Signers: addrs,
|
|
||||||
NumApprovalsThreshold: req,
|
|
||||||
UnlockDuration: duration,
|
|
||||||
}
|
|
||||||
|
|
||||||
enc, actErr := actors.SerializeParams(msigParams)
|
|
||||||
if actErr != nil {
|
|
||||||
return cid.Undef, actErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
|
||||||
// TODO: network upgrade?
|
|
||||||
execParams := &init0.ExecParams{
|
|
||||||
CodeCID: builtin0.MultisigActorCodeID,
|
|
||||||
ConstructorParams: enc,
|
|
||||||
}
|
|
||||||
|
|
||||||
enc, actErr = actors.SerializeParams(execParams)
|
|
||||||
if actErr != nil {
|
|
||||||
return cid.Undef, actErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we create the message to send this with
|
|
||||||
msg := types.Message{
|
|
||||||
To: init_.Address,
|
|
||||||
From: src,
|
|
||||||
Method: builtin0.MethodsInit.Exec,
|
|
||||||
Params: enc,
|
|
||||||
Value: val,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the message out to the network
|
// send the message out to the network
|
||||||
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, &msg, nil)
|
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
@ -91,38 +62,14 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad
|
|||||||
|
|
||||||
func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||||
|
|
||||||
if msig == address.Undef {
|
mb, err := a.messageBuilder(ctx, src)
|
||||||
return cid.Undef, xerrors.Errorf("must provide a multisig address for proposal")
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if to == address.Undef {
|
msg, err := mb.Propose(msig, to, amt, abi.MethodNum(method), params)
|
||||||
return cid.Undef, xerrors.Errorf("must provide a target address for proposal")
|
if err != nil {
|
||||||
}
|
return cid.Undef, xerrors.Errorf("failed to create proposal: %w", err)
|
||||||
|
|
||||||
if amt.Sign() == -1 {
|
|
||||||
return cid.Undef, xerrors.Errorf("must provide a positive amount for proposed send")
|
|
||||||
}
|
|
||||||
|
|
||||||
if src == address.Undef {
|
|
||||||
return cid.Undef, xerrors.Errorf("must provide source address")
|
|
||||||
}
|
|
||||||
|
|
||||||
enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{
|
|
||||||
To: to,
|
|
||||||
Value: amt,
|
|
||||||
Method: abi.MethodNum(method),
|
|
||||||
Params: params,
|
|
||||||
})
|
|
||||||
if actErr != nil {
|
|
||||||
return cid.Undef, xerrors.Errorf("failed to serialize parameters: %w", actErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := &types.Message{
|
|
||||||
To: msig,
|
|
||||||
From: src,
|
|
||||||
Value: types.NewInt(0),
|
|
||||||
Method: builtin0.MethodsMultisig.Propose,
|
|
||||||
Params: enc,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil)
|
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil)
|
||||||
@ -200,14 +147,6 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro
|
|||||||
return cid.Undef, xerrors.Errorf("must provide multisig address")
|
return cid.Undef, xerrors.Errorf("must provide multisig address")
|
||||||
}
|
}
|
||||||
|
|
||||||
if to == address.Undef {
|
|
||||||
return cid.Undef, xerrors.Errorf("must provide proposed target address")
|
|
||||||
}
|
|
||||||
|
|
||||||
if amt.Sign() == -1 {
|
|
||||||
return cid.Undef, xerrors.Errorf("must provide the positive amount that was proposed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if src == address.Undef {
|
if src == address.Undef {
|
||||||
return cid.Undef, xerrors.Errorf("must provide source address")
|
return cid.Undef, xerrors.Errorf("must provide source address")
|
||||||
}
|
}
|
||||||
@ -220,7 +159,7 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro
|
|||||||
proposer = proposerID
|
proposer = proposerID
|
||||||
}
|
}
|
||||||
|
|
||||||
p := multisig0.ProposalHashData{
|
p := multisig.ProposalHashData{
|
||||||
Requester: proposer,
|
Requester: proposer,
|
||||||
To: to,
|
To: to,
|
||||||
Value: amt,
|
Value: amt,
|
||||||
@ -228,42 +167,22 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro
|
|||||||
Params: params,
|
Params: params,
|
||||||
}
|
}
|
||||||
|
|
||||||
pser, err := p.Serialize()
|
mb, err := a.messageBuilder(ctx, src)
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, err
|
|
||||||
}
|
|
||||||
phash := blake2b.Sum256(pser)
|
|
||||||
|
|
||||||
enc, err := actors.SerializeParams(&multisig0.TxnIDParams{
|
|
||||||
ID: multisig0.TxnID(txID),
|
|
||||||
ProposalHash: phash[:],
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var msigResponseMethod abi.MethodNum
|
var msg *types.Message
|
||||||
|
|
||||||
/*
|
|
||||||
We pass in a MsigProposeResponse instead of MethodNum to
|
|
||||||
tighten the possible inputs to just Approve and Cancel.
|
|
||||||
*/
|
|
||||||
switch operation {
|
switch operation {
|
||||||
case api.MsigApprove:
|
case api.MsigApprove:
|
||||||
msigResponseMethod = builtin0.MethodsMultisig.Approve
|
msg, err = mb.Approve(msig, txID, &p)
|
||||||
case api.MsigCancel:
|
case api.MsigCancel:
|
||||||
msigResponseMethod = builtin0.MethodsMultisig.Cancel
|
msg, err = mb.Cancel(msig, txID, &p)
|
||||||
default:
|
default:
|
||||||
return cid.Undef, xerrors.Errorf("Invalid operation for msigApproveOrCancel")
|
return cid.Undef, xerrors.Errorf("Invalid operation for msigApproveOrCancel")
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
msg := &types.Message{
|
return cid.Undef, err
|
||||||
To: msig,
|
|
||||||
From: src,
|
|
||||||
Value: types.NewInt(0),
|
|
||||||
Method: msigResponseMethod,
|
|
||||||
Params: enc,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil)
|
smsg, err := a.MpoolAPI.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user