Skip to content

Commit

Permalink
feat: initial empty command
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathansumner committed Apr 16, 2024
1 parent 18ddc93 commit 2ef335f
Show file tree
Hide file tree
Showing 3 changed files with 283 additions and 1 deletion.
2 changes: 1 addition & 1 deletion app/prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

const (
AccountAddressPrefix = "fetch"
AccountAddressPrefix = "asi"
)

var (
Expand Down
281 changes: 281 additions & 0 deletions cmd/fetchd/cmd/genasiupgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
package cmd

import (
"encoding/json"
"fmt"
"github.com/btcsuite/btcutil/bech32"
"github.com/cosmos/cosmos-sdk/codec"
cosmostypes "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
"regexp"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server"
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"
)

const (
flagNewDescription = "new-description"
Bech32Chars = "023456789acdefghjklmnpqrstuvwxyz"
AddrDataLength = 32
WasmDataLength = 52
AddrChecksumLength = 6
AccAddressPrefix = ""
ValAddressPrefix = "valoper"
ConsAddressPrefix = "valcons"

NewBaseDenom = "asi"
NewDenom = "aasi"
NewAddrPrefix = "asi"
NewChainId = "asi-1"
NewDescription = "ASI Token"

OldBaseDenom = "fet"
OldDenom = "afet"
OldAddrPrefix = "fetch"
)

//" fetch char* [bech32 chars] limited by size " CHECKSUM?
//verify functions after!

// ASIGenesisUpgradeCmd returns replace-genesis-values cobra Command.
func ASIGenesisUpgradeCmd(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "asi-genesis-upgrade",
Short: "This command carries out a full upgrade of the genesis file to the new ASI chain parameters.",
Long: `The following command will upgrade the current genesis file to the new ASI chain parameters. The following changes will be made:
- Chain ID will be updated to "asi-1"
- The native coin denom will be updated to "asi"
- The address prefix will be updated to "asi"
- The old fetch addresses will be updated to the new asi addresses`,

Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
cdc := clientCtx.Codec

serverCtx := server.GetServerContextFromCmd(cmd)
config := serverCtx.Config

config.SetRoot(clientCtx.HomeDir)

genFile := config.GenesisFile()

appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile)
if err != nil {
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
}

// replace chain-id
ASIGenesisUpgradeReplaceChainID(genDoc)

// set denom metadata in bank module
err = ASIGenesisUpgradeReplaceDenomMetadata(cdc, &appState)
if err != nil {
return fmt.Errorf("failed to replace denom metadata: %w", err)
}

appStateJSON, err := json.Marshal(appState)
if err != nil {
return fmt.Errorf("failed to marshal application genesis state: %w", err)
}

appStateStr := string(appStateJSON)

// replace denom across the genesis file
ASIGenesisUpgradeReplaceDenom(&appStateStr)

// replace addresses across the genesis file
ASIGenesisUpgradeReplaceAddresses(&appStateStr)

genDoc.AppState = []byte(appStateStr)
return genutil.ExportGenesisFile(genDoc, genFile)
},
}

cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
cmd.Flags().String(flagNewDescription, "", "The new description for the native coin in the genesis file")
flags.AddQueryFlagsToCmd(cmd)

return cmd
}

func ASIGenesisUpgradeReplaceDenomMetadata(cdc codec.Codec, appState *map[string]json.RawMessage) error {
bankGenState := banktypes.GetGenesisStateFromAppState(cdc, *appState)

OldBaseDenomUpper := strings.ToUpper(OldBaseDenom)
NewBaseDenomUpper := strings.ToUpper(NewBaseDenom)

denomRegex := getRegex(OldDenom, NewDenom)
upperDenomRegex := getRegex(OldBaseDenomUpper, NewBaseDenomUpper)
exponentDenomRegex := getPartialRegexLeft(OldBaseDenom, NewBaseDenom)

for _, metadata := range bankGenState.DenomMetadata {
replaceString(&metadata.Base, []*regexPair{denomRegex})
if metadata.Name == OldBaseDenomUpper {
metadata.Description = NewDescription
metadata.Display = NewBaseDenomUpper
metadata.Name = NewBaseDenomUpper
metadata.Symbol = NewBaseDenomUpper
}
for _, unit := range metadata.DenomUnits {
replaceString(&unit.Denom, []*regexPair{upperDenomRegex})
replaceString(&unit.Denom, []*regexPair{exponentDenomRegex})
}
}

bankGenStateBytes, err := cdc.MarshalJSON(bankGenState)
if err != nil {
return fmt.Errorf("failed to marshal auth genesis state: %w", err)
}

(*appState)[banktypes.ModuleName] = bankGenStateBytes
return nil
}

func ASIGenesisUpgradeReplaceChainID(genesisData *types.GenesisDoc) {
genesisData.ChainID = NewChainId
}

