Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions app/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func (app *TacChainApp) RegisterUpgradeHandlers() {
LiquidStakeKeeper: &app.LiquidStakeKeeper,
BankKeeper: app.BankKeeper,
Erc20Keeper: &app.Erc20Keeper,
StakingKeeper: app.StakingKeeper,
}
app.GetStoreKeys()
// register all upgrade handlers
Expand Down
2 changes: 2 additions & 0 deletions app/upgrades/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper"
paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"

bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
evmerc20keeper "github.com/cosmos/evm/x/erc20/keeper"
Expand All @@ -31,6 +32,7 @@ type AppKeepers struct {
LiquidStakeKeeper *liquidstakekeeper.Keeper
BankKeeper bankkeeper.Keeper
Erc20Keeper *evmerc20keeper.Keeper
StakingKeeper *stakingkeeper.Keeper
}

type ModuleManager interface {
Expand Down
109 changes: 100 additions & 9 deletions app/upgrades/v1.0.2/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@ package v102

import (
"context"
"errors"
"fmt"
"regexp"

"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
upgradetypes "cosmossdk.io/x/upgrade/types"

"github.com/Asphere-xyz/tacchain/app/upgrades"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
evmerc20types "github.com/cosmos/evm/x/erc20/types"

"github.com/ethereum/go-ethereum/common"
"golang.org/x/crypto/sha3"

)

var WhitelistAdminAddressNotFound = errors.New("failed to find whitelist admin address")

// UpgradeName defines the on-chain upgrade name
const UpgradeName = "v1.0.2"

Expand All @@ -30,14 +36,6 @@ var Upgrade = upgrades.Upgrade{
},
}

func generateAddressFromDenom(denom string) (common.Address, error) {
hash := sha3.NewLegacyKeccak256()
if _, err := hash.Write([]byte(denom)); err != nil {
return common.Address{}, err
}
return common.BytesToAddress(hash.Sum(nil)), nil
}

func CreateUpgradeHandler(
mm upgrades.ModuleManager,
configurator module.Configurator,
Expand Down Expand Up @@ -69,6 +67,99 @@ func CreateUpgradeHandler(

ak.Erc20Keeper.SetToken(sdkCtx, lsmTokenPair)

logger := sdkCtx.Logger()
params := ak.LiquidStakeKeeper.GetParams(sdkCtx)
adminAddress, err := getAdminAddressFromPlanInfo(plan.Info)
switch err {
case WhitelistAdminAddressNotFound, nil:
default:
logger.Error("invalid whitelist admin address in plan info", "error", err)
}
params.WhitelistAdminAddress = adminAddress
if err := ak.LiquidStakeKeeper.SetParams(sdkCtx, params); err != nil {
return newVM, fmt.Errorf("failed to set params for liquidstake module: %w", err)
}

stakingParams, err := ak.StakingKeeper.GetParams(ctx)
if err != nil {
return newVM, err
}

stakingParams.ValidatorBondFactor = stakingtypes.DefaultValidatorBondFactor
stakingParams.GlobalLiquidStakingCap = stakingtypes.DefaultGlobalLiquidStakingCap
stakingParams.ValidatorLiquidStakingCap = stakingtypes.DefaultValidatorLiquidStakingCap

if err := ak.StakingKeeper.SetParams(ctx, stakingParams); err != nil {
return newVM, fmt.Errorf("failed to set params for staking module: %w", err)
}

if err := initializeNewValidatorFields(ctx, ak); err != nil {
return newVM, fmt.Errorf("failed to initialize new validtor fields: %w", err)
}

return newVM, nil
}
}

func generateAddressFromDenom(denom string) (common.Address, error) {
hash := sha3.NewLegacyKeccak256()
if _, err := hash.Write([]byte(denom)); err != nil {
return common.Address{}, err
}
return common.BytesToAddress(hash.Sum(nil)), nil
}

