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

migrate: Core-1 vesting accounts to the Charter #741

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4946d28
Major WIP - still just messing about
Reecepbcups Jun 28, 2023
279246a
Clean up migration vesting massively, actually works now
Reecepbcups Jun 28, 2023
c7047f1
Cleanup force undelegate & redelegate logic
Reecepbcups Jun 28, 2023
677deef
Merge branch 'main' into reece/remove-wolf-vesting
Reecepbcups Jun 28, 2023
d8e94c6
Only migrate Core1 on juno-1 chainId
Reecepbcups Jun 28, 2023
d401f7f
Fix upgrade test for vesting with ictest
Reecepbcups Jun 29, 2023
03f2aab
Fix upgrade test (due to changed GFee params)
Reecepbcups Jun 28, 2023
5c4fef5
TF: if feeCoin != "", then add the fees
Reecepbcups Jun 28, 2023
1820573
WIP for PeriodicVestingAccount
Reecepbcups Jul 1, 2023
c3e33b8
Wip2
Reecepbcups Jul 1, 2023
1d8a40e
Much cleaner vesting functions for Core-1 transfer
Reecepbcups Jul 1, 2023
be42155
lintorrr
Reecepbcups Jul 1, 2023
88cb307
Only move non vested funds to Core-1. Validation checks
Reecepbcups Jul 3, 2023
ff36245
Comments
Reecepbcups Jul 3, 2023
cd2b106
Merge branch 'main' into reece/remove-wolf-vesting
Reecepbcups Jul 3, 2023
62d2dc6
Use Wolfs actual account
Reecepbcups Jul 3, 2023
f81e91f
Migrate Core-1 rough draft
Reecepbcups Jul 3, 2023
3392ee1
lint
Reecepbcups Jul 3, 2023
6ca1e8e
VestingContract{}, better logs, no more mint logic, insta complete ve…
Reecepbcups Jul 3, 2023
8f1c444
lint
Reecepbcups Jul 3, 2023
bb40aa1
Remove stale func, new newVestingContract func
Reecepbcups Jul 3, 2023
30596ad
stale comments
Reecepbcups Jul 3, 2023
fa09054
Merge branch 'main' into reece/migrate-core1-vesting
Reecepbcups Jul 10, 2023
d9978db
Merge branch 'main' into reece/migrate-core1-vesting
Reecepbcups Jul 19, 2023
6c05f90
Merge branch 'main' into reece/migrate-core1-vesting
Reecepbcups Aug 8, 2023
87558ef
Merge branch 'main' of https://github.com/CosmosContracts/juno into r…
joelsmith-2019 Dec 24, 2023
24f679d
Move Upgrade Logic to v19
joelsmith-2019 Dec 24, 2023
57ffcaa
Update Vesting Transfer Logic,
joelsmith-2019 Jan 23, 2024
5a79ce8
Unbond All Except Jack,
joelsmith-2019 Jan 25, 2024
f029efe
Implement Test Cases
joelsmith-2019 Jan 29, 2024
87c5ad1
Add v20 Upgrade Handler
joelsmith-2019 Jan 29, 2024
bd4df59
Remove Multisig (Handled in v19)
joelsmith-2019 Jan 29, 2024
c04a213
Merge branch 'main' of https://github.com/CosmosContracts/juno into r…
joelsmith-2019 Jan 29, 2024
c28a225
Merge branch 'main' into reece/migrate-core1-vesting
joelsmith-2019 Feb 2, 2024
1e1a2b2
Send Funds After Disabling Vesting,
joelsmith-2019 Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import (
v17 "github.com/CosmosContracts/juno/v19/app/upgrades/v17"
v18 "github.com/CosmosContracts/juno/v19/app/upgrades/v18"
v19 "github.com/CosmosContracts/juno/v19/app/upgrades/v19"
v20 "github.com/CosmosContracts/juno/v19/app/upgrades/v20"
"github.com/CosmosContracts/juno/v19/docs"
)

Expand Down Expand Up @@ -119,6 +120,7 @@ var (
v17.Upgrade,
v18.Upgrade,
v19.Upgrade,
v20.Upgrade,
}
)

Expand Down
22 changes: 22 additions & 0 deletions app/upgrades/v20/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package v20

import (
wasmlctypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"

store "github.com/cosmos/cosmos-sdk/store/types"

"github.com/CosmosContracts/juno/v19/app/upgrades"
)

// UpgradeName defines the on-chain upgrade name for the upgrade.
const UpgradeName = "v20"