func ASIGenesisUpgradeReplaceDenom(jsonString *string) {
for _, target := range []string{"denom", "bond_denom", "mint_denom", "base_denom", "base"} {
re := regexp.MustCompile(fmt.Sprintf(`("%s"\s*:\s*)"%s"`, target, OldDenom))
if re.MatchString(*jsonString) {
*jsonString = re.ReplaceAllString(*jsonString, fmt.Sprintf(`${1}"%s"`, NewDenom))
}
}
}

func ASIGenesisUpgradeReplaceAddresses(jsonString *string) {
// account addresses
replaceAddresses(AccAddressPrefix, jsonString, AddrDataLength+AddrChecksumLength)
// validator addresses
replaceAddresses(ValAddressPrefix, jsonString, AddrDataLength+AddrChecksumLength)
// consensus addresses
replaceAddresses(ConsAddressPrefix, jsonString, AddrDataLength+AddrChecksumLength)
// contract addresses
replaceAddresses(AccAddressPrefix, jsonString, WasmDataLength+AddrChecksumLength)
}

func replaceAddresses(addressTypePrefix string, jsonString *string, dataLength int) {
re := regexp.MustCompile(fmt.Sprintf(`"%s%s1([%s]{%d})"`, OldAddrPrefix, addressTypePrefix, Bech32Chars, dataLength))
matches := re.FindAllString(*jsonString, -1)

replacements := make(map[string]string, len(matches))
for _, match := range matches {
matchedAddr := strings.ReplaceAll(match, `"`, "")
_, decodedAddrData, err := bech32.Decode(matchedAddr)
if err != nil {
panic(err)
}

newAddress, err := bech32.Encode(NewAddrPrefix+addressTypePrefix, decodedAddrData)
if err != nil {
panic(err)
}

err = cosmostypes.VerifyAddressFormat(decodedAddrData)
if err != nil {
panic(err)
}

switch addressTypePrefix {
case AccAddressPrefix:
_, err = cosmostypes.AccAddressFromBech32(newAddress)
case ValAddressPrefix:
_, err = cosmostypes.ValAddressFromBech32(newAddress)
case ConsAddressPrefix:
_, err = cosmostypes.ConsAddressFromBech32(newAddress)
default:
panic("invalid address type prefix")
}
if err != nil {
panic(err)
}
replacements[matchedAddr] = newAddress
}

var jsonData map[string]interface{}
err := json.Unmarshal([]byte(*jsonString), &jsonData)
if err != nil {
panic(err)
}

modified := crawlJson(jsonData, func(data interface{}) interface{} {
if str, ok := data.(string); ok {
if !re.MatchString(fmt.Sprintf(`"%s"`, str)) || len(str) > 200 {
return data
}

return replacements[str]
}
return data
})

modifiedJSON, err := json.Marshal(modified)
if err != nil {
panic(err)
}
*jsonString = string(modifiedJSON)
}

func ASIGenesisUpgradeWithdrawIBCChannelsBalances() {

}

func ASIGenesisUpgradeWithdrawReconciliationBalances() {

}

func getRegex(oldValue string, newValue string) *regexPair {
return &regexPair{
pattern: fmt.Sprintf(`^%s$`, oldValue),
replacement: fmt.Sprintf(`%s`, newValue),
}
}

func getPartialRegexLeft(oldValue string, newValue string) *regexPair {
return &regexPair{
pattern: fmt.Sprintf(`(.*?)%s"`, oldValue),
replacement: fmt.Sprintf(`${1}%s"`, newValue),
}
}

func replaceString(s *string, replacements []*regexPair) {
for _, pair := range replacements {
re := regexp.MustCompile(pair.pattern)
if re.MatchString(*s) {
*s = re.ReplaceAllString(*s, pair.replacement)
}
}
}

type regexPair struct {
pattern string
replacement string
}

func crawlJson(data interface{}, strHandler func(interface{}) interface{}) interface{} {
switch value := data.(type) {
case string:
if strHandler != nil {
return strHandler(data)
}
case []interface{}:
for i := range value {
value[i] = crawlJson(value[i], strHandler)
}
case map[string]interface{}:
for k := range value {
value[k] = crawlJson(value[k], strHandler)
}
default:
}
return data
}
1 change: 1 addition & 0 deletions cmd/fetchd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
// AddStakeReconciliationMigrateCmd(),
genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
genutilcli.ValidateGenesisCmd(app.ModuleBasics),
ASIGenesisUpgradeCmd(app.DefaultNodeHome),
AddGenesisAccountCmd(app.DefaultNodeHome),
AddGenesisDelegationCmd(app.DefaultNodeHome),
ReplaceGenesisValuesCmd(app.DefaultNodeHome),
Expand Down

0 comments on commit 2ef335f

Please sign in to comment.