Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Clawback Continuous Vesting Account #195

Merged
merged 15 commits into from
Feb 15, 2024
Merged

feat: Clawback Continuous Vesting Account #195

merged 15 commits into from
Feb 15, 2024

Conversation

hacheigriega
Copy link
Member

@hacheigriega hacheigriega commented Feb 8, 2024

Motivation

This PR implements a custom vesting account type ClawbackContinuousVestingAccount that wraps the SDK's ContinuousVestingAccount to provide an additional feature of "clawing back" funds to the funder of the account. Note that now this custom type is the only vesting account type our chain supports.

Explanation of Changes

The sender of the create-vesting-account transaction is registered as the funder of the vesting account so that when the funder later sends a clawback transaction, the vesting (= unvested) funds are returned back to the funder. The implementation is complicated by the fact that the funds can be in various states. The funds are clawed-back from different sources in the following order: Unbonded (through standard bank module transfer) -> Unbonding delegations -> Bonded delegations (which may also be going through redelegation process). The transfer logic is taken from Agoric's TransferDelegation and TransferUnbonding. To integrate these staking keeper methods, we wire to the app the custom staking module that wraps the SDK's staking module. However, as evident in x/staking/module.go, the SDK's default staking handles the remaining functionalities of the staking module, and most of the code present in the custom staking module such as the create-validator-vrf transaction remains unactivated.

The clawed back amount is guaranteed to be all of the currently vesting amount, unless the vesting account's delegation has been slashed, and the account doesn't have sufficient unbonded funds to make up for the loss.

How to use the transactions:

  • tx create-vesting-account [to_address] [amount] [end_time] for creating a ClawbackContinuousVestingAccount

    • The "to" account must not already exist.
    • The "from" address is registered as the newly created vesting account's funder.
    • Add a flag --disable-clawback to disallow clawback. If this flag is present, the funder field of the vesting account will be empty.
  • tx clawback [address]

    • The funds that are still vesting are sent back to the funder's address.

⚠️Note the simulation testing is still being fixed - There is an issue with the simulation app state not being updated.

Testing

Integration testing and simulation testing

Related PRs and Issues

Closes #194

@hacheigriega hacheigriega marked this pull request as ready for review February 14, 2024 18:22
@hacheigriega hacheigriega requested a review from a team February 14, 2024 18:22
Copy link
Contributor

@gluax gluax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just commenting since I'm not a cosmos expert.

It looks like we are replacing the original ContinousVestingAccoutns with Clawbackable ones. I thought we wanted both, more so for users than us; our personal main priority is Clawbacks for launch.

As for the legal stuff bc of licensing clash @jasperdg @mariocao I think GPLv3 is compatible with Apache 2. I believe this means we need to also include the Apache license. But might need to do more than that...

app/genesis.go Outdated Show resolved Hide resolved
proto/sedachain/vesting/v1/tx.proto Outdated Show resolved Hide resolved
Comment on lines +27 to +29
// NOTE: This code was taken from
// https://github.com/agoric-labs/cosmos-sdk/blob/f42d86980ddfc07869846c391a03622cbd7e9188/x/staking/keeper/delegation.go#L701
// with slight modifications.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDK who the right person to ask this question to is, but are we in the OK with their licensing and ours not conflicting?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, they are Apache, and we are GPL. I think we have to include a copy of the Apache license now. But I'm no expert

}

// MsgCreateVestingAccount defines a message that creates a vesting account.
message MsgCreateVestingAccount {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question of does this prevent creating an original continuous vesting account? We still want that behavior(although less priority I suppose), on top of being able to create a clawback one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is this a entirely different vesting thing that just additionally gets added?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it cannot create an original continuous vesting account. Adding that would be quite simple though, as we can just add a boolean field to the message to indicate clawback or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I'm not positive if we want it or not, but I figured from a user perspective, to be able to do both might be nice. idk thoughts @mariocao?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is so simple, yes, why not :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a flag for disabling clawback.

@hacheigriega
Copy link
Member Author

Just commenting since I'm not a cosmos expert.

It looks like we are replacing the original ContinousVestingAccoutns with Clawbackable ones. I thought we wanted both, more so for users than us; our personal main priority is Clawbacks for launch.

As for the legal stuff bc of licensing clash @jasperdg @mariocao I think GPLv3 is compatible with Apache 2. I believe this means we need to also include the Apache license. But might need to do more than that...

Good points. We can support both SDK's ContinousVestingAccount and our ClawbackContinousVestingAccountif we want. Not sure why we would want that though - just thought it would be simpler to support the clawback one only since they're identical except the clawback feature.

@jim380
Copy link
Contributor

jim380 commented Feb 14, 2024

When I run test-sim-determinism, MsgClawback fails in ABCI, particularly in RunTx when it’s called in DeliverTx in execModeFinalize mode.

If you run breakpoints or add a panic like below in Clawback, you will see that it never gets hits.
image

This confirms that the operation had failed in RunTx because msgs only get routed to the module protobuf msg services after a successful RunTx. Cc: @hacheigriega

@hacheigriega hacheigriega merged commit 3a60cd9 into main Feb 15, 2024
13 of 16 checks passed
@hacheigriega hacheigriega deleted the hy/vesting branch February 15, 2024 22:22
Copy link
Contributor

@jim380 jim380 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Particularly the core logic in func (m msgServer) Clawback.

Comment on lines +123 to +125
if err != nil {
return errors.New("funder of vesting account must be provided using from flag")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is a bit ambiguous to me. "invalid funder address" would make more sense imo. funder on line 118 would be "" if no funder address was provided in the flag.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need to add a check for vestingStart > vestingEnd.

// funder_address is the address which funded the account.
string funder_address = 1;
// account_address is the address of the vesting to claw back from.
string account_address = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice, almost necessary to add a dest_address like Agoric did. Funder could've either rotated her keys, or had her original compromised. We need to give them an option to clawback the funds even if the original key was no longer accessible.

Comment on lines +63 to +76
repeated cosmos.base.v1beta1.Coin clawed_unbonded = 1 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];

repeated cosmos.base.v1beta1.Coin clawed_unbonding = 2 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];

repeated cosmos.base.v1beta1.Coin clawed_bonded = 3 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.nullable) = false
];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice addition!


// NOTE: errors checked during msg validation
vestingAccAddr := sdk.MustAccAddressFromBech32(msg.AccountAddress)
funderAddr := sdk.MustAccAddressFromBech32(msg.FunderAddress)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inb4 would be good to add a destination address like Agoric does.


toClawBack := coinsMin(vestingAccount.GetVestingCoins(ctx.BlockTime()), total) // might have been slashed

// Write now now so that the bank module sees unvested tokens are unlocked.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate now

func (m msgServer) Clawback(goCtx context.Context, msg *types.MsgClawback) (*types.MsgClawbackResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// NOTE: errors checked during msg validation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this msg validation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

✨ Implement clawback continuous vesting account
4 participants