func initializeNewValidatorFields(ctx context.Context, ak *upgrades.AppKeepers) error {
params, err := ak.StakingKeeper.GetParams(ctx)
if err != nil {
return fmt.Errorf("failed to get staking params: %w", err)
}

validators, err := ak.StakingKeeper.GetValidators(ctx, params.MaxValidators)
if err != nil {
return fmt.Errorf("failed to get validators: %w", err)
}

for _, validator := range validators {
newValidator := validator
newValidator.ValidatorBondShares = math.LegacyZeroDec()
newValidator.LiquidShares = math.LegacyZeroDec()

err = ak.StakingKeeper.RemoveValidator(ctx, sdk.ValAddress(validator.OperatorAddress))
if err != nil {
return fmt.Errorf("failed to remove validator: %w", err)
}
err = ak.StakingKeeper.SetValidator(ctx, newValidator)
if err != nil {
return fmt.Errorf("failed to set validator: %w", err)
}
err = ak.StakingKeeper.SetValidatorByConsAddr(ctx, newValidator)
if err != nil {
return fmt.Errorf("failed to set validator by consensus address: %w", err)
}
err = ak.StakingKeeper.SetValidatorByPowerIndex(ctx, newValidator)
if err != nil {
return fmt.Errorf("failed to set validator by power index: %w", err)
}
}

return nil
}

func getAdminAddressFromPlanInfo(info string) (string, error) {
key := "whitelist_admin_address"
addressPrefix := sdk.GetConfig().GetBech32AccountAddrPrefix()
re := regexp.MustCompile(key + `:\s*(` + addressPrefix + `[a-zA-Z0-9]+)`)
matches := re.FindStringSubmatch(info)

var addr string
if len(matches) > 1 {
addr = matches[1]
} else {
return "", WhitelistAdminAddressNotFound
}
if _, err := sdk.AccAddressFromBech32(addr); err != nil {
return "", fmt.Errorf("failed to validate whitelist admin address %s: %w", addr, err)
}
return addr, nil
}
37 changes: 37 additions & 0 deletions app/upgrades/v1.0.2/upgrades_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package v102

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)

func TestGetAdminAddressFromPlanInfo(t *testing.T) {
testCases := []struct {
info string
expected string
expectedError bool
}{
{
info: "",
expected: "",
expectedError: true,
},
{
info: "This proposal aims to add liquid stake possibility for the TAC network. whitelist_admin_address: tac15lvhklny0khnwy7hgrxsxut6t6ku2cgknw79fr",
expected: "tac15lvhklny0khnwy7hgrxsxut6t6ku2cgknw79fr",
expectedError: false,
},
}

sdk.GetConfig().SetBech32PrefixForAccount("tac", "tacpub")

for _, tc := range testCases {
addr, err := getAdminAddressFromPlanInfo(tc.info)
if !tc.expectedError && err != nil {
t.Error(err)
}
require.Equal(t, tc.expected, addr)
}
}
10 changes: 10 additions & 0 deletions proposals/liquidstake_upgrade/1_admin_tx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"liquid_bond_denom": "stk/utac",
"unstake_fee_rate": "0.000000000000000000",
"lsm_disabled": true,
"min_liquid_stake_amount": "1000",
"cw_locked_pool_address": "",
"fee_account_address": "tac15lvhklny0khnwy7hgrxsxut6t6ku2cgknw79fr",
"autocompound_fee_rate": "0.050000000000000000",
"whitelist_admin_address": "tac15lvhklny0khnwy7hgrxsxut6t6ku2cgknw79fr"
}
6 changes: 6 additions & 0 deletions proposals/liquidstake_upgrade/2_admin_tx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"validator_address": "tacvaloper15lvhklny0khnwy7hgrxsxut6t6ku2cgkwu9tyt",
"target_weight": "10000"
}
]
57 changes: 52 additions & 5 deletions proposals/liquidstake_upgrade/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,56 @@
## Liquidstake upgrade

**Steps:**
1. **Send gov tx to upgrade binary**

[Localnet example](./example_step_1.json)
2. **Send gov tx to update module params**
1. Prepare proposal.

[Localnet example](./example_step_2.json)
**Important note**: If you want to set the `WhitelistAdminAddress`, you need to add the line `whitelist_admin_address: <your_whitelist_admin_address>` (e.g., tac15lvhklny0khnwy7hgrxsxut6t6ku2cgknw79fr) to the `plan.info` variable in the governance transaction message. The address must be valid; otherwise, an error log will appear during the update, and you will have to submit the governance transaction again.
2. Send gov tx to upgrade binary. (e.g., [gov_transaction.json](./gov_transaction.json))
3. Send admin tx to update module state.

- Update params. (e.g., [1_admin_tx.json](./1_admin_tx.json))
- Update validators. (e.g., [2_admin_tx.json](./2_admin_tx.json))

