Skip to content

Commit

Permalink
Merge pull request #123 from onomyprotocol/hieu/decimals
Browse files Browse the repository at this point in the history
Handle GetPrice with decimals
  • Loading branch information
vuong177 authored Dec 31, 2024
2 parents 3e0b3e6 + c232342 commit fa323a7
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 86 deletions.
5 changes: 5 additions & 0 deletions proto/reserve/vaults/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ message MsgActiveCollateral {
string mint_denom = 11;
string mint_symbol = 12;
int64 mint_oracle_script = 13;

uint64 collateral_decimals = 14;
uint64 mint_decimals = 15;
}

// MsgActiveCollateralResponse defines the Msg/ActiveCollateral response type.
Expand Down Expand Up @@ -184,6 +187,8 @@ message MsgUpdatesCollateral {
string symbol = 11;
string mint_denom = 12;
int64 mint_oracle_script = 13;
uint64 collateral_decimals = 14;
uint64 mint_decimals = 15;
}

// MsgActiveCollateralResponse defines the Msg/ActiveCollateral response type.
Expand Down
30 changes: 28 additions & 2 deletions x/oracle/keeper/band_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,12 @@ func (k Keeper) GetPrice(ctx context.Context, base, quote string) (price math.Le
return price, fmt.Errorf("symbol base %s old price state", base)
}
if quote == types.QuoteUSD || quote == vaultstypes.DefaultMintDenoms[0] {
return basePriceState.PriceState.Price, nil
pairDecimalsRate, err := k.GetPairDecimalsRate(ctx, base, quote)
if err != nil {
return price, err
}

return basePriceState.PriceState.Price.Mul(pairDecimalsRate), nil
}

quotePriceState := k.GetBandPriceState(ctx, quote)
Expand All @@ -346,7 +351,12 @@ func (k Keeper) GetPrice(ctx context.Context, base, quote string) (price math.Le
return price, fmt.Errorf("get price error validate for baseRate %s(%s) or quoteRate %s(%s)", base, baseRate.String(), quote, quoteRate.String())
}

price = baseRate.Quo(quoteRate)
pairDecimalsRate, err := k.GetPairDecimalsRate(ctx, base, quote)
if err != nil {
return price, err
}

price = baseRate.Quo(quoteRate).Mul(pairDecimalsRate)
return price, nil
}

Expand Down Expand Up @@ -580,3 +590,19 @@ func (k *Keeper) getPreviousRecordIDs(ctx context.Context, clientID uint64) []ui

return staleIDs
}

func (k Keeper) SetPairDecimalsRate(ctx context.Context, base, quote string, baseDecimals, quoteDecimals uint64) error {
store := k.storeService.OpenKVStore(ctx)
rate := math.LegacyNewDec(10).Power(quoteDecimals).Quo(math.LegacyNewDec(10).Power(baseDecimals))
bz := []byte(rate.String())
return store.Set(types.GetPairDecimalsKey(base, quote), bz)
}

