-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: make helper function for adding accounts to genesis state (#13298)
- Loading branch information
1 parent
b853d3f
commit 09b0f58
Showing
3 changed files
with
141 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package helpers | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
"github.com/cosmos/cosmos-sdk/x/genutil" | ||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" | ||
) | ||
|
||
// AddGenesisAccount adds a genesis account to the genesis state. | ||
// Where `cdc` is client codec, `genesisFileUrl` is the path/url of current genesis file, | ||
// `accAddr` is the address to be added to the genesis state, `amountStr` is the list of initial coins | ||
// to be added for the account, `appendAcct` updates the account if already exists. | ||
// `vestingStart, vestingEnd and vestingAmtStr` respectively are the schedule start time, end time (unix epoch) | ||
// and coins to be appended to the account already in the genesis.json file. | ||
func AddGenesisAccount( | ||
cdc codec.Codec, | ||
accAddr sdk.AccAddress, | ||
appendAcct bool, | ||
genesisFileUrl, amountStr, vestingAmtStr string, | ||
vestingStart, vestingEnd int64, | ||
) error { | ||
coins, err := sdk.ParseCoinsNormalized(amountStr) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse coins: %w", err) | ||
} | ||
|
||
vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse vesting amount: %w", err) | ||
} | ||
|
||
// create concrete account type based on input parameters | ||
var genAccount authtypes.GenesisAccount | ||
|
||
balances := banktypes.Balance{Address: accAddr.String(), Coins: coins.Sort()} | ||
baseAccount := authtypes.NewBaseAccount(accAddr, nil, 0, 0) | ||
|
||
if !vestingAmt.IsZero() { | ||
baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) | ||
|
||
if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || | ||
baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { | ||
return errors.New("vesting amount cannot be greater than total amount") | ||
} | ||
|
||
switch { | ||
case vestingStart != 0 && vestingEnd != 0: | ||
genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) | ||
|
||
case vestingEnd != 0: | ||
genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) | ||
|
||
default: | ||
return errors.New("invalid vesting parameters; must supply start and end time or end time") | ||
} | ||
} else { | ||
genAccount = baseAccount | ||
} | ||
|
||
if err := genAccount.Validate(); err != nil { | ||
return fmt.Errorf("failed to validate new genesis account: %w", err) | ||
} | ||
|
||
appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genesisFileUrl) | ||
if err != nil { | ||
return fmt.Errorf("failed to unmarshal genesis state: %w", err) | ||
} | ||
|
||
authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) | ||
|
||
accs, err := authtypes.UnpackAccounts(authGenState.Accounts) | ||
if err != nil { | ||
return fmt.Errorf("failed to get accounts from any: %w", err) | ||
} | ||
|
||
bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState) | ||
if accs.Contains(accAddr) { | ||
if !appendAcct { | ||
return fmt.Errorf(" Account %s already exists\nUse `append` flag to append account at existing address", accAddr) | ||
} | ||
|
||
genesisB := banktypes.GetGenesisStateFromAppState(cdc, appState) | ||
for idx, acc := range genesisB.Balances { | ||
if acc.Address != accAddr.String() { | ||
continue | ||
} | ||
|
||
updatedCoins := acc.Coins.Add(coins...) | ||
bankGenState.Balances[idx] = banktypes.Balance{Address: accAddr.String(), Coins: updatedCoins.Sort()} | ||
break | ||
} | ||
} else { | ||
// Add the new account to the set of genesis accounts and sanitize the accounts afterwards. | ||
accs = append(accs, genAccount) | ||
accs = authtypes.SanitizeGenesisAccounts(accs) | ||
|
||
genAccs, err := authtypes.PackAccounts(accs) | ||
if err != nil { | ||
return fmt.Errorf("failed to convert accounts into any's: %w", err) | ||
} | ||
authGenState.Accounts = genAccs | ||
|
||
authGenStateBz, err := cdc.MarshalJSON(&authGenState) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal auth genesis state: %w", err) | ||
} | ||
appState[authtypes.ModuleName] = authGenStateBz | ||
|
||
bankGenState.Balances = append(bankGenState.Balances, balances) | ||
} | ||
|
||
bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) | ||
|
||
bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) | ||
|
||
bankGenStateBz, err := cdc.MarshalJSON(bankGenState) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal bank genesis state: %w", err) | ||
} | ||
appState[banktypes.ModuleName] = bankGenStateBz | ||
|
||
appStateJSON, err := json.Marshal(appState) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal application genesis state: %w", err) | ||
} | ||
|
||
genDoc.AppState = appStateJSON | ||
return genutil.ExportGenesisFile(genDoc, genesisFileUrl) | ||
} |