var Upgrade = upgrades.Upgrade{
UpgradeName: UpgradeName,
CreateUpgradeHandler: CreateV20UpgradeHandler,
StoreUpgrades: store.StoreUpgrades{
Added: []string{
wasmlctypes.ModuleName,
},
},
}
54 changes: 54 additions & 0 deletions app/upgrades/v20/mainnet_accounts.go

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions app/upgrades/v20/upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package v20_test

import (
"testing"

"github.com/stretchr/testify/suite"

sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/CosmosContracts/juno/v19/app/apptesting"
v20 "github.com/CosmosContracts/juno/v19/app/upgrades/v20"
)

type UpgradeTestSuite struct {
apptesting.KeeperTestHelper
}

func (s *UpgradeTestSuite) SetupTest() {
s.Setup()
}

func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(UpgradeTestSuite))
}

// Ensures the test does not error out.
func (s *UpgradeTestSuite) TestUpgrade() {
s.Setup()

preUpgradeChecks(s)

upgradeHeight := int64(5)
s.ConfirmUpgradeSucceeded(v20.UpgradeName, upgradeHeight)

postUpgradeChecks(s)
}

func preUpgradeChecks(s *UpgradeTestSuite) {
// Setup mainnet account
_, err := v20.CreateMainnetVestingAccount(s.Ctx, s.App.AppKeepers)
s.Require().NoError(err)

// Create 3 generic validators
val1 := s.SetupValidator(stakingtypes.Bonded)
val2 := s.SetupValidator(stakingtypes.Bonded)
val3 := s.SetupValidator(stakingtypes.Bonded)

// Get last validator, set as mock jack validator
val, found := s.App.AppKeepers.StakingKeeper.GetValidator(s.Ctx, val3)
s.Require().True(found)
v20.JackValidatorAddress = val.OperatorAddress

validators := []sdk.ValAddress{val1, val2, val3}

// Should equal 4, including default validator
s.Require().Equal(4, len(s.App.AppKeepers.StakingKeeper.GetAllValidators(s.Ctx)))

// Create delegations to each validator 2x, ensuring multiple delegations
// are created for each validator and combined in state.
for i := 0; i < 2; i++ {
for _, delegator := range v20.Core1VestingAccounts {
delegatorAddr := sdk.MustAccAddressFromBech32(delegator.Address)

for _, validator := range validators {
s.StakingHelper.Delegate(delegatorAddr, validator, sdk.NewInt(1_000_000))
}
}
}
}

func postUpgradeChecks(_ *UpgradeTestSuite) {
}
97 changes: 97 additions & 0 deletions app/upgrades/v20/upgrades.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package v20

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

"github.com/CosmosContracts/juno/v19/app/keepers"
"github.com/CosmosContracts/juno/v19/app/upgrades"
)

const (
// Charter Council's SubDAO Address
CharterCouncil = "juno1nmezpepv3lx45mndyctz2lzqxa6d9xzd2xumkxf7a6r4nxt0y95qypm6c0"
JackKey = "jack"
)

// JackValidatorAddress must be mutable for testing
var JackValidatorAddress = "junovaloper130mdu9a0etmeuw52qfxk73pn0ga6gawk2tz77l"

type IndividualAccount struct {
Owner string
Address string
}

// Core1VestingAccounts https://daodao.zone/dao/juno1j6glql3xmrcnga0gytecsucq3kd88jexxamxg3yn2xnqhunyvflqr7lxx3/members
var Core1VestingAccounts = []IndividualAccount{
{
Owner: "block",
Address: "juno17py8gfneaam64vt9kaec0fseqwxvkq0flmsmhg",
},
{
Owner: "dimi",
Address: "juno1s33zct2zhhaf60x4a90cpe9yquw99jj0zen8pt",
},
{
Owner: JackKey,
Address: "juno130mdu9a0etmeuw52qfxk73pn0ga6gawk4k539x",
},
{
Owner: "jake",
Address: "juno18qw9ydpewh405w4lvmuhlg9gtaep79vy2gmtr2",
},
{
Owner: "wolf",
Address: "juno1a8u47ggy964tv9trjxfjcldutau5ls705djqyu",
},
}

func CreateV20UpgradeHandler(
mm *module.Manager,
cfg module.Configurator,
k *keepers.AppKeepers,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
logger := ctx.Logger().With("upgrade", UpgradeName)

nativeDenom := upgrades.GetChainsDenomToken(ctx.ChainID())
logger.Info(fmt.Sprintf("With native denom %s", nativeDenom))

// Run migrations
logger.Info(fmt.Sprintf("pre migrate version map: %v", vm))
versionMap, err := mm.RunMigrations(ctx, cfg, vm)
if err != nil {
return nil, err
}
logger.Info(fmt.Sprintf("post migrate version map: %v", versionMap))

// Migrate Core-1 vesting account remaining funds -> Council SubDAO
if ctx.ChainID() == "juno-1" {
if err := migrateCore1VestingAccounts(ctx, k, nativeDenom); err != nil {
return nil, err
}
}

return versionMap, err
}
}

