Skip to content

Commit

Permalink
feat: asset registry (#1158)
Browse files Browse the repository at this point in the history
* feat: create asset registry

* refactor: move denoms to separate file

* refactor: use AssetRegistry instead of hard-coded constants

* chore: update changelog

* refactor(denom): move denoms to separate package

* refactor(asset_registry): Use `set[string]` instead of slice `[]string`, since it covers both use cases (#1159)

* refactor(asset_registry): Use StringSet instead of []slice, since it
covers both use cases

* feat: add generic sets (#1160)

* feat(set): use a generic set instead of StringSet

* chore: update changelog

Co-authored-by: Kevin Yang <5478483+k-yang@users.noreply.github.com>

* refactor: remove redundant Denom name

* refactor: AssetRegistry in asset package

* refactor: rename AssetRegistry to Registry

Co-authored-by: Unique Divine <51418232+Unique-Divine@users.noreply.github.com>
  • Loading branch information
k-yang and Unique-Divine authored Jan 26, 2023
1 parent fc2e00c commit ab96d89
Show file tree
Hide file tree
Showing 80 changed files with 1,680 additions and 1,424 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### API Breaking

* [#1158](https://github.com/NibiruChain/nibiru/pull/1158) - feat(asset-registry)!: Add `AssetRegistry`

### State Machine Breaking

* [#1154](https://github.com/NibiruChain/nibiru/pull/1154) - refactor(asset-pair)!: refactors `common.AssetPair` as an extension of string

### CI
Expand All @@ -60,6 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1141](https://github.com/NibiruChain/nibiru/pull/1141) - refactor(oracle): rename variables for readability
* [#1146](https://github.com/NibiruChain/nibiru/pull/1146) - fix: local docker-compose network
* [#1145](https://github.com/NibiruChain/nibiru/pull/1145) - chore: add USD quote asset
* [#1160](https://github.com/NibiruChain/nibiru/pull/1160) - feat: generic set

### Bug Fixes

Expand Down
10 changes: 5 additions & 5 deletions cmd/nibid/cmd/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/denoms"
)

var (
Expand Down Expand Up @@ -89,7 +89,7 @@ Example:
cmd.Flags().String(flagNodeDaemonHome, "nibid", "Home directory of the node's daemon configuration")
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", common.DenomNIBI), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
cmd.Flags().String(server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", denoms.NIBI), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
cmd.Flags().String(flags.FlagKeyAlgorithm, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for")

Expand Down Expand Up @@ -200,8 +200,8 @@ func InitTestnet(
accTokens := sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction)
accStakingTokens := sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction)
coins := sdk.Coins{
sdk.NewCoin(common.DenomNUSD, accTokens),
sdk.NewCoin(common.DenomNIBI, accStakingTokens),
sdk.NewCoin(denoms.NUSD, accTokens),
sdk.NewCoin(denoms.NIBI, accStakingTokens),
}

genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()})
Expand All @@ -211,7 +211,7 @@ func InitTestnet(
createValMsg, err := stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(addr),
valPubKeys[i],
sdk.NewCoin(common.DenomNIBI, valTokens),
sdk.NewCoin(denoms.NIBI, valTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
sdk.OneInt(),
Expand Down
8 changes: 5 additions & 3 deletions simapp/testapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
tmdb "github.com/tendermint/tm-db"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/asset"
"github.com/NibiruChain/nibiru/x/common/denoms"
)

// NewTestNibiruApp creates an application instance ('app.NibiruApp') with an in-memory
Expand All @@ -36,8 +38,8 @@ func NewTestNibiruAppAndContext(shouldUseDefaultGenesis bool) (*NibiruTestApp, s
newNibiruApp := NewTestNibiruApp(shouldUseDefaultGenesis)
ctx := newNibiruApp.NewContext(false, tmproto.Header{})

newNibiruApp.OracleKeeper.SetPrice(ctx, common.Pair_BTC_NUSD, sdk.NewDec(20000))
// newNibiruApp.OracleKeeper.SetPrice(ctx, common.Pair_NIBI_NUSD, sdk.NewDec(10))
newNibiruApp.OracleKeeper.SetPrice(ctx, asset.Registry.Pair(denoms.BTC, denoms.NUSD), sdk.NewDec(20000))
// newNibiruApp.OracleKeeper.SetPrice(ctx, asset.AssetRegistry.Pair(denoms.NIBI, denoms.NUSD), sdk.NewDec(10))
newNibiruApp.OracleKeeper.SetPrice(ctx, "xxx:yyy", sdk.NewDec(20000))

return newNibiruApp, ctx
Expand Down Expand Up @@ -122,7 +124,7 @@ func NewTestGenesisState(codec codec.Codec, inGenState GenesisState,
var govGenState govtypes.GenesisState
codec.MustUnmarshalJSON(testGenState[govtypes.ModuleName], &govGenState)
govGenState.VotingParams.VotingPeriod = time.Second * 20
govGenState.DepositParams.MinDeposit = sdk.NewCoins(sdk.NewInt64Coin(common.DenomNIBI, 1*common.Precision)) // min deposit of 1 NIBI
govGenState.DepositParams.MinDeposit = sdk.NewCoins(sdk.NewInt64Coin(denoms.NIBI, 1*common.Precision)) // min deposit of 1 NIBI
testGenState[govtypes.ModuleName] = codec.MustMarshalJSON(&govGenState)

return testGenState
Expand Down
81 changes: 81 additions & 0 deletions x/common/asset/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package asset

import (
"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/denoms"
"github.com/NibiruChain/nibiru/x/common/set"
)

type registry map[string]set.Set[string]

var Registry registry

func init() {
// map of base asset to supported quote assets
// quote assets are usually stables
Registry = map[string]set.Set[string]{
denoms.BTC: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.ETH: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.NIBI: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.ATOM: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.OSMO: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.AVAX: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.SOL: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.BNB: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.ADA: set.New(denoms.USDC, denoms.NUSD, denoms.USD, denoms.USDT),
denoms.NUSD: set.New(denoms.USD, denoms.USDC),
denoms.USDC: set.New(denoms.USD, denoms.NUSD),
denoms.USDT: set.New(denoms.USD, denoms.NUSD, denoms.USDC),
}
}

func (r registry) Pair(base string, quote string) common.AssetPair {
for q := range r[base] {
if q == quote {
return common.NewAssetPair(string(base), string(quote))
}
}

return ""
}

// Returns all supported base denoms
func (r registry) BaseDenoms() set.Set[string] {
baseSet := make(set.Set[string])
for d := range r {
baseSet.Add(d)
}
return baseSet
}

// Returns all supported quote denoms
func (r registry) QuoteDenoms() set.Set[string] {
quoteSet := make(set.Set[string])
for base := range r {
for q := range r[base] {
quoteSet.Add(q)
}
}
return quoteSet
}

// Checks if the provided denom is a supported base denom
func (r registry) IsSupportedBaseDenom(denom string) bool {
_, ok := r[denom]
return ok
}

// Checks if the provided denom is a supported quote denom
func (r registry) IsSupportedQuoteDenom(denom string) bool {
return r.QuoteDenoms().Has(denom)
}

// Checks if the provided denom is a supported denom
func (r registry) IsSupportedDenom(denom string) bool {
return r.IsSupportedBaseDenom(string(denom)) || r.IsSupportedQuoteDenom(string(denom))
}

// Checks if the provided base and quote denoms are a supported pair
func (r registry) IsSupportedPair(base string, quote string) bool {
return r.IsSupportedBaseDenom(base) && r.IsSupportedQuoteDenom(quote)
}
82 changes: 82 additions & 0 deletions x/common/asset/registry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package asset

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/denoms"
)

func TestIsSupportedPair(t *testing.T) {
for base := range Registry {
for quote := range Registry[base] {
require.Truef(t, Registry.IsSupportedPair(base, quote), "%s:%s should be supported", base, quote)
}
}

t.Log("test an unsupported pair")
require.False(t, Registry.IsSupportedPair(denoms.ATOM, denoms.OSMO))
}

func TestPair(t *testing.T) {
for base := range Registry {
for quote := range Registry[base] {
require.Equal(t, common.NewAssetPair(base, quote), Registry.Pair(base, quote))
}
}

t.Log("test an unsupported pair")
require.Equal(t, common.AssetPair(""), Registry.Pair(denoms.ATOM, denoms.OSMO))

t.Log("test an unsupported base asset")
require.Equal(t, common.AssetPair(""), Registry.Pair("unsuported_denom", denoms.USDC))

t.Log("test an unsupported quote asset")
require.Equal(t, common.AssetPair(""), Registry.Pair(denoms.ATOM, "unsupported_denom"))
}

func TestBaseDenoms(t *testing.T) {
for base := range Registry {
require.Contains(t, Registry.BaseDenoms(), base)
}
}

func TestIsSupportedBaseDenom(t *testing.T) {
for base := range Registry {
require.True(t, Registry.IsSupportedBaseDenom(base))
}
require.False(t, Registry.IsSupportedBaseDenom("unsupported_denom"))
}

func TestQuoteDenoms(t *testing.T) {
for base := range Registry {
for quote := range Registry[base] {
require.True(t, Registry.QuoteDenoms().Has(quote))
}
}
}

func TestIsSupportedQuoteDenom(t *testing.T) {
for base := range Registry {
for quote := range Registry[base] {
require.True(t, Registry.IsSupportedQuoteDenom(quote))
}
}

require.False(t, Registry.IsSupportedQuoteDenom("unsupported_denom"))
}

func TestIsSupportedDenom(t *testing.T) {
for base := range Registry.BaseDenoms() {
require.True(t, Registry.IsSupportedDenom(base))
}

for quote := range Registry.QuoteDenoms() {
require.True(t, Registry.IsSupportedDenom(quote))
}

t.Log("test an unsupported denom")
require.False(t, Registry.IsSupportedDenom("unsupported_denom"))
}
31 changes: 3 additions & 28 deletions x/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,15 @@ import (
type AssetPair string

const (
// stablecoins
DenomUSDC = "uusdc"
DenomNUSD = "unusd"
DenomUSD = "uusd"
DenomUSDT = "uusdt"

// crypto assets
DenomNIBI = "unibi"
DenomBTC = "ubtc"
DenomETH = "ueth"

ModuleName = "common"

ModuleName = "common"
TreasuryPoolModuleAccount = "treasury_pool"

PairSeparator = ":"
PairSeparator = ":"
)

var (
// paired against USD
Pair_NIBI_USD = NewAssetPair(DenomNIBI, DenomUSD)
Pair_USDC_USD = NewAssetPair(DenomUSDC, DenomUSD)
Pair_BTC_USD = NewAssetPair(DenomBTC, DenomUSD)
Pair_ETH_USD = NewAssetPair(DenomETH, DenomUSD)

// paired against NUSD
Pair_NIBI_NUSD = NewAssetPair(DenomNIBI, DenomNUSD)
Pair_USDC_NUSD = NewAssetPair(DenomUSDC, DenomNUSD)
Pair_BTC_NUSD = NewAssetPair(DenomBTC, DenomNUSD)
Pair_ETH_NUSD = NewAssetPair(DenomETH, DenomNUSD)

ErrInvalidTokenPair = sdkerrors.Register(ModuleName, 1, "invalid token pair")
APrecision = uint256.NewInt().SetUint64(1)

// Precision for int representation in sdk.Int objects
Precision = int64(1_000_000)
)
Expand Down Expand Up @@ -126,7 +101,7 @@ func (pair AssetPair) QuoteDenom() string {
func (pair AssetPair) Validate() error {
split := strings.Split(pair.String(), PairSeparator)
if len(split) != 2 {
return ErrInvalidTokenPair.Wrapf("invalid pair: %s", pair)
return ErrInvalidTokenPair.Wrap(pair.String())
}

if err := sdk.ValidateDenom(split[0]); err != nil {
Expand Down
11 changes: 6 additions & 5 deletions x/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/denoms"
)

func TestTryNewAssetPair(t *testing.T) {
Expand All @@ -19,23 +20,23 @@ func TestTryNewAssetPair(t *testing.T) {
}{
{
"only one token",
common.DenomNIBI,
denoms.NIBI,
common.ErrInvalidTokenPair,
},
{
"more than 2 tokens",
fmt.Sprintf("%s%s%s%s%s", common.DenomNIBI, common.PairSeparator, common.DenomNUSD,
common.PairSeparator, common.DenomUSDC),
fmt.Sprintf("%s%s%s%s%s", denoms.NIBI, common.PairSeparator, denoms.NUSD,
common.PairSeparator, denoms.USDC),
common.ErrInvalidTokenPair,
},
{
"different separator",
fmt.Sprintf("%s%s%s", common.DenomNIBI, "%", common.DenomNUSD),
fmt.Sprintf("%s%s%s", denoms.NIBI, "%", denoms.NUSD),
common.ErrInvalidTokenPair,
},
{
"correct pair",
fmt.Sprintf("%s%s%s", common.DenomNIBI, common.PairSeparator, common.DenomNUSD),
fmt.Sprintf("%s%s%s", denoms.NIBI, common.PairSeparator, denoms.NUSD),
nil,
},
{
Expand Down
20 changes: 20 additions & 0 deletions x/common/denoms/denoms.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package denoms

const ( // stablecoins
USDC = "uusdc"
NUSD = "unusd"
USD = "uusd"
USDT = "uusdt"
)

const ( // volatile assets
NIBI = "unibi"
BTC = "ubtc"
ETH = "ueth"
ATOM = "uatom"
OSMO = "uosmo"
AVAX = "uavax"
SOL = "usol"
BNB = "ubnb"
ADA = "uada"
)
6 changes: 4 additions & 2 deletions x/common/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/stretchr/testify/assert"

"github.com/NibiruChain/nibiru/x/common"
"github.com/NibiruChain/nibiru/x/common/asset"
"github.com/NibiruChain/nibiru/x/common/denoms"
"github.com/NibiruChain/nibiru/x/testutil"
)

Expand Down Expand Up @@ -86,12 +88,12 @@ func TestCombineErrorsGeneric(t *testing.T) {
{name: "type=[]string | mixed", in: []string{"", "abc", ""}, out: errors.New(": abc: ")},

// cases: fmt.Stringer
{name: "type=fmt.Stringer |", in: common.Pair_USDC_NUSD, out: errors.New("uusdc:unusd")},
{name: "type=fmt.Stringer |", in: asset.Registry.Pair(denoms.USDC, denoms.NUSD), out: errors.New("uusdc:unusd")},

// cases: []fmt.Stringer
{
name: "type=[]fmt.Stringer | happy",
in: []fmt.Stringer{common.Pair_BTC_NUSD, common.Pair_ETH_NUSD},
in: []fmt.Stringer{asset.Registry.Pair(denoms.BTC, denoms.NUSD), asset.Registry.Pair(denoms.ETH, denoms.NUSD)},
out: errors.New("ubtc:unusd: ueth:unusd")},
{name: "type=[]fmt.Stringer | empty", in: []fmt.Stringer{}, out: nil},
}
Expand Down
Loading

0 comments on commit ab96d89

Please sign in to comment.