func (k Keeper) GetPairDecimalsRate(ctx context.Context, base, quote string) (math.LegacyDec, error) {
store := k.storeService.OpenKVStore(ctx)
bz, err := store.Get(types.GetPairDecimalsKey(base, quote))
if err != nil {
return math.LegacyZeroDec(), err
}
return math.LegacyMustNewDecFromStr(string(bz)), nil
}
31 changes: 29 additions & 2 deletions x/oracle/keeper/band_oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ func TestBandPriceState(t *testing.T) {
states := app.OracleKeeper.GetAllBandPriceStates(ctx)
require.Equal(t, 0, len(states))

_, err := app.OracleKeeper.GetPrice(ctx, "ATOM", "USD")
err := app.OracleKeeper.SetPairDecimalsRate(ctx, "ATOM", "USD", 6, 6)
require.NoError(t, err)

_, err = app.OracleKeeper.GetPrice(ctx, "ATOM", "USD")
require.Error(t, err)

bandPriceState := &types.BandPriceState{
Expand Down Expand Up @@ -205,6 +208,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol string
basePriceState *types.BandPriceState
quotePriceState *types.BandPriceState
baseDecimals uint64
quoteDecimals uint64
expectedPrice math.LegacyDec
expectNil bool
}{
Expand All @@ -215,6 +220,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "USD",
basePriceState: nil,
quotePriceState: nil,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: math.LegacyNewDec(-1),
expectNil: true,
},
Expand All @@ -224,6 +231,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "USD",
basePriceState: invalidPriceStateATOM,
quotePriceState: bandPriceStateUSD,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: math.LegacyNewDec(-1),
expectNil: true,
},
Expand All @@ -233,6 +242,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "NOM",
basePriceState: bandPriceStateATOM,
quotePriceState: nil,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: math.LegacyNewDec(-1), // Since NOM doesn't exist, expect nil
expectNil: true,
},
Expand All @@ -243,6 +254,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "NOM",
basePriceState: bandPriceStateATOM,
quotePriceState: bandPriceStateNOM,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: expectedPrice05, // 10/2 = 5
expectNil: false,
},
Expand All @@ -252,6 +265,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "USD",
basePriceState: bandPriceStateATOM,
quotePriceState: nil,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: expectedPrice10, // Since quote = USD, we return base price directly
expectNil: false,
},
Expand All @@ -261,6 +276,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "USD",
basePriceState: bandPriceStateATOM,
quotePriceState: bandPriceStateUSD,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: expectedPrice10,
expectNil: false,
},
Expand All @@ -270,6 +287,8 @@ func TestGetPrice(t *testing.T) {
quoteSymbol: "ATOM",
basePriceState: bandPriceStateUSD,
quotePriceState: bandPriceStateATOM,
baseDecimals: 6,
quoteDecimals: 6,
expectedPrice: expectedPrice01,
expectNil: false,
},
Expand All @@ -287,6 +306,8 @@ func TestGetPrice(t *testing.T) {
require.NoError(t, err)
}

err := app.OracleKeeper.SetPairDecimalsRate(ctx, tc.baseSymbol, tc.quoteSymbol, tc.baseDecimals, tc.quoteDecimals)
require.NoError(t, err)
// Execute GetPrice
price, err := app.OracleKeeper.GetPrice(ctx, tc.baseSymbol, tc.quoteSymbol)

Expand Down Expand Up @@ -339,8 +360,14 @@ func (s *KeeperTestSuite) TestPriceOld() {
s.Require().NoError(err)
}

err := s.App.OracleKeeper.SetPairDecimalsRate(s.Ctx, "ATOM", "USD", 6, 6)
s.Require().NoError(err)

err = s.App.OracleKeeper.SetPairDecimalsRate(s.Ctx, "NOM", "USD", 6, 6)
s.Require().NoError(err)

// ATOM price old
_, err := s.App.OracleKeeper.GetPrice(s.Ctx, "ATOM", "USD")
_, err = s.App.OracleKeeper.GetPrice(s.Ctx, "ATOM", "USD")
s.Require().Error(err)

