Merge pull request #410 from filecoin-project/feat/multisig-lockout
Add linear vesting to multisig
This commit is contained in:
commit
cf2bbeb775
@ -16,10 +16,29 @@ type MultiSigActorState struct {
|
|||||||
Required uint64
|
Required uint64
|
||||||
NextTxID uint64
|
NextTxID uint64
|
||||||
|
|
||||||
|
InitialBalance types.BigInt
|
||||||
|
StartingBlock uint64
|
||||||
|
UnlockDuration uint64
|
||||||
|
|
||||||
//TODO: make this map/sharray/whatever
|
//TODO: make this map/sharray/whatever
|
||||||
Transactions []MTransaction
|
Transactions []MTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (msas MultiSigActorState) canSpend(act *types.Actor, amnt types.BigInt, height uint64) bool {
|
||||||
|
if msas.UnlockDuration == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := height - msas.StartingBlock
|
||||||
|
if offset > msas.UnlockDuration {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
minBalance := types.BigDiv(msas.InitialBalance, types.NewInt(msas.UnlockDuration))
|
||||||
|
minBalance = types.BigMul(minBalance, types.NewInt(offset))
|
||||||
|
return !minBalance.LessThan(types.BigSub(act.Balance, amnt))
|
||||||
|
}
|
||||||
|
|
||||||
func (msas MultiSigActorState) isSigner(addr address.Address) bool {
|
func (msas MultiSigActorState) isSigner(addr address.Address) bool {
|
||||||
for _, s := range msas.Signers {
|
for _, s := range msas.Signers {
|
||||||
if s == addr {
|
if s == addr {
|
||||||
@ -90,8 +109,9 @@ func (msa MultiSigActor) Exports() []interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MultiSigConstructorParams struct {
|
type MultiSigConstructorParams struct {
|
||||||
Signers []address.Address
|
Signers []address.Address
|
||||||
Required uint64
|
Required uint64
|
||||||
|
UnlockDuration uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext,
|
func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext,
|
||||||
@ -100,6 +120,13 @@ func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext
|
|||||||
Signers: params.Signers,
|
Signers: params.Signers,
|
||||||
Required: params.Required,
|
Required: params.Required,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.UnlockDuration != 0 {
|
||||||
|
self.InitialBalance = vmctx.Message().Value
|
||||||
|
self.UnlockDuration = params.UnlockDuration
|
||||||
|
self.StartingBlock = vmctx.BlockHeight()
|
||||||
|
}
|
||||||
|
|
||||||
head, err := vmctx.Storage().Put(self)
|
head, err := vmctx.Storage().Put(self)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Wrap(err, "could not put new head")
|
return nil, aerrors.Wrap(err, "could not put new head")
|
||||||
@ -183,6 +210,9 @@ func (msa MultiSigActor) Propose(act *types.Actor, vmctx types.VMContext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.Required == 1 {
|
if self.Required == 1 {
|
||||||
|
if !self.canSpend(act, tx.Value, vmctx.BlockHeight()) {
|
||||||
|
return nil, aerrors.New(100, "transaction amount exceeds available")
|
||||||
|
}
|
||||||
_, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params)
|
_, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params)
|
||||||
if aerrors.IsFatal(err) {
|
if aerrors.IsFatal(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -229,6 +259,9 @@ func (msa MultiSigActor) Approve(act *types.Actor, vmctx types.VMContext,
|
|||||||
}
|
}
|
||||||
tx.Approved = append(tx.Approved, vmctx.Message().From)
|
tx.Approved = append(tx.Approved, vmctx.Message().From)
|
||||||
if uint64(len(tx.Approved)) >= self.Required {
|
if uint64(len(tx.Approved)) >= self.Required {
|
||||||
|
if !self.canSpend(act, tx.Value, vmctx.BlockHeight()) {
|
||||||
|
return nil, aerrors.New(100, "transaction amount exceeds available")
|
||||||
|
}
|
||||||
_, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params)
|
_, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params)
|
||||||
if aerrors.IsFatal(err) {
|
if aerrors.IsFatal(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -963,7 +963,7 @@ func (t *MultiSigActorState) MarshalCBOR(w io.Writer) error {
|
|||||||
_, err := w.Write(cbg.CborNull)
|
_, err := w.Write(cbg.CborNull)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := w.Write([]byte{132}); err != nil {
|
if _, err := w.Write([]byte{135}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,6 +987,21 @@ func (t *MultiSigActorState) MarshalCBOR(w io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t.t.InitialBalance (types.BigInt)
|
||||||
|
if err := t.InitialBalance.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.StartingBlock (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.StartingBlock)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.UnlockDuration (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.UnlockDuration)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// t.t.Transactions ([]actors.MTransaction)
|
// t.t.Transactions ([]actors.MTransaction)
|
||||||
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Transactions)))); err != nil {
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Transactions)))); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1010,7 +1025,7 @@ func (t *MultiSigActorState) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return fmt.Errorf("cbor input should be of type array")
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
}
|
}
|
||||||
|
|
||||||
if extra != 4 {
|
if extra != 7 {
|
||||||
return fmt.Errorf("cbor input had wrong number of fields")
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1060,6 +1075,35 @@ func (t *MultiSigActorState) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return fmt.Errorf("wrong type for uint64 field")
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
}
|
}
|
||||||
t.NextTxID = extra
|
t.NextTxID = extra
|
||||||
|
// t.t.InitialBalance (types.BigInt)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.InitialBalance.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.StartingBlock (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.StartingBlock = extra
|
||||||
|
// t.t.UnlockDuration (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.UnlockDuration = extra
|
||||||
// t.t.Transactions ([]actors.MTransaction)
|
// t.t.Transactions ([]actors.MTransaction)
|
||||||
|
|
||||||
maj, extra, err = cbg.CborReadHeader(br)
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
@ -1094,7 +1138,7 @@ func (t *MultiSigConstructorParams) MarshalCBOR(w io.Writer) error {
|
|||||||
_, err := w.Write(cbg.CborNull)
|
_, err := w.Write(cbg.CborNull)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := w.Write([]byte{130}); err != nil {
|
if _, err := w.Write([]byte{131}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1112,6 +1156,11 @@ func (t *MultiSigConstructorParams) MarshalCBOR(w io.Writer) error {
|
|||||||
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Required)); err != nil {
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Required)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t.t.UnlockDuration (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.UnlockDuration)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1126,7 +1175,7 @@ func (t *MultiSigConstructorParams) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return fmt.Errorf("cbor input should be of type array")
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
}
|
}
|
||||||
|
|
||||||
if extra != 2 {
|
if extra != 3 {
|
||||||
return fmt.Errorf("cbor input had wrong number of fields")
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1166,6 +1215,16 @@ func (t *MultiSigConstructorParams) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return fmt.Errorf("wrong type for uint64 field")
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
}
|
}
|
||||||
t.Required = extra
|
t.Required = extra
|
||||||
|
// t.t.UnlockDuration (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.UnlockDuration = extra
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user