// Migrate balances from the Core-1 vesting accounts to the Council SubDAO.
func migrateCore1VestingAccounts(ctx sdk.Context, keepers *keepers.AppKeepers, bondDenom string) error {
for _, account := range Core1VestingAccounts {
// A new vesting contract will not be created if the account name is 'wolf'.
if err := MoveVestingCoinFromVestingAccount(ctx,
keepers,
bondDenom,
account.Owner,
sdk.MustAccAddressFromBech32(account.Address),
sdk.MustAccAddressFromBech32(CharterCouncil),
); err != nil {
return err
}
}
return nil
}
179 changes: 179 additions & 0 deletions app/upgrades/v20/vesting.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package v20

import (
"fmt"
"time"

"cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"
authvestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"

"github.com/CosmosContracts/juno/v19/app/keepers"
)

// Stops a vesting account and returns all tokens back to the council
func MoveVestingCoinFromVestingAccount(ctx sdk.Context, keepers *keepers.AppKeepers, bondDenom string, owner string, accAddr sdk.AccAddress, councilAccAddr sdk.AccAddress) error {
now := ctx.BlockHeader().Time

stdAcc := keepers.AccountKeeper.GetAccount(ctx, accAddr)
vacc, ok := stdAcc.(*authvestingtypes.PeriodicVestingAccount)
if !ok {
// For e2e testing
fmt.Printf("account " + accAddr.String() + " is not a vesting account.\n")
return nil
}

fmt.Printf("\n\n== Vesting Account Address: %s (%s) ==\n", vacc.GetAddress().String(), owner)

// Gets vesting coins (These get returned back to council / a new vesting contract made from)
vestingCoins := vacc.GetVestingCoins(now)
fmt.Printf("Vesting Coins: %v\n", vestingCoins)

// Display locked & spendable funds
lockedCoins := keepers.BankKeeper.LockedCoins(ctx, accAddr)
fmt.Printf("Locked Coins: %v\n", lockedCoins)
spendableCoins := keepers.BankKeeper.SpendableCoins(ctx, accAddr)
fmt.Printf("Spendable Coins: %v\n", spendableCoins)

// Instantly complete any re-deleations.
amt, err := completeAllRedelegations(ctx, now, keepers, accAddr)
if err != nil {
return err
}
fmt.Println("Redelegated Amount: ", amt)

// Instantly unbond all delegations.
amt, err = unbondAllAndFinish(ctx, now, keepers, owner, accAddr)
if err != nil {
return err
}
fmt.Println("Unbonded Amount: ", amt)

// Pre transfer balance
councilBeforeBal := keepers.BankKeeper.GetBalance(ctx, councilAccAddr, bondDenom)

// Set the vesting account to a base account
keepers.AccountKeeper.SetAccount(ctx, vacc.BaseAccount)

// Moves vesting tokens to the council.
if err := transferUnvestedTokensToCouncil(ctx, keepers, accAddr, councilAccAddr, vestingCoins); err != nil {
return err
}

// Log new council balance
councilAfterBal := keepers.BankKeeper.GetBalance(ctx, councilAccAddr, bondDenom)
fmt.Printf("Council Balance Before: %v\n", councilBeforeBal)
fmt.Printf("Council Balance After: %v\n", councilAfterBal)

// Ensure the post validation checks are met.
err = postValidation(ctx, keepers, bondDenom, owner, accAddr, councilAccAddr, vestingCoins, councilBeforeBal)
return err
}