// NOM price new (6h)
Expand Down
3 changes: 3 additions & 0 deletions x/oracle/module/module_ibc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ func (suite *PriceRelayTestSuite) TestOnRecvPacket() {
suite.Require().True(ack.Success())
suite.Require().Equal(expectedAck, ack)

err := onomyApp.OracleKeeper.SetPairDecimalsRate(suite.chainO.GetContext(), "ATOM", "USD", 6, 6)
suite.Require().NoError(err)

price, err := onomyApp.OracleKeeper.GetPrice(suite.chainO.GetContext(), "ATOM", "USD")
suite.Require().NoError(err)
suite.Require().Equal("10.822375461000000000", price.String())
Expand Down
2 changes: 2 additions & 0 deletions x/oracle/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"cosmossdk.io/core/address"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

// AccountKeeper defines the expected interface for the Account module.
Expand All @@ -16,6 +17,7 @@ type AccountKeeper interface {
// BankKeeper defines the expected interface for the Bank module.
type BankKeeper interface {
SpendableCoins(context.Context, sdk.AccAddress) sdk.Coins
GetDenomMetaData(ctx context.Context, denom string) (banktypes.Metadata, bool)
// Methods imported from bank should be defined here
}

Expand Down
6 changes: 6 additions & 0 deletions x/oracle/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
BandPriceKey = []byte{0x05}
LatestRequestIDKey = []byte{0x06}
BandOracleRequestParamsKey = []byte{0x07}
PairDecimalsKeys = []byte{0x08}
)

var (
Expand All @@ -52,3 +53,8 @@ func GetBandPriceStoreKey(symbol string) []byte {
func KeyPrefix(p string) []byte {
return []byte(p)
}

func GetPairDecimalsKey(base, quote string) []byte {
pairBz := append([]byte(base), []byte(quote)...)
return append(PairDecimalsKeys, pairBz...)
}
4 changes: 2 additions & 2 deletions x/vaults/keeper/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (s *KeeperTestSuite) TestBeginBlock() {
math.LegacyMustNewDecFromStr("1.5"),
maxDebt, stabilityFee,
types.DefaultMintingFee,
types.DefaultLiquidationPenalty, 1, 1,
types.DefaultLiquidationPenalty, 1, 1, 6, 6,
)
s.Require().NoError(err)

Expand Down Expand Up @@ -66,7 +66,7 @@ func (s *KeeperTestSuite) TestBeginBlock() {
math.LegacyMustNewDecFromStr("1.5"),
maxDebt, stabilityFee,
types.DefaultMintingFee,
types.DefaultLiquidationPenalty, 1, 1,
types.DefaultLiquidationPenalty, 1, 1, 6, 6,
)
s.Require().NoError(err)

Expand Down
5 changes: 5 additions & 0 deletions x/vaults/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func (k *Keeper) ActiveCollateralAsset(
liquidationPenalty math.LegacyDec,
collateralOracleScript int64,
mintOracleScript int64,
collateralDecimals, mintDecimals uint64,
) error {
// Check if asset alreay be actived
actived, vmKey := k.IsActived(ctx, CollateralDenom, MintDenom)
Expand Down Expand Up @@ -118,6 +119,10 @@ func (k *Keeper) ActiveCollateralAsset(
return err
}

err = k.OracleKeeper.SetPairDecimalsRate(ctx, CollateralSymbol, MintSymbol, collateralDecimals, mintDecimals)
if err != nil {
return err
}
return k.VaultsManager.Set(ctx, vmKey, vm)
}

Expand Down
4 changes: 4 additions & 0 deletions x/vaults/keeper/mock/oracle_keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ func (s *MockOracleKeeper) SetPrice(denom string, price math.LegacyDec) {
func (s *MockOracleKeeper) AddNewSymbolToBandOracleRequest(ctx context.Context, symbol string, oracleScriptId int64) error {
return nil
}

func (s *MockOracleKeeper) SetPairDecimalsRate(ctx context.Context, base, quote string, baseDecimals, quoteDecimals uint64) error {
return nil
}
2 changes: 1 addition & 1 deletion x/vaults/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (k msgServer) ActiveCollateral(ctx context.Context, msg *types.MsgActiveCol
return nil, errorsmod.Wrapf(types.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, msg.Authority)
}

err = k.ActiveCollateralAsset(ctx, msg.CollateralDenom, msg.CollateralSymbol, msg.MintDenom, msg.MintSymbol, msg.MinCollateralRatio, msg.LiquidationRatio, msg.MaxDebt, msg.StabilityFee, msg.MintingFee, msg.LiquidationPenalty, msg.CollateralOracleScript, msg.MintOracleScript)
err = k.ActiveCollateralAsset(ctx, msg.CollateralDenom, msg.CollateralSymbol, msg.MintDenom, msg.MintSymbol, msg.MinCollateralRatio, msg.LiquidationRatio, msg.MaxDebt, msg.StabilityFee, msg.MintingFee, msg.LiquidationPenalty, msg.CollateralOracleScript, msg.MintOracleScript, msg.CollateralDecimals, msg.MintDecimals)
if err != nil {
return nil, err
}
Expand Down
16 changes: 8 additions & 8 deletions x/vaults/keeper/vaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (s *KeeperTestSuite) TestCreateNewVault() {
collateral = sdk.NewCoin(denom, math.NewInt(10_000_000)) // 10 atom = 80$
maxDebt = math.NewInt(100_000_000)
)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("1.6"), math.LegacyMustNewDecFromStr("1.5"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("1.6"), math.LegacyMustNewDecFromStr("1.5"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

tests := []struct {
Expand Down Expand Up @@ -166,7 +166,7 @@ func (s *KeeperTestSuite) TestRepayDebt() {
maxDebt = math.NewInt(2000000000)
mintedCoin = sdk.NewCoin(types.DefaultMintDenoms[0], math.NewInt(300000000))
)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

tests := []struct {
Expand Down Expand Up @@ -284,7 +284,7 @@ func (s *KeeperTestSuite) TestDepositToVault() {
maxDebt = math.NewInt(2000000000)
mintedCoin = sdk.NewCoin(types.DefaultMintDenoms[0], math.NewInt(200000000))
)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

tests := []struct {
Expand Down Expand Up @@ -407,7 +407,7 @@ func (s *KeeperTestSuite) TestWithdrawFromVault() {
setup: func() {
s.FundAccount(s.TestAccs[0], types.ModuleName, sdk.NewCoins(fund))

err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

err = s.k.CreateNewVault(s.Ctx, s.TestAccs[0], coinMintToAcc, mintedCoin)
Expand Down Expand Up @@ -443,7 +443,7 @@ func (s *KeeperTestSuite) TestWithdrawFromVault() {
setup: func() {
s.FundAccount(s.TestAccs[0], types.ModuleName, sdk.NewCoins(fund))

err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

err = s.k.CreateNewVault(s.Ctx, s.TestAccs[0], coinMintToAcc, mintedCoin)
Expand All @@ -460,7 +460,7 @@ func (s *KeeperTestSuite) TestWithdrawFromVault() {
setup: func() {
s.FundAccount(s.TestAccs[0], types.ModuleName, sdk.NewCoins(fund))

err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

err = s.k.CreateNewVault(s.Ctx, s.TestAccs[0], coinMintToAcc, mintedCoin)
Expand All @@ -477,7 +477,7 @@ func (s *KeeperTestSuite) TestWithdrawFromVault() {
setup: func() {
s.FundAccount(s.TestAccs[0], types.ModuleName, sdk.NewCoins(fund))

err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, denom, denom, "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), maxDebt, types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

err = s.k.CreateNewVault(s.Ctx, s.TestAccs[0], coinMintToAcc, mintedCoin)
Expand Down Expand Up @@ -709,7 +709,7 @@ func (s *KeeperTestSuite) TestLiquidate() {
for _, t := range tests {
s.Run(t.name, func() {
s.SetupTest()
err := s.k.ActiveCollateralAsset(s.Ctx, "atom", "atom", "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), math.NewInt(1000_000_000), types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1)
err := s.k.ActiveCollateralAsset(s.Ctx, "atom", "atom", "nomUSD", "USD", math.LegacyMustNewDecFromStr("0.1"), math.LegacyMustNewDecFromStr("0.1"), math.NewInt(1000_000_000), types.DefaultStabilityFee, types.DefaultMintingFee, types.DefaultLiquidationPenalty, 1, 1, 6, 6)
s.Require().NoError(err)

for _, vault := range t.liquidation.LiquidatingVaults {
Expand Down
1 change: 1 addition & 0 deletions x/vaults/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ type BankKeeper interface {
type OracleKeeper interface {
GetPrice(ctx context.Context, base, quote string) (math.LegacyDec, error)
AddNewSymbolToBandOracleRequest(ctx context.Context, symbol string, oracleScriptId int64) error
SetPairDecimalsRate(ctx context.Context, base, quote string, baseDecimals, quoteDecimals uint64) error
}
Loading

0 comments on commit fa323a7

Please sign in to comment.