github.com/Finschia/finschia-sdk@v0.48.1/simapp/simd/cmd/genaccounts.go (about) 1 package cmd 2 3 import ( 4 "bufio" 5 "encoding/json" 6 "errors" 7 "fmt" 8 9 "github.com/spf13/cobra" 10 11 "github.com/Finschia/finschia-sdk/client" 12 "github.com/Finschia/finschia-sdk/client/flags" 13 "github.com/Finschia/finschia-sdk/crypto/keyring" 14 "github.com/Finschia/finschia-sdk/server" 15 sdk "github.com/Finschia/finschia-sdk/types" 16 authtypes "github.com/Finschia/finschia-sdk/x/auth/types" 17 authvesting "github.com/Finschia/finschia-sdk/x/auth/vesting/types" 18 banktypes "github.com/Finschia/finschia-sdk/x/bank/types" 19 "github.com/Finschia/finschia-sdk/x/genutil" 20 genutiltypes "github.com/Finschia/finschia-sdk/x/genutil/types" 21 ) 22 23 const ( 24 flagVestingStart = "vesting-start-time" 25 flagVestingEnd = "vesting-end-time" 26 flagVestingAmt = "vesting-amount" 27 ) 28 29 // AddGenesisAccountCmd returns add-genesis-account cobra Command. 30 func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { 31 cmd := &cobra.Command{ 32 Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]", 33 Short: "Add a genesis account to genesis.json", 34 Long: `Add a genesis account to genesis.json. The provided account must specify 35 the account address or key name and a list of initial coins. If a key name is given, 36 the address will be looked up in the local Keybase. The list of initial tokens must 37 contain valid denominations. Accounts may optionally be supplied with vesting parameters. 38 `, 39 Args: cobra.ExactArgs(2), 40 RunE: func(cmd *cobra.Command, args []string) error { 41 clientCtx := client.GetClientContextFromCmd(cmd) 42 serverCtx := server.GetServerContextFromCmd(cmd) 43 config := serverCtx.Config 44 45 config.SetRoot(clientCtx.HomeDir) 46 47 var kb keyring.Keyring 48 addr, err := sdk.AccAddressFromBech32(args[0]) 49 if err != nil { 50 inBuf := bufio.NewReader(cmd.InOrStdin()) 51 keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) 52 if keyringBackend != "" && clientCtx.Keyring == nil { 53 var err error 54 // attempt to lookup address from Keybase if no address was provided 55 kb, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) 56 if err != nil { 57 return err 58 } 59 } else { 60 kb = clientCtx.Keyring 61 } 62 63 info, err := kb.Key(args[0]) 64 if err != nil { 65 return fmt.Errorf("failed to get address from Keyring: %w", err) 66 } 67 addr = info.GetAddress() 68 } 69 70 coins, err := sdk.ParseCoinsNormalized(args[1]) 71 if err != nil { 72 return fmt.Errorf("failed to parse coins: %w", err) 73 } 74 75 vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) 76 vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) 77 vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) 78 79 vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) 80 if err != nil { 81 return fmt.Errorf("failed to parse vesting amount: %w", err) 82 } 83 84 // create concrete account type based on input parameters 85 var genAccount authtypes.GenesisAccount 86 87 balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} 88 baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) 89 90 if !vestingAmt.IsZero() { 91 baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) 92 93 if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || 94 baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { 95 return errors.New("vesting amount cannot be greater than total amount") 96 } 97 98 switch { 99 case vestingStart != 0 && vestingEnd != 0: 100 genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) 101 102 case vestingEnd != 0: 103 genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount) 104 105 default: 106 return errors.New("invalid vesting parameters; must supply start and end time or end time") 107 } 108 } else { 109 genAccount = baseAccount 110 } 111 112 if err := genAccount.Validate(); err != nil { 113 return fmt.Errorf("failed to validate new genesis account: %w", err) 114 } 115 116 genFile := config.GenesisFile() 117 appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) 118 if err != nil { 119 return fmt.Errorf("failed to unmarshal genesis state: %w", err) 120 } 121 122 authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) 123 124 accs, err := authtypes.UnpackAccounts(authGenState.Accounts) 125 if err != nil { 126 return fmt.Errorf("failed to get accounts from any: %w", err) 127 } 128 129 if accs.Contains(addr) { 130 return fmt.Errorf("cannot add account at existing address %s", addr) 131 } 132 133 // Add the new account to the set of genesis accounts and sanitize the 134 // accounts afterwards. 135 accs = append(accs, genAccount) 136 accs = authtypes.SanitizeGenesisAccounts(accs) 137 138 genAccs, err := authtypes.PackAccounts(accs) 139 if err != nil { 140 return fmt.Errorf("failed to convert accounts into any's: %w", err) 141 } 142 authGenState.Accounts = genAccs 143 144 authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) 145 if err != nil { 146 return fmt.Errorf("failed to marshal auth genesis state: %w", err) 147 } 148 149 appState[authtypes.ModuleName] = authGenStateBz 150 151 bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) 152 bankGenState.Balances = append(bankGenState.Balances, balances) 153 bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) 154 bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) 155 156 bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) 157 if err != nil { 158 return fmt.Errorf("failed to marshal bank genesis state: %w", err) 159 } 160 161 appState[banktypes.ModuleName] = bankGenStateBz 162 163 appStateJSON, err := json.Marshal(appState) 164 if err != nil { 165 return fmt.Errorf("failed to marshal application genesis state: %w", err) 166 } 167 168 genDoc.AppState = appStateJSON 169 return genutil.ExportGenesisFile(genDoc, genFile) 170 }, 171 } 172 173 cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") 174 cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") 175 cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") 176 cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") 177 cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts") 178 flags.AddQueryFlagsToCmd(cmd) 179 180 return cmd 181 }