/
query_plugin.go
183 lines (147 loc) · 5.16 KB
/
query_plugin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package wasmbinding
import (
"encoding/json"
"fmt"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/osmosis-labs/osmosis/v14/wasmbinding/bindings"
)
// StargateQuerier dispatches whitelisted stargate queries
func StargateQuerier(queryRouter baseapp.GRPCQueryRouter, cdc codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
protoResponseType, err := GetWhitelistedQuery(request.Path)
if err != nil {
return nil, err
}
route := queryRouter.Route(request.Path)
if route == nil {
return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", request.Path)}
}
res, err := route(ctx, abci.RequestQuery{
Data: request.Data,
Path: request.Path,
})
if err != nil {
return nil, err
}
bz, err := ConvertProtoToJSONMarshal(protoResponseType, res.Value, cdc)
if err != nil {
return nil, err
}
return bz, nil
}
}
// CustomQuerier dispatches custom CosmWasm bindings queries.
func CustomQuerier(qp *QueryPlugin) func(ctx sdk.Context, request json.RawMessage) ([]byte, error) {
return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) {
var contractQuery bindings.OsmosisQuery
if err := json.Unmarshal(request, &contractQuery); err != nil {
return nil, sdkerrors.Wrap(err, "osmosis query")
}
switch {
case contractQuery.FullDenom != nil:
creator := contractQuery.FullDenom.CreatorAddr
subdenom := contractQuery.FullDenom.Subdenom
fullDenom, err := GetFullDenom(creator, subdenom)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo full denom query")
}
res := bindings.FullDenomResponse{
Denom: fullDenom,
}
bz, err := json.Marshal(res)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo full denom query response")
}
return bz, nil
case contractQuery.DenomAdmin != nil:
res, err := qp.GetDenomAdmin(ctx, contractQuery.DenomAdmin.Subdenom)
if err != nil {
return nil, err
}
bz, err := json.Marshal(res)
if err != nil {
return nil, fmt.Errorf("failed to JSON marshal DenomAdminResponse response: %w", err)
}
return bz, nil
case contractQuery.PoolState != nil:
poolId := contractQuery.PoolState.PoolId
state, err := qp.GetPoolState(ctx, poolId)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo pool state query")
}
assets := ConvertSdkCoinsToWasmCoins(state.Assets)
shares := ConvertSdkCoinToWasmCoin(state.Shares)
res := bindings.PoolStateResponse{
Assets: assets,
Shares: shares,
}
bz, err := json.Marshal(res)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo pool state query response")
}
return bz, nil
case contractQuery.SpotPrice != nil:
spotPrice, err := qp.GetSpotPrice(ctx, contractQuery.SpotPrice)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo spot price query")
}
res := bindings.SpotPriceResponse{Price: spotPrice.String()}
bz, err := json.Marshal(res)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo spot price query response")
}
return bz, nil
case contractQuery.EstimateSwap != nil:
swapAmount, err := qp.EstimateSwap(ctx, contractQuery.EstimateSwap)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo estimate swap query")
}
res := bindings.EstimatePriceResponse{Amount: *swapAmount}
bz, err := json.Marshal(res)
if err != nil {
return nil, sdkerrors.Wrap(err, "osmo estimate swap query response")
}
return bz, nil
default:
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown osmosis query variant"}
}
}
}
// ConvertProtoToJsonMarshal unmarshals the given bytes into a proto message and then marshals it to json.
// This is done so that clients calling stargate queries do not need to define their own proto unmarshalers,
// being able to use response directly by json marshalling, which is supported in cosmwasm.
func ConvertProtoToJSONMarshal(protoResponseType codec.ProtoMarshaler, bz []byte, cdc codec.Codec) ([]byte, error) {
// unmarshal binary into stargate response data structure
err := cdc.Unmarshal(bz, protoResponseType)
if err != nil {
return nil, wasmvmtypes.Unknown{}
}
bz, err = cdc.MarshalJSON(protoResponseType)
if err != nil {
return nil, wasmvmtypes.Unknown{}
}
protoResponseType.Reset()
return bz, nil
}
// ConvertSdkCoinsToWasmCoins converts sdk type coins to wasm vm type coins
func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Coins {
var toSend wasmvmtypes.Coins
for _, coin := range coins {
c := ConvertSdkCoinToWasmCoin(coin)
toSend = append(toSend, c)
}
return toSend
}
// ConvertSdkCoinToWasmCoin converts a sdk type coin to a wasm vm type coin
func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin {
return wasmvmtypes.Coin{
Denom: coin.Denom,
// Note: gamm tokens have 18 decimal places, so 10^22 is common, no longer in u64 range
Amount: coin.Amount.String(),
}
}