Skip to content

Commit

Permalink
transform normal denom to base denom and mod value (#5947)
Browse files Browse the repository at this point in the history
  • Loading branch information
czarcas7ic authored Aug 7, 2023
1 parent e1552a3 commit 59c5a8c
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 21 deletions.
18 changes: 15 additions & 3 deletions cmd/osmosisd/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,19 +171,31 @@ const defaultConfigTemplate = `# This is a TOML config file.
# The network chain ID
chain-id = "{{ .ChainID }}"
# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory)
keyring-backend = "{{ .KeyringBackend }}"
# CLI output format (text|json)
output = "{{ .Output }}"
# <host>:<port> to Tendermint RPC interface for this chain
node = "{{ .Node }}"
# Transaction broadcasting mode (sync|async)
broadcast-mode = "{{ .BroadcastMode }}"
# Human-readable denoms
# If enabled, when using CLI, user can input base denoms (baseatom, basescrt, baseweth, basewbtc, basewbtc.grv etc.) instead of their ibc equivalents.
# Human-readable denoms: Input
# If enabled, when using CLI, user can input 0 exponent denoms (atom, scrt, avax, wbtc, etc.) instead of their ibc equivalents.
# Note, this will also change the coin's value to it's base value if the input or flag is a coin.
# Example:
# * 10.45atom input will automatically change to 10450000ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2
# * uakt will change to ibc/1480B8FD20AD5FCAE81EA87584D269547DD4D436843C1D20F15E00EB64743EF4
# * 12000000uscrt will change to 12000000ibc/0954E1C28EB7AF5B72D24F3BC2B47BBB2FDF91BDDFD57B74B99E133AED40972A
# This feature isn't stable yet, and outputs will change in subsequent releases
human-readable-denoms-input = {{ .HumanReadableDenomsInput }}
# If enabled, CLI response return base denoms (baseatom, basescrt, baseweth, basewbtc, basewbtc.grv etc.) instead of their ibc equivalents.
# Human-readable denoms: Output
# If enabled, CLI response return base denoms (uatom, uscrt, wavax-wei, wbtc-satoshi, etc.) instead of their ibc equivalents.
# This feature isn't stable yet, and outputs will change in subsequent releases
human-readable-denoms-output = {{ .HumanReadableDenomsOutput }}
Expand Down
89 changes: 71 additions & 18 deletions cmd/osmosisd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ type Asset struct {
}

type DenomUnit struct {
Denom string `json:"denom"`
Exponent uint64 `json:"exponent"`
Denom string `json:"denom"`
Exponent uint64 `json:"exponent"`
Aliases []string `json:"aliases"`
}

type Trace struct {
Expand All @@ -79,8 +80,8 @@ type Trace struct {
}

type DenomUnitMap struct {
Base string
DenomUnits []DenomUnit `json:"denom_units"`
Base string
Exponent uint64 `json:"exponent"`
}

var (
Expand Down Expand Up @@ -143,16 +144,38 @@ func loadAssetList(initClientCtx client.Context, cmd *cobra.Command, basedenomTo

if basedenomToIBC {
for _, asset := range assetList.Assets {
DenomUnitMap := DenomUnitMap{
Base: asset.Base,
DenomUnits: asset.DenomUnits,
// Each asset has a list of denom units. A majority of them have 2 entries, one being the base 0 exponent denom and the other being a larger exponent denom.
// An example for tether:
// * Exponent 0: uusdt
// * Exponent 6: usdt
// This implies that if a usdt value is given, in order to convert it to it's base denom (uusdt), we need to multiply the provided value by 10^6.
for i, denomUnit := range asset.DenomUnits {
DenomUnitMap := DenomUnitMap{
Base: asset.Base,
Exponent: asset.DenomUnits[i].Exponent,
}
// The 0 exponent denom is the base denom.
if asset.DenomUnits[i].Exponent == 0 {
// To make everyone's life harder, some assets have multiple base denom aliases. For example, the asset list has the following base aliases for the asset "luna":
// * uluna
// * microluna
for _, alias := range denomUnit.Aliases {
baseMap[strings.ToLower(alias)] = DenomUnitMap
}
} else {
// Otherwise we just store the denom alias for that exponent.
baseMap[strings.ToLower(denomUnit.Denom)] = DenomUnitMap
}
}
baseMap["base"+strings.ToLower(asset.Symbol)] = DenomUnitMap
}
}
if IBCtoBasedenom {
// We just store a link from the first base denom alias to the IBC denom. This is just used for display purposes on the terminal's output.
for _, asset := range assetList.Assets {
baseMapRev[asset.Base] = "base" + strings.ToLower(asset.Symbol)
if len(asset.DenomUnits) > 0 && asset.DenomUnits[0].Exponent == 0 && len(asset.DenomUnits[0].Aliases) > 0 {
baseDenom := asset.DenomUnits[0].Aliases[0]
baseMapRev[asset.Base] = strings.ToLower(baseDenom)
}
}
}
return baseMap, baseMapRev
Expand Down Expand Up @@ -295,17 +318,20 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
for i, arg := range args {
lowerCaseArg := strings.ToLower(arg)
lowerCaseArgArray := strings.Split(lowerCaseArg, ",")
re := regexp.MustCompile(`^(\d+)(.+)`)

re := regexp.MustCompile(`^([\d.]+)(\D+)$`)

for i, lowerCaseArg := range lowerCaseArgArray {
match := re.FindStringSubmatch(lowerCaseArg)
if len(match) == 3 {
value, denom := match[1], match[2]
// If the index has a length of 3 then it has a number and a denom (this is a coin object)
// Note, index 0 is the entire string, index 1 is the number, and index 2 is the denom
if _, ok := assetMap[match[2]]; ok {
// In this case, we just need to replace the denom with the base denom and retain the number
lowerCaseArgArray[i] = match[1] + assetMap[match[2]].Base
transformedCoin, err := transformCoinValueToBaseInt(value, denom, assetMap)
if err != nil {
continue
}
lowerCaseArgArray[i] = transformedCoin
} else {
if _, ok := assetMap[lowerCaseArg]; ok {
// In this case, we just need to replace the denom with the base denom
Expand All @@ -321,17 +347,19 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
lowerCaseFlagValue := strings.ToLower(flag.Value.String())
lowerCaseFlagValueArray := strings.Split(lowerCaseFlagValue, ",")

re := regexp.MustCompile(`^(\d+)(.+)`)
re := regexp.MustCompile(`^([\d.]+)(\D+)$`)

for i, lowerCaseFlagValue := range lowerCaseFlagValueArray {
match := re.FindStringSubmatch(lowerCaseFlagValue)
if len(match) == 3 {
value, denom := match[1], match[2]
// If the index has a length of 3 then it has a number and a denom (this is a coin object)
// Note, index 0 is the entire string, index 1 is the number, and index 2 is the denom
if _, ok := assetMap[match[2]]; ok {
// In this case, we just need to replace the denom with the base denom and retain the number
lowerCaseFlagValueArray[i] = strings.Replace(lowerCaseFlagValue, match[2], assetMap[match[2]].Base, -1)
transformedCoin, err := transformCoinValueToBaseInt(value, denom, assetMap)
if err != nil {
continue
}
lowerCaseFlagValueArray[i] = transformedCoin
} else {
if _, ok := assetMap[lowerCaseFlagValue]; ok {
// Otherwise, we just need to replace the denom with the base denom
Expand Down Expand Up @@ -407,7 +435,7 @@ func initAppConfig() (string, interface{}) {
###############################################################################
[osmosis-mempool]
# This is the max allowed gas any tx.
# This is the max allowed gas any tx.
# This is only for local mempool purposes, and thus is only ran on check tx.
max-gas-wanted-per-tx = "25000000"
Expand Down Expand Up @@ -676,3 +704,28 @@ source ~/.zshrc
},
})
}

// transformCoinValueToBaseInt transforms a cli input that has been split into a number and a denom into it's base int value and base denom.
// i.e. 10.7osmo -> 10700000uosmo
// 12atom -> 12000000uatom
// 15000000uakt -> 15000000uakt (does nothing since it's already in base denom format)
func transformCoinValueToBaseInt(coinValue, coinDenom string, assetMap map[string]DenomUnitMap) (string, error) {
// If the index has a length of 3 then it has a number and a denom (this is a coin object)
// Note, index 0 is the entire string, index 1 is the number, and index 2 is the denom
if denomUnitMap, ok := assetMap[coinDenom]; ok {
// In this case, we just need to replace the denom with the base denom and retain the number
if denomUnitMap.Exponent != 0 {
coinDec, err := sdk.NewDecFromStr(coinValue)
if err != nil {
return "", err
}
transformedCoinValue := coinDec.Mul(sdk.MustNewDecFromStr("10").Power(denomUnitMap.Exponent))
transformedCoinValueInt := transformedCoinValue.TruncateInt()
transformedCoinValueStr := transformedCoinValueInt.String()
return transformedCoinValueStr + assetMap[coinDenom].Base, nil
} else {
return coinValue + assetMap[coinDenom].Base, nil
}
}
return "", fmt.Errorf("denom %s not found in asset map", coinDenom)
}

0 comments on commit 59c5a8c

Please sign in to comment.