diff --git a/codecov.yml b/.github/codecov.yml similarity index 69% rename from codecov.yml rename to .github/codecov.yml index 45b3a6429..73f60319f 100644 --- a/codecov.yml +++ b/.github/codecov.yml @@ -14,14 +14,19 @@ parsers: method: no conditional: yes coverage: - range: 40..100 + range: 40..92 round: down precision: 2 + # status: See https://docs.codecov.com/docs/commit-status status: project: default: if_not_found: success if_ci_failed: error + target: auto + threshold: 1% # Allow coverage to drop by X%, posting a success status. + # removed_code_behavior: Takes values [off, removals_only, adjust_base] + removed_code_behavior: adjust_base comment: # this is a top-level key layout: " diff, flags, files" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2237d9e23..28f679000 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,31 +44,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### For next mainnet version: -* [#1682](https://github.com/NibiruChain/nibiru/pull/1682) - feat!: add upgrade handler for v1.1.0 * [#1688](https://github.com/NibiruChain/nibiru/pull/1688) - fix(inflation)!: make default inflation allocation follow tokenomics +* [#1682](https://github.com/NibiruChain/nibiru/pull/1682) - feat!: add upgrade handler for v1.1.0 #### Dapp modules: perp, spot, etc. -* [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price -* [#1632](https://github.com/NibiruChain/nibiru/pull/1632) - feat(perp): Add settle position transaction -* [#1656](https://github.com/NibiruChain/nibiru/pull/1656) - feat(perp): Make the collateral denom a stateful collections.Item -* [#1663](https://github.com/NibiruChain/nibiru/pull/1663) - feat(perp): Add volume based rebates -* [#1669](https://github.com/NibiruChain/nibiru/pull/1669) - feat(perp): add query to get collateral metadata -* [#1677](https://github.com/NibiruChain/nibiru/pull/1677) - fix(perp): make Gen_market set initial perp versions -* [#1680](https://github.com/NibiruChain/nibiru/pull/1680) - feat(perp): MsgShiftPegMultiplier, MsgShiftSwapInvariant. +* [#1687](https://github.com/NibiruChain/nibiru/pull/1687) - chore(wasmbinding): delete CustomQuerier since we have QueryRequest::Stargate now * [#1686](https://github.com/NibiruChain/nibiru/pull/1686) - test(perp): add more tests for perp module msg server for DnR * [#1683](https://github.com/NibiruChain/nibiru/pull/1683) - feat(perp): Add `StartDnREpoch` to `AfterEpochEnd` hook +* [#1680](https://github.com/NibiruChain/nibiru/pull/1680) - feat(perp): MsgShiftPegMultiplier, MsgShiftSwapInvariant. +* [#1680](https://github.com/NibiruChain/nibiru/pull/1680) - feat(perp): MsgShiftPegMultiplier, MsgShiftSwapInvariant. +* [#1677](https://github.com/NibiruChain/nibiru/pull/1677) - fix(perp): make Gen_market set initial perp versions +* [#1669](https://github.com/NibiruChain/nibiru/pull/1669) - feat(perp): add query to get collateral metadata +* [#1663](https://github.com/NibiruChain/nibiru/pull/1663) - feat(perp): Add volume based rebates +* [#1656](https://github.com/NibiruChain/nibiru/pull/1656) - feat(perp): Make the collateral denom a stateful collections.Item +* [#1632](https://github.com/NibiruChain/nibiru/pull/1632) - feat(perp): Add settle position transaction +* [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price ### Non-breaking/Compatible Improvements -* [#1679](https://github.com/NibiruChain/nibiru/pull/1679) - test(perp): add more tests for perp module msg server * [#1690](https://github.com/NibiruChain/nibiru/pull/1690) - docs(CHANGELOG.md): Correct the change log, providing clarity on what's released. +* [#1679](https://github.com/NibiruChain/nibiru/pull/1679) - test(perp): add more tests for perp module msg server ### Dependencies - Bump `github.com/spf13/cast` from 1.5.1 to 1.6.0 ([#1689](https://github.com/NibiruChain/nibiru/pull/1689)) -- Bump `github.com/grpc-ecosystem/grpc-gateway/v2` from 2.18.0 to 2.18.1 ([#1675](https://github.com/NibiruChain/nibiru/pull/1675)) - Bump `cosmossdk.io/math` from 1.1.2 to 1.2.0 ([#1676](https://github.com/NibiruChain/nibiru/pull/1676)) +- Bump `github.com/grpc-ecosystem/grpc-gateway/v2` from 2.18.0 to 2.18.1 ([#1675](https://github.com/NibiruChain/nibiru/pull/1675)) ## [v1.1.0] - 2023-11-20 @@ -105,27 +107,27 @@ v0.47.5. [2a250a3](https://github.com/NibiruChain/nibiru/commit/2a250a3c4c60c58c5526ac7d75ce5b9e13889471) [d713f41](https://github.com/NibiruChain/nibiru/commit/d713f41dfe17d6d29451ade4d2f0e6d950ce7c59) [011f1ed](https://github.com/NibiruChain/nibiru/commit/011f1ed431d92899d01583e5e6110e663eceaa24) -* [#1609](https://github.com/NibiruChain/nibiru/pull/1609) - refactor(app)!: Remove x/stablecoin module. -* [#1613](https://github.com/NibiruChain/nibiru/pull/1613) - feat(app)!: enforce min commission by changing default and genesis validation -* [#1615](https://github.com/NibiruChain/nibiru/pull/1613) - feat(ante)!: Ante handler to add a maximum commission rate of 25% for validators. -* [#1616](https://github.com/NibiruChain/nibiru/pull/1616) - fix(app)!: Add custom wasm snapshotter for proper state exports -* [#1617](https://github.com/NibiruChain/nibiru/pull/1617) - fix(app)!: non-nil snapshot manager is not guaranteed in testapp -* [#1645](https://github.com/NibiruChain/nibiru/pull/1645) - fix(tokenfactory)!: token supply in bank keeper must be correct after MsgBurn. -* [#1646](https://github.com/NibiruChain/nibiru/pull/1646) - feat(wasmbinding)!: whitelisted stargate queries for QueryRequest::Stargate: auth, bank, gov, tokenfactory, epochs, inflation, oracle, sudo, devgas * [#1655](https://github.com/NibiruChain/nibiru/pull/1655) - fix(inflation): inflate NIBI correctly to strategic treasury account +* [#1646](https://github.com/NibiruChain/nibiru/pull/1646) - feat(wasmbinding)!: whitelisted stargate queries for QueryRequest::Stargate: auth, bank, gov, tokenfactory, epochs, inflation, oracle, sudo, devgas +* [#1645](https://github.com/NibiruChain/nibiru/pull/1645) - fix(tokenfactory)!: token supply in bank keeper must be correct after MsgBurn. +* [#1617](https://github.com/NibiruChain/nibiru/pull/1617) - fix(app)!: non-nil snapshot manager is not guaranteed in testapp +* [#1616](https://github.com/NibiruChain/nibiru/pull/1616) - fix(app)!: Add custom wasm snapshotter for proper state exports +* [#1615](https://github.com/NibiruChain/nibiru/pull/1613) - feat(ante)!: Ante handler to add a maximum commission rate of 25% for validators. +* [#1613](https://github.com/NibiruChain/nibiru/pull/1613) - feat(app)!: enforce min commission by changing default and genesis validation +* [#1609](https://github.com/NibiruChain/nibiru/pull/1609) - refactor(app)!: Remove x/stablecoin module. ### Non-breaking/Compatible Improvements -* [#1606](https://github.com/NibiruChain/nibiru/pull/1606) - fix(perp): emit `MarketUpdatedEvent` in the absence of index price -* [#1610](https://github.com/NibiruChain/nibiru/pull/1610) - refactor(app): Simplify app.go with less redundant imports using struct embedding. -* [#1614](https://github.com/NibiruChain/nibiru/pull/1614) - refactor(proto): Use explicit namespacing on proto imports for #1608 -* [#1630](https://github.com/NibiruChain/nibiru/pull/1630) - refactor(wasm): clean up wasmbinding/ folder structure -* [#1631](https://github.com/NibiruChain/nibiru/pull/1631) - fix(.goreleaser.yml): Load version for wasmvm dynamically. -* [#1638](https://github.com/NibiruChain/nibiru/pull/1638) - test(tokenfactory): integration test core logic with a real smart contract using `nibiru-std` -* [#1639](https://github.com/NibiruChain/nibiru/pull/1639) - fix(perp): by default, disable new markets until they are toggled on. -* [#1649](https://github.com/NibiruChain/nibiru/pull/1649) - fix(ledger): fix ledger for newer macos versions -* [#1652](https://github.com/NibiruChain/nibiru/pull/1652) - test: refactors cli.network suites with 'Integration' to use common function * [#1659](https://github.com/NibiruChain/nibiru/pull/1659) - refactor(oracle): curate oracle default whitelist +* [#1652](https://github.com/NibiruChain/nibiru/pull/1652) - test: refactors cli.network suites with 'Integration' to use common function +* [#1649](https://github.com/NibiruChain/nibiru/pull/1649) - fix(ledger): fix ledger for newer macos versions +* [#1639](https://github.com/NibiruChain/nibiru/pull/1639) - fix(perp): by default, disable new markets until they are toggled on. +* [#1638](https://github.com/NibiruChain/nibiru/pull/1638) - test(tokenfactory): integration test core logic with a real smart contract using `nibiru-std` +* [#1631](https://github.com/NibiruChain/nibiru/pull/1631) - fix(.goreleaser.yml): Load version for wasmvm dynamically. +* [#1630](https://github.com/NibiruChain/nibiru/pull/1630) - refactor(wasm): clean up wasmbinding/ folder structure +* [#1614](https://github.com/NibiruChain/nibiru/pull/1614) - refactor(proto): Use explicit namespacing on proto imports for #1608 +* [#1610](https://github.com/NibiruChain/nibiru/pull/1610) - refactor(app): Simplify app.go with less redundant imports using struct embedding. +* [#1606](https://github.com/NibiruChain/nibiru/pull/1606) - fix(perp): emit `MarketUpdatedEvent` in the absence of index price ### Dependencies diff --git a/wasmbinding/bindings/marshalling_test.go b/wasmbinding/bindings/marshalling_test.go index 8d6957da2..931ecdd49 100644 --- a/wasmbinding/bindings/marshalling_test.go +++ b/wasmbinding/bindings/marshalling_test.go @@ -12,7 +12,6 @@ import ( "github.com/NibiruChain/nibiru/app" "github.com/NibiruChain/nibiru/wasmbinding/bindings" - "github.com/NibiruChain/nibiru/x/common/testutil/genesis" ) type TestSuiteBindingJsonTypes struct { @@ -36,57 +35,6 @@ func (s *TestSuiteBindingJsonTypes) SetupSuite() { s.fileJson = fileJson } -func (s *TestSuiteBindingJsonTypes) TestQueries() { - testCaseMap := map[string]any{ - "all_markets": new(bindings.AllMarketsResponse), - "reserves": new(bindings.ReservesResponse), - "base_price": new(bindings.BasePriceResponse), - "position": new(bindings.PositionResponse), - "positions": new(bindings.PositionsResponse), - "module_params": new(bindings.PerpParamsResponse), - "premium_fraction": new(bindings.PremiumFractionResponse), - "metrics": new(bindings.MetricsResponse), - "module_accounts": new(bindings.ModuleAccountsResponse), - "oracle_prices": new(bindings.OraclePricesResponse), - } - - for name, cwRespPtr := range testCaseMap { - s.T().Run(name, func(t *testing.T) { - err := json.Unmarshal(s.fileJson[name], cwRespPtr) - s.Assert().NoErrorf(err, "name: %v", name) - jsonBz, err := json.Marshal(cwRespPtr) - s.NoErrorf(err, "jsonBz: %s", jsonBz) - }) - } -} - -func (s *TestSuiteBindingJsonTypes) TestToAppMarket() { - var lastCwMarket bindings.Market - for _, ammMarket := range genesis.START_MARKETS { - dummyBlockHeight := int64(1) - cwMarket := bindings.NewMarket( - ammMarket.Market, - ammMarket.Amm, - "index price", - ammMarket.Amm.InstMarkPrice().String(), - dummyBlockHeight, - ) - - // Test the ToAppMarket fn - gotAppMarket, err := cwMarket.ToAppMarket() - s.Assert().NoError(err) - s.Assert().EqualValues(ammMarket.Market, gotAppMarket) - - lastCwMarket = cwMarket - } - - // Test failure case - sadCwMarket := lastCwMarket - sadCwMarket.Pair = "ftt:ust:xxx-yyy!!!" - _, err := sadCwMarket.ToAppMarket() - s.Error(err) -} - func getFileJson(t *testing.T) (fileJson map[string]json.RawMessage) { file, err := os.Open("execute_msg.json") require.NoError(t, err) @@ -102,13 +50,7 @@ func (s *TestSuiteBindingJsonTypes) TestExecuteMsgs() { fileJson := getFileJson(t) testCaseMap := []string{ - "market_order", - "close_position", - "add_margin", - "remove_margin", "donate_to_insurance_fund", - "peg_shift", - "depth_shift", "edit_oracle_params", "set_market_enabled", "insurance_fund_withdraw", diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index bce9b362e..8e360a09d 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -13,11 +13,7 @@ import ( // - https://github.com/NibiruChain/cw-nibiru/blob/90df123f8d32d47b5b280ec6ae7dde0f9dbf2787/contracts/bindings-perp/src/msg.rs type NibiruMsg struct { // bindings-perp ExecuteMsg enum types - MarketOrder *MarketOrder `json:"market_order,omitempty"` - ClosePosition *ClosePosition `json:"close_position,omitempty"` // MultiLiquidate *MultiLiquidate `json:"multi_liquidate,omitempty"` // TODO - AddMargin *AddMargin `json:"add_margin,omitempty"` - RemoveMargin *RemoveMargin `json:"remove_margin,omitempty"` DonateToInsuranceFund *DonateToInsuranceFund `json:"donate_to_insurance_fund,omitempty"` // TODO InsuranceFundWithdraw *InsuranceFundWithdraw `json:"insurance_fund_withdraw,omitempty"` SetMarketEnabled *SetMarketEnabled `json:"set_market_enabled,omitempty"` @@ -29,37 +25,6 @@ type NibiruMsg struct { NoOp *NoOp `json:"no_op,omitempty"` } -type MarketOrder struct { - Pair string `json:"pair"` - IsLong bool `json:"is_long"` - QuoteAmount sdkmath.Int `json:"quote_amount"` - Leverage sdk.Dec `json:"leverage"` - BaseAmountLimit sdkmath.Int `json:"base_amount_limit"` -} - -type ClosePosition struct { - Pair string `json:"pair"` -} - -type MultiLiquidate struct { - Liquidations []LiquidationArgs `json:"liquidations"` -} - -type LiquidationArgs struct { - Pair string `json:"pair"` - Trader string `json:"trader"` -} - -type AddMargin struct { - Pair string `json:"pair"` - Margin sdk.Coin `json:"margin"` -} - -type RemoveMargin struct { - Pair string `json:"pair"` - Margin sdk.Coin `json:"margin"` -} - type DonateToInsuranceFund struct { Sender string `json:"sender"` Donation sdk.Coin `json:"donation"` diff --git a/wasmbinding/bindings/query.go b/wasmbinding/bindings/query.go deleted file mode 100644 index fe54aaca3..000000000 --- a/wasmbinding/bindings/query.go +++ /dev/null @@ -1,230 +0,0 @@ -package bindings - -import ( - "time" - - sdkmath "cosmossdk.io/math" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/NibiruChain/nibiru/x/common/asset" - epochstypes "github.com/NibiruChain/nibiru/x/epochs/types" - perpv2types "github.com/NibiruChain/nibiru/x/perp/v2/types" -) - -// BindingQuery corresponds to the NibiruQuery enum in CosmWasm binding -// contracts (Rust). It specifies which queries can be called with -// Nibiru bindings and specifies the JSON schema that connects app ⇔ Wasm. -// -// ### Note -// 1. The JSON field names must match the ones on the smart contract -// 2. You use a pointer so that each field can be nil, which will be missing in -// the input or output json. What's actually sent from the contract will be an -// instance of the parent type, but the message body will be on one of these -// nullable fields. -// This is part of the reason we need the "omitempty" struct tags -// -// See: -// - https://github.com/NibiruChain/cw-nibiru/blob/90df123f8d32d47b5b280ec6ae7dde0f9dbf2787/contracts/bindings-perp/src/query.rs -type BindingQuery struct { - // bindings-perp NibiruQuery enum types - Reserves *ReservesRequest `json:"reserves,omitempty"` - AllMarkets *AllMarketsRequest `json:"all_markets,omitempty"` - BasePrice *BasePriceRequest `json:"base_price,omitempty"` - Positions *PositionsRequest `json:"positions,omitempty"` - Position *PositionRequest `json:"position,omitempty"` - PremiumFraction *PremiumFractionRequest `json:"premium_fraction,omitempty"` - Metrics *MetricsRequest `json:"metrics,omitempty"` - ModuleAccounts *ModuleAccountsRequest `json:"module_accounts,omitempty"` - PerpParams *PerpParamsRequest `json:"module_params,omitempty"` - OraclePrices *OraclePrices `json:"oracle_prices,omitempty"` -} - -type ReservesRequest struct { - Pair string `json:"pair"` -} - -type ReservesResponse struct { - Pair string `json:"pair"` - BaseReserve sdk.Dec `json:"base_reserve"` - QuoteReserve sdk.Dec `json:"quote_reserve"` -} - -type AllMarketsRequest struct{} - -type AllMarketsResponse struct { - MarketMap map[string]Market `json:"market_map"` -} - -type Market struct { - Pair string `json:"pair"` - Version sdkmath.Int `json:"version"` - BaseReserve sdk.Dec `json:"base_reserve"` - QuoteReserve sdk.Dec `json:"quote_reserve"` - SqrtDepth sdk.Dec `json:"sqrt_depth"` - Depth sdkmath.Int `json:"depth"` - TotalLong sdk.Dec `json:"total_long"` - TotalShort sdk.Dec `json:"total_short"` - PegMult sdk.Dec `json:"peg_mult"` - Config *MarketConfig `json:"config,omitempty"` - MarkPrice sdk.Dec `json:"mark_price"` - IndexPrice string `json:"index_price"` - TwapMark string `json:"twap_mark"` - BlockNumber sdkmath.Int `json:"block_number"` -} - -// ToAppMarket Converts the JSON market, which comes in from Rust, to its corresponding -// protobuf (Golang) type in the app: perpv2types.Market. -func (m Market) ToAppMarket() (appMarket perpv2types.Market, err error) { - config := m.Config - pair, err := asset.TryNewPair(m.Pair) - if err != nil { - return appMarket, err - } - return perpv2types.Market{ - Pair: pair, - Enabled: true, - Version: m.Version.Uint64(), - MaintenanceMarginRatio: config.MaintenanceMarginRatio, - MaxLeverage: config.MaxLeverage, - LatestCumulativePremiumFraction: sdk.ZeroDec(), - ExchangeFeeRatio: sdk.MustNewDecFromStr("0.0010"), - EcosystemFundFeeRatio: sdk.MustNewDecFromStr("0.0010"), - LiquidationFeeRatio: sdk.MustNewDecFromStr("0.0500"), - PartialLiquidationRatio: sdk.MustNewDecFromStr("0.5"), - FundingRateEpochId: epochstypes.ThirtyMinuteEpochID, - MaxFundingRate: sdk.NewDec(1), - TwapLookbackWindow: 30 * time.Minute, - PrepaidBadDebt: sdk.NewCoin(pair.QuoteDenom(), sdk.ZeroInt()), - }, nil -} - -func NewMarket(appMarket perpv2types.Market, appAmm perpv2types.AMM, indexPrice, twapMark string, blockNumber int64) Market { - return Market{ - Pair: appMarket.Pair.String(), - Version: sdk.NewIntFromUint64(appMarket.Version), - BaseReserve: appAmm.BaseReserve, - QuoteReserve: appAmm.QuoteReserve, - SqrtDepth: appAmm.SqrtDepth, - // Depth: base.Mul(quote).RoundInt(), - TotalLong: appAmm.TotalLong, - TotalShort: appAmm.TotalShort, - PegMult: appAmm.PriceMultiplier, - Config: &MarketConfig{ - MaintenanceMarginRatio: appMarket.MaintenanceMarginRatio, - MaxLeverage: appMarket.MaxLeverage, - }, - MarkPrice: appAmm.InstMarkPrice(), - IndexPrice: indexPrice, - TwapMark: twapMark, - BlockNumber: sdk.NewInt(blockNumber), - } -} - -type MarketConfig struct { - MaintenanceMarginRatio sdk.Dec `json:"maintenance_margin_ratio"` - MaxLeverage sdk.Dec `json:"max_leverage"` -} - -type BasePriceRequest struct { - Pair string `json:"pair"` - IsLong bool `json:"is_long"` - BaseAmount sdkmath.Int `json:"base_amount"` -} - -type BasePriceResponse struct { - Pair string `json:"pair"` - BaseAmount sdk.Dec `json:"base_amount"` - IsLong bool `json:"is_long"` -} - -type PositionsRequest struct { - Trader string `json:"trader"` -} - -type Position struct { - TraderAddr string `json:"trader_addr"` - Pair string `json:"pair"` - Size sdk.Dec `json:"size"` - Margin sdk.Dec `json:"margin"` - OpenNotional sdk.Dec `json:"open_notional"` - LatestCPF sdk.Dec `json:"latest_cpf"` - BlockNumber sdkmath.Int `json:"block_number"` -} - -type PositionsResponse struct { - Positions map[string]Position `json:"positions"` -} - -type PositionRequest struct { - Trader string `json:"trader"` - Pair string `json:"pair"` -} - -type PositionResponse struct { - Position Position `json:"position"` - Notional sdk.Dec `json:"notional"` - Upnl sdk.Dec `json:"upnl"` - Margin_ratio_mark sdk.Dec `json:"margin_ratio_mark"` - Margin_ratio_index sdk.Dec `json:"margin_ratio_index"` - Block_number sdkmath.Int `json:"block_number"` -} - -type PremiumFractionRequest struct { - Pair string `json:"pair"` -} - -type PremiumFractionResponse struct { - Pair string `json:"pair"` - CPF sdk.Dec `json:"cpf"` - EstimatedNextCPF sdk.Dec `json:"estimated_next_cpf"` -} - -type MetricsRequest struct { - Pair string `json:"pair"` -} - -type MetricsResponse struct { - Metrics Metrics `json:"metrics"` -} - -type Metrics struct { - Pair string `json:"pair"` - NetSize sdkmath.LegacyDec `json:"net_size"` - VolumeQuote sdkmath.LegacyDec `json:"volume_quote"` - VolumeBase sdkmath.LegacyDec `json:"volume_base"` - BlockNumber sdkmath.Int `json:"block_number"` -} - -type ModuleAccountsRequest struct{} - -type ModuleAccountWithBalance struct { - Name string `json:"name"` - Addr sdk.AccAddress `json:"addr"` - Balance []sdk.Coin `json:"balance"` -} - -type ModuleAccountsResponse struct { - ModuleAccounts map[string]ModuleAccountWithBalance `json:"module_accounts"` -} - -type PerpParamsRequest struct{} - -type PerpParamsResponse struct { - ModuleParams PerpParams `json:"module_params"` -} - -type PerpParams struct { - Stopped bool `json:"stopped"` - FeePoolFeeRatio sdkmath.LegacyDec `json:"fee_pool_fee_ratio"` - EcosystemFundFeeRatio sdkmath.LegacyDec `json:"ecosystem_fund_fee_ratio"` - LiquidationFeeRatio sdkmath.LegacyDec `json:"liquidation_fee_ratio"` - PartialLiquidationRatio sdkmath.LegacyDec `json:"partial_liquidation_ratio"` - FundingRateInterval string `json:"funding_rate_interval"` - TwapLookbackWindow sdkmath.Int `json:"twap_lookback_window"` - WhitelistedLiquidators []string `json:"whitelisted_liquidators"` -} - -type OraclePrices struct{} - -type OraclePricesResponse = map[string]sdk.Dec diff --git a/wasmbinding/exec_perp.go b/wasmbinding/exec_perp.go index 992718e9e..9ef201feb 100644 --- a/wasmbinding/exec_perp.go +++ b/wasmbinding/exec_perp.go @@ -20,123 +20,6 @@ func (exec *ExecutorPerp) MsgServer() perpv2types.MsgServer { return perpv2keeper.NewMsgServerImpl(exec.PerpV2) } -func (exec *ExecutorPerp) MarketOrder( - cwMsg *bindings.MarketOrder, sender sdk.AccAddress, ctx sdk.Context, -) ( - sdkResp *perpv2types.MsgMarketOrderResponse, err error, -) { - if cwMsg == nil { - return sdkResp, wasmvmtypes.InvalidRequest{Err: "null open position msg"} - } - - pair, err := asset.TryNewPair(cwMsg.Pair) - if err != nil { - return sdkResp, err - } - - var side perpv2types.Direction - if cwMsg.IsLong { - side = perpv2types.Direction_LONG - } else { - side = perpv2types.Direction_SHORT - } - - sdkMsg := &perpv2types.MsgMarketOrder{ - Sender: sender.String(), - Pair: pair, - Side: side, - QuoteAssetAmount: cwMsg.QuoteAmount, - Leverage: cwMsg.Leverage, - BaseAssetAmountLimit: cwMsg.BaseAmountLimit, - } - if err := sdkMsg.ValidateBasic(); err != nil { - return sdkResp, err - } - - goCtx := sdk.WrapSDKContext(ctx) - return exec.MsgServer().MarketOrder(goCtx, sdkMsg) -} - -func (exec *ExecutorPerp) ClosePosition( - cwMsg *bindings.ClosePosition, sender sdk.AccAddress, ctx sdk.Context, -) ( - sdkResp *perpv2types.MsgClosePositionResponse, err error, -) { - if cwMsg == nil { - return sdkResp, wasmvmtypes.InvalidRequest{Err: "null close position msg"} - } - - pair, err := asset.TryNewPair(cwMsg.Pair) - if err != nil { - return sdkResp, err - } - - sdkMsg := &perpv2types.MsgClosePosition{ - Sender: sender.String(), - Pair: pair, - } - if err := sdkMsg.ValidateBasic(); err != nil { - return sdkResp, err - } - - goCtx := sdk.WrapSDKContext(ctx) - return exec.MsgServer().ClosePosition(goCtx, sdkMsg) -} - -func (exec *ExecutorPerp) AddMargin( - cwMsg *bindings.AddMargin, sender sdk.AccAddress, ctx sdk.Context, -) ( - sdkResp *perpv2types.MsgAddMarginResponse, err error, -) { - if cwMsg == nil { - return sdkResp, wasmvmtypes.InvalidRequest{Err: "null add margin msg"} - } - - pair, err := asset.TryNewPair(cwMsg.Pair) - if err != nil { - return sdkResp, err - } - - sdkMsg := &perpv2types.MsgAddMargin{ - Sender: sender.String(), - Pair: pair, - Margin: cwMsg.Margin, - } - if err := sdkMsg.ValidateBasic(); err != nil { - return sdkResp, err - } - - goCtx := sdk.WrapSDKContext(ctx) - return exec.MsgServer().AddMargin(goCtx, sdkMsg) -} - -func (exec *ExecutorPerp) RemoveMargin( - cwMsg *bindings.RemoveMargin, sender sdk.AccAddress, ctx sdk.Context, -) ( - sdkResp *perpv2types.MsgRemoveMarginResponse, err error, -) { - if cwMsg == nil { - return sdkResp, wasmvmtypes.InvalidRequest{Err: "null remove margin msg"} - } - - pair, err := asset.TryNewPair(cwMsg.Pair) - if err != nil { - return sdkResp, err - } - - sdkMsg := &perpv2types.MsgRemoveMargin{ - Sender: sender.String(), - Pair: pair, - Margin: cwMsg.Margin, - } - if err := sdkMsg.ValidateBasic(); err != nil { - return sdkResp, err - } - - goCtx := sdk.WrapSDKContext(ctx) - return exec.MsgServer().RemoveMargin(goCtx, sdkMsg) -} - func (exec *ExecutorPerp) InsuranceFundWithdraw( cwMsg *bindings.InsuranceFundWithdraw, ctx sdk.Context, ) (err error) { diff --git a/wasmbinding/exec_perp_test.go b/wasmbinding/exec_perp_test.go index b5db53479..bfac0d502 100644 --- a/wasmbinding/exec_perp_test.go +++ b/wasmbinding/exec_perp_test.go @@ -1,7 +1,6 @@ package wasmbinding_test import ( - "errors" "testing" "time" @@ -17,7 +16,9 @@ import ( "github.com/NibiruChain/nibiru/x/common/asset" "github.com/NibiruChain/nibiru/x/common/denoms" "github.com/NibiruChain/nibiru/x/common/testutil" + "github.com/NibiruChain/nibiru/x/common/testutil/genesis" "github.com/NibiruChain/nibiru/x/common/testutil/testapp" + oracletypes "github.com/NibiruChain/nibiru/x/oracle/types" perpv2types "github.com/NibiruChain/nibiru/x/perp/v2/types" ) @@ -38,6 +39,59 @@ type TestSuitePerpExecutor struct { happyFields ExampleFields } +func SetExchangeRates( + testSuite *suite.Suite, + nibiru *app.NibiruApp, + ctx sdk.Context, +) (exchangeRateMap map[asset.Pair]sdk.Dec) { + s := testSuite + exchangeRateTuples := []oracletypes.ExchangeRateTuple{ + { + Pair: asset.Registry.Pair(denoms.ETH, denoms.NUSD), + ExchangeRate: sdk.NewDec(1_000), + }, + { + Pair: asset.Registry.Pair(denoms.NIBI, denoms.NUSD), + ExchangeRate: sdk.NewDec(10), + }, + } + + for _, exchangeRateTuple := range exchangeRateTuples { + pair := exchangeRateTuple.Pair + exchangeRate := exchangeRateTuple.ExchangeRate + nibiru.OracleKeeper.SetPrice(ctx, pair, exchangeRate) + + rate, err := nibiru.OracleKeeper.ExchangeRates.Get(ctx, pair) + s.Assert().NoError(err) + s.Assert().EqualValues(exchangeRate, rate.ExchangeRate) + } + + return oracletypes.ExchangeRateTuples(exchangeRateTuples).ToMap() +} + +type ExampleFields struct { + Pair string + Trader sdk.AccAddress + Dec sdk.Dec + Int sdkmath.Int +} + +func GetHappyFields() ExampleFields { + return ExampleFields{ + Pair: asset.Registry.Pair(denoms.ETH, denoms.NUSD).String(), + Trader: sdk.AccAddress([]byte("trader")), + Dec: sdk.NewDec(50), + Int: sdk.NewInt(420), + } +} + +func SetupPerpGenesis() app.GenesisState { + genesisState := genesis.NewTestGenesisState(app.MakeEncodingConfig()) + genesisState = genesis.AddOracleGenesis(genesisState) + genesisState = genesis.AddPerpV2Genesis(genesisState) + return genesisState +} + func (s *TestSuitePerpExecutor) SetupSuite() { s.happyFields = GetHappyFields() sender := testutil.AccAddress() @@ -77,20 +131,9 @@ func (s *TestSuitePerpExecutor) OnSetupEnd() { s.ratesMap = SetExchangeRates(&s.Suite, s.nibiru, s.ctx) } -// Happy path coverage of MarketOrder, AddMargin, RemoveMargin, and ClosePosition -func (s *TestSuitePerpExecutor) TestOpenAddRemoveClose() { - pair := asset.MustNewPair(s.happyFields.Pair) - - margin := sdk.NewCoin(perpv2types.TestingCollateralDenomNUSD, sdk.NewInt(69)) - incorrectMargin := sdk.NewCoin(denoms.USDT, sdk.NewInt(69)) - +// Happy path coverage +func (s *TestSuitePerpExecutor) TestPerpExecutorHappy() { for _, err := range []error{ - s.DoMarketOrderTest(pair), - s.DoAddMarginTest(pair, margin), - s.DoAddIncorrectMarginTest(pair, incorrectMargin), - s.DoRemoveIncorrectMarginTest(pair, incorrectMargin), - s.DoRemoveMarginTest(pair, margin), - s.DoClosePositionTest(pair), s.DoInsuranceFundWithdrawTest(sdk.NewInt(69), s.contractDeployer), s.DoCreateMarketTest(asset.MustNewPair("ufoo:ubar")), s.DoCreateMarketTestWithParams(asset.MustNewPair("ufoo2:ubar")), @@ -99,118 +142,6 @@ func (s *TestSuitePerpExecutor) TestOpenAddRemoveClose() { } } -func (s *TestSuitePerpExecutor) DoMarketOrderTest(pair asset.Pair) error { - cwMsg := &bindings.MarketOrder{ - Pair: pair.String(), - IsLong: false, - QuoteAmount: sdk.NewInt(4_200_000), - Leverage: sdk.NewDec(5), - BaseAmountLimit: sdk.ZeroInt(), - } - - _, err := s.exec.MarketOrder(cwMsg, s.contractPerp, s.ctx) - if err != nil { - return err - } - - // Verify position exists with PerpKeeper - _, err = s.exec.PerpV2.GetPosition(s.ctx, pair, 1, s.contractPerp) - if err != nil { - return err - } - - // Verify position exists with CustomQuerier - multi-position - bindingQuery := bindings.BindingQuery{ - Positions: &bindings.PositionsRequest{ - Trader: s.contractPerp.String(), - }, - } - bindingRespMulti := new(bindings.PositionsRequest) - _, err = DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingRespMulti, - ) - if err != nil { - return err - } - - // Verify position exists with CustomQuerier - single position - bindingQuery = bindings.BindingQuery{ - Position: &bindings.PositionRequest{ - Trader: s.contractPerp.String(), - Pair: pair.String(), - }, - } - bindingResp := new(bindings.PositionRequest) - _, err = DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - - return err -} - -func (s *TestSuitePerpExecutor) DoAddMarginTest( - pair asset.Pair, margin sdk.Coin, -) error { - cwMsg := &bindings.AddMargin{ - Pair: pair.String(), - Margin: margin, - } - - _, err := s.exec.AddMargin(cwMsg, s.contractPerp, s.ctx) - return err -} - -func (s *TestSuitePerpExecutor) DoAddIncorrectMarginTest( - pair asset.Pair, margin sdk.Coin, -) error { - cwMsg := &bindings.AddMargin{ - Pair: pair.String(), - Margin: margin, - } - - _, err := s.exec.AddMargin(cwMsg, s.contractPerp, s.ctx) - if err == nil { - return errors.New("incorrect margin type should have failed") - } - return nil -} - -func (s *TestSuitePerpExecutor) DoRemoveIncorrectMarginTest( - pair asset.Pair, margin sdk.Coin, -) error { - cwMsg := &bindings.RemoveMargin{ - Pair: pair.String(), - Margin: margin, - } - - _, err := s.exec.RemoveMargin(cwMsg, s.contractPerp, s.ctx) - if err == nil { - return errors.New("incorrect margin type should have failed") - } - return nil -} - -func (s *TestSuitePerpExecutor) DoRemoveMarginTest( - pair asset.Pair, margin sdk.Coin, -) error { - cwMsg := &bindings.RemoveMargin{ - Pair: pair.String(), - Margin: margin, - } - - _, err := s.exec.RemoveMargin(cwMsg, s.contractPerp, s.ctx) - return err -} - -func (s *TestSuitePerpExecutor) DoClosePositionTest(pair asset.Pair) error { - cwMsg := &bindings.ClosePosition{ - Pair: pair.String(), - } - - _, err := s.exec.ClosePosition(cwMsg, s.contractPerp, s.ctx) - return err -} - func (s *TestSuitePerpExecutor) DoInsuranceFundWithdrawTest( amt sdkmath.Int, to sdk.AccAddress, ) error { @@ -266,21 +197,7 @@ func (s *TestSuitePerpExecutor) DoCreateMarketTestWithParams(pair asset.Pair) er } func (s *TestSuitePerpExecutor) TestSadPaths_Nil() { - var err error - - _, err = s.exec.MarketOrder(nil, nil, s.ctx) - s.Error(err) - - _, err = s.exec.AddMargin(nil, nil, s.ctx) - s.Error(err) - - _, err = s.exec.RemoveMargin(nil, nil, s.ctx) - s.Error(err) - - _, err = s.exec.ClosePosition(nil, nil, s.ctx) - s.Error(err) - - err = s.exec.InsuranceFundWithdraw(nil, s.ctx) + err := s.exec.InsuranceFundWithdraw(nil, s.ctx) s.Error(err) } @@ -312,13 +229,8 @@ func (s *TestSuitePerpExecutor) TestSadPath_InsuranceFundWithdraw() { func (s *TestSuitePerpExecutor) TestSadPaths_InvalidPair() { sadPair := asset.Pair("ftt:ust:doge") pair := sadPair - margin := sdk.NewCoin(perpv2types.TestingCollateralDenomNUSD, sdk.NewInt(69)) for _, err := range []error{ - s.DoMarketOrderTest(pair), - s.DoAddMarginTest(pair, margin), - s.DoRemoveMarginTest(pair, margin), - s.DoClosePositionTest(pair), s.DoSetMarketEnabledTest(pair, true), s.DoSetMarketEnabledTest(pair, false), s.DoCreateMarketTest(pair), diff --git a/wasmbinding/exec_test.go b/wasmbinding/exec_test.go index d5b5fd9a5..0ad880db0 100644 --- a/wasmbinding/exec_test.go +++ b/wasmbinding/exec_test.go @@ -127,64 +127,6 @@ func (s *TestSuiteExecutor) OnSetupEnd() { SetExchangeRates(&s.Suite, s.nibiru, s.ctx) } -func (s *TestSuiteExecutor) TestOpenAddRemoveClose() { - pair := asset.MustNewPair(s.happyFields.Pair) - margin := sdk.NewCoin(perpv2types.TestingCollateralDenomNUSD, sdk.NewInt(69)) - - coins := sdk.NewCoins( - margin.Add(sdk.NewCoin(perpv2types.TestingCollateralDenomNUSD, sdk.NewInt(1_000))), - ) - s.NoError(testapp.FundAccount(s.nibiru.BankKeeper, s.ctx, s.contractPerp, coins)) - - // TestMarketOrder (integration - real contract, real app) - execMsg := bindings.NibiruMsg{ - MarketOrder: &bindings.MarketOrder{ - Pair: s.happyFields.Pair, - IsLong: true, - QuoteAmount: sdk.NewInt(42), - Leverage: sdk.NewDec(5), - BaseAmountLimit: sdk.ZeroInt(), - }, - } - - s.T().Log("Executing with permission should succeed") - s.keeper.SetSudoContracts( - []string{s.contractPerp.String()}, s.ctx, - ) - - contractRespBz, err := s.ExecuteAgainstContract(s.contractPerp, execMsg) - s.NoErrorf(err, "contractRespBz: %s", contractRespBz) - - // TestAddMargin (integration - real contract, real app) - execMsg = bindings.NibiruMsg{ - AddMargin: &bindings.AddMargin{ - Pair: pair.String(), - Margin: margin, - }, - } - contractRespBz, err = s.ExecuteAgainstContract(s.contractPerp, execMsg) - s.NoErrorf(err, "contractRespBz: %s", contractRespBz) - - // TestRemoveMargin (integration - real contract, real app) - execMsg = bindings.NibiruMsg{ - RemoveMargin: &bindings.RemoveMargin{ - Pair: pair.String(), - Margin: margin, - }, - } - contractRespBz, err = s.ExecuteAgainstContract(s.contractPerp, execMsg) - s.NoErrorf(err, "contractRespBz: %s", contractRespBz) - - // TestClosePosition (integration - real contract, real app) - execMsg = bindings.NibiruMsg{ - ClosePosition: &bindings.ClosePosition{ - Pair: pair.String(), - }, - } - contractRespBz, err = s.ExecuteAgainstContract(s.contractPerp, execMsg) - s.NoErrorf(err, "contractRespBz: %s", contractRespBz) -} - func (s *TestSuiteExecutor) TestOracleParams() { defaultParams := types.DefaultParams() defaultParams.VotePeriod = 1_000 diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index a05b249c7..51ef552ba 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -62,24 +62,6 @@ func (messenger *CustomMessenger) DispatchMsg( } switch { - // Perp module | bindings-perp: for trading with smart contracts - case contractExecuteMsg.ExecuteMsg.MarketOrder != nil: - cwMsg := contractExecuteMsg.ExecuteMsg.MarketOrder - _, err = messenger.Perp.MarketOrder(cwMsg, contractAddr, ctx) - return events, data, err - case contractExecuteMsg.ExecuteMsg.ClosePosition != nil: - cwMsg := contractExecuteMsg.ExecuteMsg.ClosePosition - _, err = messenger.Perp.ClosePosition(cwMsg, contractAddr, ctx) - return events, data, err - case contractExecuteMsg.ExecuteMsg.AddMargin != nil: - cwMsg := contractExecuteMsg.ExecuteMsg.AddMargin - _, err = messenger.Perp.AddMargin(cwMsg, contractAddr, ctx) - return events, data, err - case contractExecuteMsg.ExecuteMsg.RemoveMargin != nil: - cwMsg := contractExecuteMsg.ExecuteMsg.RemoveMargin - _, err = messenger.Perp.RemoveMargin(cwMsg, contractAddr, ctx) - return events, data, err - // Perp module | controller case contractExecuteMsg.ExecuteMsg.CreateMarket != nil: if err := messenger.Sudo.CheckPermissions(contractAddr, ctx); err != nil { diff --git a/wasmbinding/querier.go b/wasmbinding/querier.go deleted file mode 100644 index 961df23c2..000000000 --- a/wasmbinding/querier.go +++ /dev/null @@ -1,331 +0,0 @@ -package wasmbinding - -import ( - "encoding/json" - "errors" - "fmt" - - sdkerrors "cosmossdk.io/errors" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/NibiruChain/nibiru/wasmbinding/bindings" - "github.com/NibiruChain/nibiru/x/common/asset" - oraclekeeper "github.com/NibiruChain/nibiru/x/oracle/keeper" - oracletypes "github.com/NibiruChain/nibiru/x/oracle/types" - perpv2keeper "github.com/NibiruChain/nibiru/x/perp/v2/keeper" - perpv2types "github.com/NibiruChain/nibiru/x/perp/v2/types" -) - -type QueryPlugin struct { - Perp *PerpQuerier - Oracle *OracleQuerier -} - -// NewQueryPlugin returns a pointer to a new QueryPlugin -func NewQueryPlugin(perp perpv2keeper.Keeper, oracle oraclekeeper.Keeper) QueryPlugin { - return QueryPlugin{ - Perp: &PerpQuerier{ - perp: perpv2keeper.NewQuerier(perp), - }, - Oracle: &OracleQuerier{ - oracle: oraclekeeper.NewQuerier(oracle), - }, - } -} - -func (qp *QueryPlugin) ToBinary( - cwResp any, err error, cwReq any, -) ([]byte, error) { - if err != nil { - return nil, sdkerrors.Wrapf(err, - "failed to query: perp all markets: request: %v", - cwReq) - } - bz, err := json.Marshal(cwResp) - if err != nil { - return nil, sdkerrors.Wrapf(err, "failed to JSON marshal response: %v", cwResp) - } - return bz, nil -} - -// CustomQuerier returns a function that is an implementation of the custom -// querier mechanism for specific messages -func CustomQuerier(qp QueryPlugin) func(ctx sdk.Context, request json.RawMessage) ([]byte, error) { - return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) { - var wasmContractQuery bindings.BindingQuery - if err := json.Unmarshal(request, &wasmContractQuery); err != nil { - return nil, sdkerrors.Wrapf(err, "failed to JSON unmarshal nibiru query: %v", err) - } - - switch { - case wasmContractQuery.AllMarkets != nil: - cwReq := wasmContractQuery.AllMarkets - cwResp, err := qp.Perp.AllMarkets(ctx) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.Reserves != nil: - cwReq := wasmContractQuery.Reserves - cwResp, err := qp.Perp.Reserves(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.BasePrice != nil: - cwReq := wasmContractQuery.BasePrice - cwResp, err := qp.Perp.BasePrice(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.Positions != nil: - cwReq := wasmContractQuery.Positions - cwResp, err := qp.Perp.Positions(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.Position != nil: - cwReq := wasmContractQuery.Position - cwResp, err := qp.Perp.Position(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.PremiumFraction != nil: - cwReq := wasmContractQuery.PremiumFraction - cwResp, err := qp.Perp.PremiumFraction(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.Metrics != nil: - cwReq := wasmContractQuery.Metrics - cwResp, err := qp.Perp.Metrics(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.ModuleAccounts != nil: - cwReq := wasmContractQuery.ModuleAccounts - cwResp, err := qp.Perp.ModuleAccounts(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.PerpParams != nil: - cwReq := wasmContractQuery.PerpParams - cwResp, err := qp.Perp.ModuleParams(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - case wasmContractQuery.OraclePrices != nil: - cwReq := wasmContractQuery.OraclePrices - cwResp, err := qp.Oracle.ExchangeRates(ctx, cwReq) - return qp.ToBinary(cwResp, err, cwReq) - - default: - return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown nibiru query variant"} - } - } -} - -// ---------------------------------------------------------------------- -// PerpQuerier -// ---------------------------------------------------------------------- - -type PerpQuerier struct { - perp perpv2types.QueryServer -} - -func (perpExt *PerpQuerier) Reserves( - ctx sdk.Context, cwReq *bindings.ReservesRequest, -) (*bindings.ReservesResponse, error) { - pair := asset.Pair(cwReq.Pair) - sdkReq := &perpv2types.QueryMarketsRequest{} - goCtx := sdk.WrapSDKContext(ctx) - sdkResp, err := perpExt.perp.QueryMarkets(goCtx, sdkReq) - if err != nil { - return nil, err - } - - for _, market := range sdkResp.AmmMarkets { - if market.Amm.Pair.Equal(pair) { - return &bindings.ReservesResponse{ - Pair: pair.String(), - BaseReserve: market.Amm.BaseReserve, - QuoteReserve: market.Amm.QuoteReserve, - }, err - } - } - - return nil, fmt.Errorf("market not found for pair %s", pair) -} - -func (perpExt *PerpQuerier) AllMarkets( - ctx sdk.Context, -) (*bindings.AllMarketsResponse, error) { - sdkReq := &perpv2types.QueryMarketsRequest{} - goCtx := sdk.WrapSDKContext(ctx) - sdkResp, err := perpExt.perp.QueryMarkets(goCtx, sdkReq) - if err != nil { - return nil, err - } - - marketMap := make(map[string]bindings.Market) - for _, pbMarket := range sdkResp.AmmMarkets { - key := pbMarket.Amm.Pair.String() - marketMap[key] = bindings.Market{ - Pair: key, - Version: sdk.NewIntFromUint64(pbMarket.Market.Version), - BaseReserve: pbMarket.Amm.BaseReserve, - QuoteReserve: pbMarket.Amm.QuoteReserve, - SqrtDepth: pbMarket.Amm.SqrtDepth, - TotalLong: pbMarket.Amm.TotalLong, - TotalShort: pbMarket.Amm.TotalShort, - PegMult: pbMarket.Amm.PriceMultiplier, - Config: &bindings.MarketConfig{ - MaintenanceMarginRatio: pbMarket.Market.MaintenanceMarginRatio, - MaxLeverage: pbMarket.Market.MaxLeverage, - }, - MarkPrice: pbMarket.Amm.InstMarkPrice(), - BlockNumber: sdk.NewInt(ctx.BlockHeight()), - } - } - - return &bindings.AllMarketsResponse{ - MarketMap: marketMap, - }, err -} - -func (perpExt *PerpQuerier) BasePrice( - ctx sdk.Context, cwReq *bindings.BasePriceRequest, -) (*bindings.BasePriceResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -func (perpExt *PerpQuerier) PremiumFraction( - ctx sdk.Context, cwReq *bindings.PremiumFractionRequest, -) (*bindings.PremiumFractionResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -func (perpExt *PerpQuerier) Metrics( - ctx sdk.Context, cwReq *bindings.MetricsRequest, -) (*bindings.MetricsResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -func (perpExt *PerpQuerier) ModuleAccounts( - ctx sdk.Context, cwReq *bindings.ModuleAccountsRequest, -) (*bindings.ModuleAccountsResponse, error) { - if cwReq == nil { - return nil, errors.New("nil request") - } - - sdkReq := &perpv2types.QueryModuleAccountsRequest{} - goCtx := sdk.WrapSDKContext(ctx) - sdkResp, err := perpExt.perp.ModuleAccounts(goCtx, sdkReq) - if err != nil { - return nil, err - } - - moduleAccounts := make(map[string]bindings.ModuleAccountWithBalance) - for _, acc := range sdkResp.Accounts { - addr, err := sdk.AccAddressFromBech32(acc.Address) - if err != nil { - return nil, err - } - moduleAccounts[acc.Name] = bindings.ModuleAccountWithBalance{ - Name: acc.Name, - Addr: addr, - Balance: acc.Balance, - } - } - - return &bindings.ModuleAccountsResponse{ - ModuleAccounts: moduleAccounts, - }, err -} - -func (perpExt *PerpQuerier) ModuleParams( - ctx sdk.Context, cwReq *bindings.PerpParamsRequest, -) (*bindings.PerpParamsResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -func (perpExt *PerpQuerier) Position( - ctx sdk.Context, cwReq *bindings.PositionRequest, -) (*bindings.PositionResponse, error) { - pair, err := asset.TryNewPair(cwReq.Pair) - if err != nil { - return nil, err - } - sdkReq := &perpv2types.QueryPositionRequest{ - Pair: pair, - Trader: cwReq.Trader, - } - goCtx := sdk.WrapSDKContext(ctx) - sdkResp, err := perpExt.perp.QueryPosition(goCtx, sdkReq) - if err != nil { - return nil, err - } - return &bindings.PositionResponse{ - Position: bindings.Position{ - TraderAddr: sdkResp.Position.TraderAddress, - Pair: sdkResp.Position.Pair.String(), - Size: sdkResp.Position.Size_, - Margin: sdkResp.Position.Margin, - OpenNotional: sdkResp.Position.OpenNotional, - LatestCPF: sdkResp.Position.LatestCumulativePremiumFraction, - BlockNumber: sdk.NewInt(sdkResp.Position.LastUpdatedBlockNumber), - }, - Notional: sdkResp.PositionNotional, - Upnl: sdkResp.UnrealizedPnl, - Margin_ratio_mark: sdkResp.MarginRatio, - // Margin_ratio_index: sdkResp.MarginRatioIndex, - Block_number: sdk.NewInt(sdkResp.Position.LastUpdatedBlockNumber), - }, err -} - -func (perpExt *PerpQuerier) Positions( - ctx sdk.Context, cwReq *bindings.PositionsRequest, -) (*bindings.PositionsResponse, error) { - sdkReq := &perpv2types.QueryPositionsRequest{ - Trader: cwReq.Trader, - } - goCtx := sdk.WrapSDKContext(ctx) - sdkResp, err := perpExt.perp.QueryPositions(goCtx, sdkReq) - if err != nil { - return nil, err - } - - positionMap := make(map[string]bindings.Position) - for _, posResp := range sdkResp.Positions { - pair := posResp.Position.Pair.String() - pos := posResp.Position - positionMap[pair] = bindings.Position{ - TraderAddr: pos.TraderAddress, - Pair: pair, - Size: pos.Size_, - Margin: pos.Margin, - OpenNotional: pos.OpenNotional, - LatestCPF: pos.LatestCumulativePremiumFraction, - BlockNumber: sdk.NewInt(pos.LastUpdatedBlockNumber), - } - } - - return &bindings.PositionsResponse{ - Positions: positionMap, - }, err -} - -// ---------------------------------------------------------------------- -// OracleQuerier -// ---------------------------------------------------------------------- - -type OracleQuerier struct { - oracle oracletypes.QueryServer -} - -func (oracleExt *OracleQuerier) ExchangeRates( - ctx sdk.Context, cwReq *bindings.OraclePrices, -) (*bindings.OraclePricesResponse, error) { - queryExchangeRatesRequest := oracletypes.QueryExchangeRatesRequest{} - queryExchangeRates, err := oracleExt.oracle.ExchangeRates(ctx, &queryExchangeRatesRequest) - - // Transform Tuple to Map - exchangeRates := make(map[string]sdk.Dec) - for _, exchangeRate := range queryExchangeRates.ExchangeRates { - exchangeRates[exchangeRate.Pair.String()] = exchangeRate.ExchangeRate - } - - cwResp := new(bindings.OraclePricesResponse) - *cwResp = exchangeRates - return cwResp, err -} diff --git a/wasmbinding/querier_perp_test.go b/wasmbinding/querier_perp_test.go deleted file mode 100644 index efd8d644a..000000000 --- a/wasmbinding/querier_perp_test.go +++ /dev/null @@ -1,319 +0,0 @@ -package wasmbinding_test - -import ( - "encoding/json" - "testing" - "time" - - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - - "github.com/NibiruChain/nibiru/app" - "github.com/NibiruChain/nibiru/wasmbinding" - "github.com/NibiruChain/nibiru/wasmbinding/bindings" - "github.com/NibiruChain/nibiru/wasmbinding/wasmbin" - "github.com/NibiruChain/nibiru/x/common/asset" - "github.com/NibiruChain/nibiru/x/common/denoms" - "github.com/NibiruChain/nibiru/x/common/testutil" - "github.com/NibiruChain/nibiru/x/common/testutil/genesis" - "github.com/NibiruChain/nibiru/x/common/testutil/testapp" - oracletypes "github.com/NibiruChain/nibiru/x/oracle/types" - perpv2types "github.com/NibiruChain/nibiru/x/perp/v2/types" -) - -func TestSuitePerpQuerier_RunAll(t *testing.T) { - suite.Run(t, new(TestSuitePerpQuerier)) -} - -func SetExchangeRates( - testSuite *suite.Suite, - nibiru *app.NibiruApp, - ctx sdk.Context, -) (exchangeRateMap map[asset.Pair]sdk.Dec) { - s := testSuite - exchangeRateTuples := []oracletypes.ExchangeRateTuple{ - { - Pair: asset.Registry.Pair(denoms.ETH, denoms.NUSD), - ExchangeRate: sdk.NewDec(1_000), - }, - { - Pair: asset.Registry.Pair(denoms.NIBI, denoms.NUSD), - ExchangeRate: sdk.NewDec(10), - }, - } - - for _, exchangeRateTuple := range exchangeRateTuples { - pair := exchangeRateTuple.Pair - exchangeRate := exchangeRateTuple.ExchangeRate - nibiru.OracleKeeper.SetPrice(ctx, pair, exchangeRate) - - rate, err := nibiru.OracleKeeper.ExchangeRates.Get(ctx, pair) - s.Assert().NoError(err) - s.Assert().EqualValues(exchangeRate, rate.ExchangeRate) - } - - return oracletypes.ExchangeRateTuples(exchangeRateTuples).ToMap() -} - -// ———————————————————————————————————————————————————————————————————————————— -// # Test Setup -// ———————————————————————————————————————————————————————————————————————————— - -type TestSuitePerpQuerier struct { - suite.Suite - - nibiru *app.NibiruApp - ctx sdk.Context - contractDeployer sdk.AccAddress - queryPlugin wasmbinding.QueryPlugin - - contractPerp sdk.AccAddress - fields ExampleFields - ratesMap map[asset.Pair]sdk.Dec -} - -func SetupPerpGenesis() app.GenesisState { - genesisState := genesis.NewTestGenesisState(app.MakeEncodingConfig()) - genesisState = genesis.AddOracleGenesis(genesisState) - genesisState = genesis.AddPerpV2Genesis(genesisState) - return genesisState -} - -func (s *TestSuitePerpQuerier) SetupSuite() { - s.fields = GetHappyFields() - sender := testutil.AccAddress() - s.contractDeployer = sender - - genesisState := SetupPerpGenesis() - nibiru := testapp.NewNibiruTestApp(genesisState) - ctx := nibiru.NewContext(false, tmproto.Header{ - Height: 1, - ChainID: "nibiru-wasmnet-1", - Time: time.Now().UTC(), - }) - coins := sdk.NewCoins( - sdk.NewCoin(denoms.NIBI, sdk.NewInt(10_000_000)), - sdk.NewCoin(perpv2types.TestingCollateralDenomNUSD, sdk.NewInt(1_420_000)), - ) - s.NoError(testapp.FundAccount(nibiru.BankKeeper, ctx, sender, coins)) - - nibiru, ctx = SetupAllContracts(s.T(), sender, nibiru, ctx) - s.nibiru = nibiru - s.ctx = ctx - - s.contractPerp = ContractMap[wasmbin.WasmKeyPerpBinding] - s.queryPlugin = wasmbinding.NewQueryPlugin( - nibiru.PerpKeeperV2, - nibiru.OracleKeeper, - ) - s.OnSetupEnd() -} - -func (s *TestSuitePerpQuerier) OnSetupEnd() { - s.ratesMap = SetExchangeRates(&s.Suite, s.nibiru, s.ctx) -} - -// ———————————————————————————————————————————————————————————————————————————— -// # Tests -// -// - TestPremiumFraction -// - TestAllMarkets -// - TestMetrics -// - TestModuleAccounts -// - TestModuleParams -// - TestPosition -// ———————————————————————————————————————————————————————————————————————————— - -func (s *TestSuitePerpQuerier) TestPremiumFraction() { - testCases := map[string]struct { - cwReq *bindings.PremiumFractionRequest - cwResp *bindings.PremiumFractionResponse - expectErr bool - }{ - "invalid pair": { - cwReq: &bindings.PremiumFractionRequest{Pair: "nonsense"}, - expectErr: true, - }, - "happy": { - cwReq: &bindings.PremiumFractionRequest{Pair: s.fields.Pair}, - cwResp: &bindings.PremiumFractionResponse{ - Pair: s.fields.Pair, - CPF: sdk.MustNewDecFromStr("0.5"), - EstimatedNextCPF: sdk.MustNewDecFromStr("0.5"), - }, - expectErr: false, - }, - } - - for name, testCase := range testCases { - s.T().Run(name, func(t *testing.T) { - cwResp, err := s.queryPlugin.Perp.PremiumFraction( - s.ctx, testCase.cwReq, - ) - - if testCase.expectErr { - s.Error(err) - return - } - - s.Errorf(err, "cwResp: %s", cwResp) - s.Nil(cwResp) - // s.Assert().EqualValues(cwResp.Pair, cwResp.Pair) - // s.Assert().EqualValues(cwResp.CPF.String(), cwResp.CPF.String()) - // s.Assert().EqualValues(cwResp.EstimatedNextCPF.String(), cwResp.EstimatedNextCPF.String()) - }) - } -} - -func (s *TestSuitePerpQuerier) TestAllMarkets() { - type CwMarketMap map[asset.Pair]bindings.Market - - marketMap := make(CwMarketMap) - for pair, ammMarket := range genesis.START_MARKETS { - cwMarket := bindings.NewMarket( - ammMarket.Market, - ammMarket.Amm, - "", - "", - s.ctx.BlockHeight(), - ) - marketMap[pair] = cwMarket - - // Test the ToAppMarket fn - gotAppMarket, err := cwMarket.ToAppMarket() - s.Assert().NoError(err) - s.Assert().EqualValues(ammMarket.Market, gotAppMarket) - } - - testCases := map[string]struct { - marketMap CwMarketMap - expectErr bool - }{ - "happy": { - marketMap: marketMap, - expectErr: false, - }, - } - - for name, testCase := range testCases { - s.T().Run(name, func(t *testing.T) { - cwResp, err := s.queryPlugin.Perp.AllMarkets(s.ctx) - - if testCase.expectErr { - s.Error(err) - return - } - - s.NoErrorf(err, "cwResp: %s", cwResp) - for pair, cwMarketWant := range testCase.marketMap { - cwMarketOut := cwResp.MarketMap[pair.String()] - - jsonWant, err := json.Marshal(cwMarketWant) - s.Assert().NoError(err) - jsonGot, err := json.Marshal(cwMarketOut) - s.Assert().NoError(err) - - s.Assert().EqualValuesf( - cwMarketWant, cwMarketOut, - "\nwant: %s\ngot: %s", jsonWant, jsonGot, - ) - } - }) - } -} - -func (s *TestSuitePerpQuerier) TestMetrics() { - // happy case - for pair := range genesis.START_MARKETS { - cwReq := &bindings.MetricsRequest{Pair: pair.String()} - cwResp, err := s.queryPlugin.Perp.Metrics(s.ctx, cwReq) - s.Error(err, "cwResp: %s", cwResp) - s.Nil(cwResp) - } - - // sad case - cwReq := &bindings.MetricsRequest{Pair: "ftt:ust"} - cwResp, err := s.queryPlugin.Perp.Metrics(s.ctx, cwReq) - s.Errorf(err, "cwResp: %s", cwResp) -} - -func (s *TestSuitePerpQuerier) TestModuleAccounts() { - cwReq := &bindings.ModuleAccountsRequest{} - cwResp, err := s.queryPlugin.Perp.ModuleAccounts(s.ctx, cwReq) - s.NoErrorf(err, "\ncwResp: %s", cwResp) -} - -func (s *TestSuitePerpQuerier) TestModuleParams() { - cwReq := &bindings.PerpParamsRequest{} - cwResp, err := s.queryPlugin.Perp.ModuleParams(s.ctx, cwReq) - s.Errorf(err, "\ncwResp: %s", cwResp) - s.Nil(cwResp) -} - -func (s *TestSuitePerpQuerier) TestPosition() { - trader := s.contractDeployer - pair := genesis.PerpV2Genesis().Markets[0].Pair - margin := sdk.NewInt(1_000_000) - leverage := sdk.NewDec(5) - baseAmtLimit := sdk.ZeroDec() - - s.T().Log("Request should error since the trader hasn't yet opened a position") - cwReq := &bindings.PositionRequest{ - Trader: trader.String(), - Pair: pair.String(), - } - cwResp, err := s.queryPlugin.Perp.Position(s.ctx, cwReq) - s.Errorf(err, "\ncwResp: %s", cwResp) - - s.T().Log("Open a position") - resp, err := s.nibiru.PerpKeeperV2.MarketOrder( - s.ctx, pair, perpv2types.Direction_LONG, - trader, margin, leverage, baseAmtLimit, - ) - s.NoError(err) - - s.T().Log("Successfully query position") - cwResp, err = s.queryPlugin.Perp.Position(s.ctx, cwReq) - s.NoErrorf(err, "\ncwResp: %s", cwResp) - - // Verify that the response marshals to JSON - jsonBz, err := json.Marshal(cwResp) - s.NoErrorf(err, "jsonBz: %s", jsonBz) - // and unmarshals from JSON - freshCwResp := new(bindings.PositionResponse) - err = json.Unmarshal(jsonBz, freshCwResp) - s.NoErrorf(err, "freshCwResp: %s", freshCwResp) - s.Assert().EqualValues(resp.ExchangedNotionalValue, leverage.MulInt(margin)) - s.Assert().EqualValues(cwResp.Position.OpenNotional, leverage.MulInt(margin)) - s.Assert().EqualValues(cwResp.Position.Margin, sdk.NewDecFromInt(margin)) - - s.T().Log("fail due to invalid pair") - cwReq = &bindings.PositionRequest{ - Trader: trader.String(), - Pair: "ftt:ust:xyz", - } - cwResp, err = s.queryPlugin.Perp.Position(s.ctx, cwReq) - s.Errorf(err, "\ncwResp: %s", cwResp) - - s.T().Log("test multiple positions query") - positionResponses := []bindings.PositionResponse{*freshCwResp} - s.DoPositionsTest(trader, positionResponses) -} - -func (s *TestSuitePerpQuerier) DoPositionsTest( - trader sdk.AccAddress, responses []bindings.PositionResponse, -) { - s.T().Log("test multiple positions query") - cwReq := &bindings.PositionsRequest{ - Trader: trader.String(), - } - cwResp, err := s.queryPlugin.Perp.Positions(s.ctx, cwReq) - s.NoErrorf(err, "\ncwResp: %s", cwResp) - - for _, resp := range responses { - pair := resp.Position.Pair - pos := cwResp.Positions[pair] - s.Assert().EqualValues(resp.Position, pos) - } -} diff --git a/wasmbinding/querier_test.go b/wasmbinding/querier_test.go deleted file mode 100644 index a5763c9b8..000000000 --- a/wasmbinding/querier_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package wasmbinding_test - -import ( - "encoding/json" - "testing" - "time" - - sdkerrors "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" - - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/suite" - - "github.com/NibiruChain/nibiru/app" - "github.com/NibiruChain/nibiru/wasmbinding/bindings" - "github.com/NibiruChain/nibiru/wasmbinding/wasmbin" - "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/common/testutil" - "github.com/NibiruChain/nibiru/x/common/testutil/genesis" - "github.com/NibiruChain/nibiru/x/common/testutil/testapp" -) - -func TestSuiteQuerier_RunAll(t *testing.T) { - suite.Run(t, new(TestSuiteQuerier)) -} - -func DoCustomBindingQuery( - ctx sdk.Context, - nibiru *app.NibiruApp, - contract sdk.AccAddress, - bindingRequest bindings.BindingQuery, - responsePointer interface{}, -) (contractRespBz []byte, err error) { - // Parse query type compatible with wasm vm - reqJsonBz, err := json.Marshal(bindingRequest) - if err != nil { - return contractRespBz, err - } - - // Query the smart contract - var originalError error - if err := common.TryCatch(func() { - // The WasmVM tends to panic pretty easily with "Wasmer runtimer error". - // TryCatch here makes it more safe and easy to debug. - bz, err := nibiru.WasmKeeper.QuerySmart( - ctx, contract, reqJsonBz, - ) - if err != nil { - originalError = err - } else { - contractRespBz = bz - } - })(); err != nil { - return contractRespBz, sdkerrors.Wrapf( - err, "contractRespBz: %s", contractRespBz) - } - - // originalError: the error raised if the WasmVM doesn't panic - if originalError != nil { - return contractRespBz, originalError - } - - // Parse the response data into the response pointer - err = json.Unmarshal(contractRespBz, responsePointer) - if err != nil { - return contractRespBz, sdkerrors.Wrapf( - err, "responsePointer: %s", responsePointer) - } - - return contractRespBz, nil -} - -type TestSuiteQuerier struct { - suite.Suite - - nibiru *app.NibiruApp - ctx sdk.Context - contractDeployer sdk.AccAddress - - contractPerp sdk.AccAddress - fields ExampleFields -} - -type ExampleFields struct { - Pair string - Trader sdk.AccAddress - Dec sdk.Dec - Int sdkmath.Int - Market bindings.Market -} - -func GetHappyFields() ExampleFields { - fields := ExampleFields{ - Pair: asset.Registry.Pair(denoms.ETH, denoms.NUSD).String(), - Trader: sdk.AccAddress([]byte("trader")), - Dec: sdk.NewDec(50), - Int: sdk.NewInt(420), - } - - fields.Market = bindings.Market{ - Pair: fields.Pair, - BaseReserve: fields.Dec, - QuoteReserve: fields.Dec, - SqrtDepth: fields.Dec, - Depth: fields.Int, - TotalLong: fields.Dec, - TotalShort: fields.Dec, - PegMult: fields.Dec, - Config: &bindings.MarketConfig{ - MaintenanceMarginRatio: fields.Dec, - MaxLeverage: fields.Dec, - }, - MarkPrice: fields.Dec, - IndexPrice: fields.Dec.String(), - TwapMark: fields.Dec.String(), - BlockNumber: sdk.NewInt(100), - } - return fields -} - -func (s *TestSuiteQuerier) SetupSuite() { - s.fields = GetHappyFields() - sender := testutil.AccAddress() - s.contractDeployer = sender - - genesisState := SetupPerpGenesis() - nibiru := testapp.NewNibiruTestApp(genesisState) - ctx := nibiru.NewContext(false, tmproto.Header{ - Height: 1, - ChainID: "nibiru-wasmnet-1", - Time: time.Now().UTC(), - }) - coins := sdk.NewCoins( - sdk.NewCoin(denoms.NIBI, sdk.NewInt(1_000)), - sdk.NewCoin(denoms.NUSD, sdk.NewInt(420)), - ) - s.NoError(testapp.FundAccount(nibiru.BankKeeper, ctx, sender, coins)) - - nibiru, ctx = SetupAllContracts(s.T(), sender, nibiru, ctx) - s.nibiru = nibiru - s.ctx = ctx - - s.contractPerp = ContractMap[wasmbin.WasmKeyPerpBinding] - s.OnSetupEnd() -} - -func (s *TestSuiteQuerier) OnSetupEnd() { - SetExchangeRates(&s.Suite, s.nibiru, s.ctx) -} - -func (s *TestSuiteQuerier) TestQueryReserves() { - testCases := map[string]struct { - pairStr string - wasmError bool - }{ - "happy": {pairStr: s.fields.Pair, wasmError: false}, - "sad - non existent pair": {pairStr: "ftt:ust", wasmError: true}, - } - - for name, testCase := range testCases { - s.T().Run(name, func(t *testing.T) { - pairStr := testCase.pairStr - bindingQuery := bindings.BindingQuery{ - Reserves: &bindings.ReservesRequest{Pair: pairStr}, - } - bindingResp := new(bindings.ReservesResponse) - - if testCase.wasmError { - _, err := DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, - bindingQuery, bindingResp, - ) - s.Assert().Contains(err.Error(), "query wasm contract failed") - return - } - - _, err := DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - s.Require().NoError(err) - - wantPair := asset.MustNewPair(pairStr) - s.Assert().EqualValues(bindingResp.Pair, wantPair) - s.Assert().EqualValues( - bindingResp.BaseReserve.String(), - genesis.START_MARKETS[wantPair].Amm.BaseReserve.String()) - s.Assert().EqualValues( - bindingResp.QuoteReserve.String(), - genesis.START_MARKETS[wantPair].Amm.QuoteReserve.String()) - }) - } -} - -// Integration test for BindingQuery::AllMarkets against real contract -func (s *TestSuiteQuerier) TestQueryAllMarkets() { - bindingQuery := bindings.BindingQuery{ - AllMarkets: &bindings.AllMarketsRequest{}, - } - bindingResp := new(bindings.AllMarketsResponse) - - respBz, err := DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - s.Require().NoErrorf(err, "resp bytes: %s", respBz) - - for pair, marketAmm := range genesis.START_MARKETS { - cwMarket := bindingResp.MarketMap[pair.String()] - s.Assert().EqualValues(marketAmm.Amm.BaseReserve, cwMarket.BaseReserve) - s.Assert().EqualValues(marketAmm.Amm.QuoteReserve, cwMarket.QuoteReserve) - s.Assert().EqualValues(marketAmm.Amm.SqrtDepth, cwMarket.SqrtDepth) - s.Assert().EqualValues(marketAmm.Amm.TotalLong, cwMarket.TotalLong) - s.Assert().EqualValues(marketAmm.Amm.TotalShort, cwMarket.TotalShort) - s.Assert().EqualValues(marketAmm.Amm.PriceMultiplier.String(), cwMarket.PegMult.String()) - s.Assert().EqualValues(marketAmm.Amm.InstMarkPrice().String(), cwMarket.MarkPrice.String()) - s.Assert().EqualValues(s.ctx.BlockHeight(), cwMarket.BlockNumber.Int64()) - } -} - -// Integration test for BindingQuery::AllMarkets against real contract -func (s *TestSuiteQuerier) TestQueryExchangeRate() { - bindingQuery := bindings.BindingQuery{ - OraclePrices: &bindings.OraclePrices{}, - } - bindingResp := new(bindings.OraclePricesResponse) - respBz, err := DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - priceMap := *bindingResp - s.Require().NoErrorf(err, "resp bytes: %s", respBz) - s.Assert().EqualValues(sdk.NewDec(1000).String(), priceMap["ueth:unusd"].String()) -} - -func (s *TestSuiteQuerier) TestQueryBasePrice() { - cwReq := &bindings.BasePriceRequest{ - Pair: s.fields.Pair, - IsLong: true, - BaseAmount: sdk.NewInt(69_420), - } - bindingQuery := bindings.BindingQuery{ - BasePrice: cwReq, - } - bindingResp := new(bindings.BasePriceResponse) - - var respBz []byte - var err error - err = common.TryCatch(func() { - respBz, err = DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - s.Require().Errorf(err, "expect error since query is not implemented: resp bytes: %s", respBz) - s.Require().Contains(err.Error(), "Wasmer runtime error") - })() - - // s.Require().NoErrorf(err, "resp bytes: %s", respBz) - // s.Assert().EqualValues(cwReq.Pair, bindingResp.Pair) - // s.Assert().EqualValues(cwReq.IsLong, bindingResp.IsLong) - // s.Assert().EqualValues(cwReq.BaseAmount.String(), bindingResp.BaseAmount.String()) - // s.Assert().True(bindingResp.QuoteAmount.GT(sdk.ZeroDec())) - // - // cwReqBz, err := json.Marshal(cwReq) - // s.T().Logf("cwReq: %s", cwReqBz) - // s.NoError(err) - // - // cwRespBz, err := json.Marshal(bindingResp) - // s.T().Logf("cwResp: %s", cwRespBz) - // s.NoError(err) -} - -func (s *TestSuiteQuerier) TestQueryPremiumFraction() { - cwReq := &bindings.PremiumFractionRequest{ - Pair: s.fields.Pair, - } - - bindingQuery := bindings.BindingQuery{ - PremiumFraction: cwReq, - } - bindingResp := new(bindings.PremiumFractionResponse) - - var respBz []byte - var err error - err = common.TryCatch(func() { - respBz, err = DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - s.Require().Errorf(err, "expect error since query is not implemented: resp bytes: %s", respBz) - s.Require().Contains(err.Error(), "Querier contract error") - })() - - // respBz, err := DoCustomBindingQuery( - // s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - // ) - // s.Require().NoErrorf(err, "resp bytes: %s", respBz) - - // s.Assert().EqualValues(cwReq.Pair, bindingResp.Pair) - // s.Assert().Truef( - // - // !bindingResp.CPF.IsNegative(), - // "cpf: %s", - // bindingResp.CPF) - // - // s.Assert().Truef( - // - // !bindingResp.EstimatedNextCPF.IsNegative(), - // "estimated_next_cpf: %s", - // bindingResp.EstimatedNextCPF) -} - -// func (s *TestSuiteQuerier) TestQueryMetrics() { -// cwReq := &bindings.MetricsRequest{ -// Pair: s.fields.Pair, -// } - -// bindingQuery := bindings.BindingQuery{ -// Metrics: cwReq, -// } -// bindingResp := new(bindings.MetricsResponse) - -// respBz, err := DoCustomBindingQuery( -// s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, -// ) -// s.Require().NoErrorf(err, "resp bytes: %s", respBz) -// } - -// func (s *TestSuiteQuerier) TestQueryPerpParams() { -// cwReq := &bindings.PerpParamsRequest{} - -// bindingQuery := bindings.BindingQuery{ -// PerpParams: cwReq, -// } -// bindingResp := new(bindings.PerpParamsResponse) - -// respBz, err := DoCustomBindingQuery( -// s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, -// ) -// s.Require().NoErrorf(err, "resp bytes: %s", respBz) -// } - -func (s *TestSuiteQuerier) TestQueryPerpModuleAccounts() { - cwReq := &bindings.ModuleAccountsRequest{} - - bindingQuery := bindings.BindingQuery{ - ModuleAccounts: cwReq, - } - bindingResp := new(bindings.ModuleAccountsResponse) - - respBz, err := DoCustomBindingQuery( - s.ctx, s.nibiru, s.contractPerp, bindingQuery, bindingResp, - ) - s.Require().NoErrorf(err, "resp bytes: %s", respBz) -} diff --git a/wasmbinding/wasm.go b/wasmbinding/wasm.go index baee43c27..972e5067f 100644 --- a/wasmbinding/wasm.go +++ b/wasmbinding/wasm.go @@ -20,9 +20,7 @@ func NibiruWasmOptions( sudoKeeper keeper.Keeper, oracleKeeper oraclekeeper.Keeper, ) []wasmkeeper.Option { - wasmQueryPlugin := NewQueryPlugin(perpv2, oracleKeeper) wasmQueryOption := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{ - Custom: CustomQuerier(wasmQueryPlugin), Stargate: wasmkeeper.AcceptListStargateQuerier( WasmAcceptedStargateQueries(), grpcQueryRouter, diff --git a/x/perp/v2/keeper/amm.go b/x/perp/v2/keeper/amm.go index 7fc741f6b..ae317d7f0 100644 --- a/x/perp/v2/keeper/amm.go +++ b/x/perp/v2/keeper/amm.go @@ -19,7 +19,9 @@ func (k Keeper) handleMarketUpdateCost( return costPaid, err } - if costAmt.IsPositive() { + if costAmt.IsZero() { + costPaid = sdk.NewCoin(collateral, costAmt) + } else if costAmt.IsPositive() { // Positive cost, send from perp EF to vault cost := sdk.NewCoins( sdk.NewCoin(collateral, costAmt), diff --git a/x/perp/v2/types/msgs_test.go b/x/perp/v2/types/msgs_test.go index ae92f4a67..e57c074b3 100644 --- a/x/perp/v2/types/msgs_test.go +++ b/x/perp/v2/types/msgs_test.go @@ -377,7 +377,7 @@ func TestMsgValidateBasic(t *testing.T) { msg: &MsgShiftPegMultiplier{ Sender: validSender, Pair: asset.Pair("not_a_pair"), - NewPegMult: sdk.NewDec(420), + NewPegMult: sdk.NewDec(420), // valid positive value, unused }, expectErr: true, expectedError: asset.ErrInvalidTokenPair.Error(), @@ -387,7 +387,7 @@ func TestMsgValidateBasic(t *testing.T) { msg: &MsgShiftPegMultiplier{ Sender: validSender, Pair: asset.Pair("valid:pair"), - NewPegMult: sdk.NewDec(-420), + NewPegMult: sdk.NewDec(-420), // invalid nonpositive }, expectErr: true, expectedError: ErrNonPositivePegMultiplier.Error(), @@ -398,7 +398,7 @@ func TestMsgValidateBasic(t *testing.T) { msg: &MsgShiftSwapInvariant{ Sender: validSender, Pair: asset.Pair("not_a_pair"), - NewSwapInvariant: sdk.NewInt(420), + NewSwapInvariant: sdk.NewInt(420), // valid positive }, expectErr: true, expectedError: asset.ErrInvalidTokenPair.Error(), @@ -408,7 +408,17 @@ func TestMsgValidateBasic(t *testing.T) { msg: &MsgShiftSwapInvariant{ Sender: validSender, Pair: asset.Pair("valid:pair"), - NewSwapInvariant: sdk.NewInt(-420), + NewSwapInvariant: sdk.NewInt(-420), // invalid nonpositive + }, + expectErr: true, + expectedError: ErrNonPositiveSwapInvariant.Error(), + }, + { + name: "MsgShiftSwapInvariant: nonpositive swap invariant", + msg: &MsgShiftSwapInvariant{ + Sender: validSender, + Pair: asset.Pair("valid:pair"), + NewSwapInvariant: sdk.ZeroInt(), // invalid nonpositive }, expectErr: true, expectedError: ErrNonPositiveSwapInvariant.Error(),