**Localnet Node Upgrade Checklist (v1.0.1 to v1.0.2)**

1. Initial Setup and Governance Proposal
1. Checkout to the old node version.
2. Build the old version.
```shell
make build
```
3. Initialize and start the local network (with a short voting period).
```shell
make localnet-init GOV_TIME_SECONDS=60 TACCHAIND=./build/tacchaind
make localnet-start TACCHAIND=./build/tacchaind
```
4. (New Session) Submit the upgrade governance proposal (targeting height 400).
```shell
./build/tacchaind tx gov submit-proposal ./proposals/liquidstake_upgrade/gov_transaction.json --from validator --fees 200000000000000000utac --gas-adjustment 2 --gas 500000
```
5. Vote 'Yes' on the proposal.
```shell
./build/tacchaind tx gov vote 1 yes --from validator --fees 80000000000000000utac
```
6. Wait for the node to stop automatically at upgrade height (400).
2. Upgrade the Node Software
1. Checkout to the new node version.
2. Build the new version.
```shell
make build
```
3. Restart the node using the new binary.
```shell
make localnet-start TACCHAIND=./build/tacchaind
```
4. Verification: Node starts successfully at height 400.
3. Post-Upgrade Liquidstake Module Configuration
1. Update Liquidstake module parameters (e.g., setting the admin address).
```shell
tacchaind tx liquidstake update-params ./proposals/liquidstake_upgrade/1_admin_tx.json --from validator --fees 80000000000000000utac
```
2. Unpause/enable the Liquidstake module.
```shell
tacchaind tx liquidstake pause-module false --from validator --fees 80000000000000000utac
```

The upgraded node is successfully running, and the module is active.
19 changes: 0 additions & 19 deletions proposals/liquidstake_upgrade/example_step_1.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,34 +1,15 @@
{
"messages": [
{
"@type": "/tac.liquidstake.v1beta1.MsgUpdateParams",
"@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade",
"authority": "tac10d07y265gmmuvt4z0w9aw880jnsr700jlgpywe",
"params": {
"liquid_bond_denom": "stk/utac",
"unstake_fee_rate": "0.000000000000000000",
"lsm_disabled": true,
"min_liquid_stake_amount": "1000",
"cw_locked_pool_address": "",
"fee_account_address": "tac1w2q3mashs2k4wcpqzs5q5xewnhnnr7wslr34safzvwqzvuqh3gjqn6xzrj",
"autocompound_fee_rate": "0.050000000000000000",
"whitelist_admin_address": "tac1w2q3mashs2k4wcpqzs5q5xewnhnnr7wslr34safzvwqzvuqh3gjqn6xzrj"
"plan": {
"name": "v1.0.2",
"height": "400",
"info": "This proposal aims to add liquid stake possibility for the TAC network. whitelist_admin_address: tac15lvhklny0khnwy7hgrxsxut6t6ku2cgknw79fr",
"upgraded_client_state": null
}
},
{
"@type": "/tac.liquidstake.v1beta1.MsgUpdateWhitelistedValidators",
"authority": "tac10d07y265gmmuvt4z0w9aw880jnsr700jlgpywe",
"whitelisted_validators": [
{
"validator_address": "tacvaloper15lvhklny0khnwy7hgrxsxut6t6ku2cgkwu9tyt",
"target_weight": "10000"
}
]
},
{
"@type": "/tac.liquidstake.v1beta1.MsgSetModulePaused",
"authority": "tac10d07y265gmmuvt4z0w9aw880jnsr700jlgpywe",
"is_paused": false
},
{
"@type": "/cosmos.evm.vm.v1.MsgUpdateParams",
"authority": "tac10d07y265gmmuvt4z0w9aw880jnsr700jlgpywe",
Expand Down Expand Up @@ -90,9 +71,9 @@
}
}
],
"metadata": "<url/to/metadata>",
"metadata": "https://github.com/TacBuild/tacchain/pull/61",
"deposit": "1000000000000000000utac",
"title": "Update Liquidstake params",
"summary": "Liquidstake params",
"title": "Add liquid staking functionality to TAC network",
"summary": "The main liquid stake module is compatible with the existing staking and ERC-20 modules of the TAC node, introducing liquid staking tokens (gTAC) that are automatically represented as ERC-20 assets. The second module expands the capabilities of liquid staking and allows users to transfer staked funds to LST bypassing an unbound staking period",
"expedited": false
}
Loading