Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: asset registry #1158

Merged
merged 12 commits into from
Jan 26, 2023
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