func postValidation(ctx sdk.Context, keepers *keepers.AppKeepers, bondDenom string, owner string, accAddr sdk.AccAddress, councilAccAddr sdk.AccAddress, vestingCoins sdk.Coins, councilBeforeBal sdk.Coin) error {
// Council balance should only increase by exactly the council + vestedCoins
councilAfterBal := keepers.BankKeeper.GetBalance(ctx, councilAccAddr, bondDenom)
if !councilBeforeBal.Add(vestingCoins[0]).IsEqual(councilAfterBal) {
return fmt.Errorf("ERROR: core1BeforeBal (%v) + unvestedCoins (%v) != core1BalAfter (%v)", councilBeforeBal, vestingCoins, councilAfterBal)
}

// vesting account should have no future vesting periods
newVacc := keepers.AccountKeeper.GetAccount(ctx, accAddr)
if _, ok := newVacc.(*authvestingtypes.PeriodicVestingAccount); ok {
return fmt.Errorf("ERROR: account %s still is a vesting account", accAddr.String())
}

// ensure the account has 0 delegations, redelegations, or unbonding delegations,
// if the account is Jack's account, ensure it has 1 delegation to his validator
delegations := keepers.StakingKeeper.GetAllDelegatorDelegations(ctx, accAddr)
if !(len(delegations) == 0 || (owner == JackKey && len(delegations) == 1)) {
return fmt.Errorf("ERROR: account %s still has delegations", accAddr.String())
}

redelegations := keepers.StakingKeeper.GetRedelegations(ctx, accAddr, 65535)
if len(redelegations) != 0 {
return fmt.Errorf("ERROR: account %s still has redelegations", accAddr.String())
}

unbondingDelegations := keepers.StakingKeeper.GetAllUnbondingDelegations(ctx, accAddr)
if len(unbondingDelegations) != 0 {
return fmt.Errorf("ERROR: account %s still has unbonding delegations", accAddr.String())
}

return nil
}

// Transfer funds from the vesting account to the Council SubDAO.
func transferUnvestedTokensToCouncil(ctx sdk.Context, keepers *keepers.AppKeepers, accAddr sdk.AccAddress, councilAccAddr sdk.AccAddress, vestingCoins sdk.Coins) error {
fmt.Printf("Sending Vesting Coins to Council: %v\n", vestingCoins)
err := keepers.BankKeeper.SendCoins(ctx, accAddr, councilAccAddr, vestingCoins)
return err
}

// Completes all re-delegations and returns the amount of tokens which were re-delegated.
func completeAllRedelegations(ctx sdk.Context, now time.Time, keepers *keepers.AppKeepers, accAddr sdk.AccAddress) (math.Int, error) {
redelegatedAmt := math.ZeroInt()

for _, activeRedelegation := range keepers.StakingKeeper.GetRedelegations(ctx, accAddr, 65535) {
redelegationSrc, _ := sdk.ValAddressFromBech32(activeRedelegation.ValidatorSrcAddress)
redelegationDst, _ := sdk.ValAddressFromBech32(activeRedelegation.ValidatorDstAddress)

// set all entry completionTime to now so we can complete re-delegation
for i := range activeRedelegation.Entries {
activeRedelegation.Entries[i].CompletionTime = now
redelegatedAmt = redelegatedAmt.Add(math.Int(activeRedelegation.Entries[i].SharesDst))
}

keepers.StakingKeeper.SetRedelegation(ctx, activeRedelegation)
_, err := keepers.StakingKeeper.CompleteRedelegation(ctx, accAddr, redelegationSrc, redelegationDst)
if err != nil {
return redelegatedAmt, err
}
}

return redelegatedAmt, nil
}

// Returns the amount of tokens which were unbonded (not rewards)
func unbondAllAndFinish(ctx sdk.Context, now time.Time, keepers *keepers.AppKeepers, owner string, accAddr sdk.AccAddress) (math.Int, error) {
unbondedAmt := math.ZeroInt()

// Unbond all delegations from the account
for _, delegation := range keepers.StakingKeeper.GetAllDelegatorDelegations(ctx, accAddr) {
validatorValAddr := delegation.GetValidatorAddr()
if _, found := keepers.StakingKeeper.GetValidator(ctx, validatorValAddr); !found {
continue
}

// Jack's account has a delegation to his validator which is not unbonded.
if owner == JackKey && validatorValAddr.String() == JackValidatorAddress {
continue
}

_, err := keepers.StakingKeeper.Undelegate(ctx, accAddr, validatorValAddr, delegation.GetShares())
if err != nil {
return math.ZeroInt(), err
}
}

// Take all unbonding and complete them.
for _, unbondingDelegation := range keepers.StakingKeeper.GetAllUnbondingDelegations(ctx, accAddr) {
validatorStringAddr := unbondingDelegation.ValidatorAddress
validatorValAddr, _ := sdk.ValAddressFromBech32(validatorStringAddr)

// Complete unbonding delegation
for i := range unbondingDelegation.Entries {
unbondingDelegation.Entries[i].CompletionTime = now
unbondedAmt = unbondedAmt.Add(unbondingDelegation.Entries[i].Balance)
}

keepers.StakingKeeper.SetUnbondingDelegation(ctx, unbondingDelegation)
_, err := keepers.StakingKeeper.CompleteUnbonding(ctx, accAddr, validatorValAddr)
if err != nil {
return math.ZeroInt(), err
}
}

return unbondedAmt, nil
}
Loading