diff --git a/proto/Dockerfile b/proto/Dockerfile new file mode 100644 index 000000000..f5e6f162c --- /dev/null +++ b/proto/Dockerfile @@ -0,0 +1,39 @@ +# This Dockerfile is used for proto generation +# To build, run `make proto-image-build` + +FROM bufbuild/buf:1.7.0 as BUILDER + +FROM golang:1.19-alpine + + +RUN apk add --no-cache \ + nodejs \ + npm \ + git \ + make + +ENV GOLANG_PROTOBUF_VERSION=1.28.0 \ + GOGO_PROTOBUF_VERSION=1.3.2 \ + GRPC_GATEWAY_VERSION=1.16.0 + + +RUN go install github.com/cosmos/cosmos-proto/cmd/protoc-gen-go-pulsar@latest +RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${GOLANG_PROTOBUF_VERSION} +RUN go install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway@v${GRPC_GATEWAY_VERSION} \ + github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger@v${GRPC_GATEWAY_VERSION} + +# install all gogo protobuf binaries +RUN git clone https://github.com/regen-network/protobuf.git; \ + cd protobuf; \ + go mod download; \ + make install + +# we need to use git clone because we use 'replace' directive in go.mod +# protoc-gen-gocosmos was moved to to in cosmos/gogoproto but pending a migration there. +RUN git clone https://github.com/regen-network/cosmos-proto.git; \ + cd cosmos-proto/protoc-gen-gocosmos; \ + go install . + +RUN npm install -g swagger-combine + +COPY --from=BUILDER /usr/local/bin /usr/local/bin diff --git a/proto/buf.gen.doc.yml b/proto/buf.gen.doc.yml new file mode 100644 index 000000000..6a18570df --- /dev/null +++ b/proto/buf.gen.doc.yml @@ -0,0 +1,5 @@ +version: v1 +plugins: + - name: doc + out: ../docs/proto + opt: ../docs/proto/protodoc-markdown.tmpl,proto-docs.md diff --git a/proto/buf.gen.gogo.yaml b/proto/buf.gen.gogo.yaml index 9c8ba0a4b..1d1910836 100644 --- a/proto/buf.gen.gogo.yaml +++ b/proto/buf.gen.gogo.yaml @@ -2,7 +2,7 @@ version: v1 plugins: - name: gocosmos out: .. - opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types + opt: plugins=grpc,Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1alpha1/orm.proto=github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1 - name: grpc-gateway out: .. - opt: logtostderr=true,allow_colon_final_segments=true + opt: logtostderr=true,allow_colon_final_segments=true \ No newline at end of file diff --git a/proto/buf.gen.gogo.yml b/proto/buf.gen.gogo.yml new file mode 100644 index 000000000..855ea251a --- /dev/null +++ b/proto/buf.gen.gogo.yml @@ -0,0 +1,8 @@ +version: v1 +plugins: + - name: gocosmos + out: .. + opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types + - name: grpc-gateway + out: .. + opt: logtostderr=true,allow_colon_final_segments=true \ No newline at end of file diff --git a/proto/buf.lock b/proto/buf.lock index f7e7eb4b6..fae8adcbe 100644 --- a/proto/buf.lock +++ b/proto/buf.lock @@ -8,7 +8,7 @@ deps: - remote: buf.build owner: cosmos repository: cosmos-sdk - commit: e0cedba5309948a0b4734cab8e311723 + commit: 8dc523b705c34317bfd4a961fba89e72 - remote: buf.build owner: cosmos repository: gogo-proto @@ -16,4 +16,4 @@ deps: - remote: buf.build owner: googleapis repository: googleapis - commit: 75b4300737fb4efca0831636be94e517 + commit: 5ae7f88519b04fe1965da0f8a375a088 diff --git a/proto/buf.yaml b/proto/buf.yaml index 4a643443a..c621b97be 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -1,5 +1,5 @@ version: v1 -name: buf.build/CosmosContracts/juno +name: buf.build/osmosis-labs/osmosis deps: - buf.build/cosmos/cosmos-sdk - buf.build/cosmos/cosmos-proto @@ -19,3 +19,5 @@ lint: - SERVICE_SUFFIX - PACKAGE_VERSION_SUFFIX - RPC_REQUEST_STANDARD_NAME + ignore: + - tendermint \ No newline at end of file diff --git a/proto/osmosis/tokenfactory/v1beta1/authorityMetadata.proto b/proto/osmosis/tokenfactory/v1beta1/authorityMetadata.proto new file mode 100755 index 000000000..b0c2fe756 --- /dev/null +++ b/proto/osmosis/tokenfactory/v1beta1/authorityMetadata.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package osmosis.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types"; + +// DenomAuthorityMetadata specifies metadata for addresses that have specific +// capabilities over a token factory denom. Right now there is only one Admin +// permission, but is planned to be extended to the future. +message DenomAuthorityMetadata { + option (gogoproto.equal) = true; + + // Can be empty for no admin, or a valid osmosis address + string admin = 1 [ (gogoproto.moretags) = "yaml:\"admin\"" ]; +} \ No newline at end of file diff --git a/proto/osmosis/tokenfactory/v1beta1/genesis.proto b/proto/osmosis/tokenfactory/v1beta1/genesis.proto new file mode 100755 index 000000000..a14f0336b --- /dev/null +++ b/proto/osmosis/tokenfactory/v1beta1/genesis.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; +package osmosis.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "osmosis/tokenfactory/v1beta1/authorityMetadata.proto"; +import "osmosis/tokenfactory/v1beta1/params.proto"; + +option go_package = "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types"; + +// GenesisState defines the tokenfactory module's genesis state. +message GenesisState { + // params defines the paramaters of the module. + Params params = 1 [ (gogoproto.nullable) = false ]; + + repeated GenesisDenom factory_denoms = 2 [ + (gogoproto.moretags) = "yaml:\"factory_denoms\"", + (gogoproto.nullable) = false + ]; +} + +// GenesisDenom defines a tokenfactory denom that is defined within genesis +// state. The structure contains DenomAuthorityMetadata which defines the +// denom's admin. +message GenesisDenom { + option (gogoproto.equal) = true; + + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + DenomAuthorityMetadata authority_metadata = 2 [ + (gogoproto.moretags) = "yaml:\"authority_metadata\"", + (gogoproto.nullable) = false + ]; +} \ No newline at end of file diff --git a/proto/osmosis/tokenfactory/v1beta1/params.proto b/proto/osmosis/tokenfactory/v1beta1/params.proto new file mode 100755 index 000000000..36ffafa82 --- /dev/null +++ b/proto/osmosis/tokenfactory/v1beta1/params.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package osmosis.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "osmosis/tokenfactory/v1beta1/authorityMetadata.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types"; + +// Params defines the parameters for the tokenfactory module. +message Params { + repeated cosmos.base.v1beta1.Coin denom_creation_fee = 1 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.moretags) = "yaml:\"denom_creation_fee\"", + (gogoproto.nullable) = false + ]; + + // if denom_creation_fee is an empty array, then this field is used to add more gas consumption + // to the base cost. + // https://github.com/CosmWasm/token-factory/issues/11 + uint64 denom_creation_gas_consume = 2 [ + (gogoproto.moretags) = "yaml:\"denom_creation_gas_consume\"", + (gogoproto.nullable) = true + ]; +} \ No newline at end of file diff --git a/proto/osmosis/tokenfactory/v1beta1/query.proto b/proto/osmosis/tokenfactory/v1beta1/query.proto new file mode 100755 index 000000000..0d5795ce8 --- /dev/null +++ b/proto/osmosis/tokenfactory/v1beta1/query.proto @@ -0,0 +1,71 @@ +syntax = "proto3"; +package osmosis.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "osmosis/tokenfactory/v1beta1/authorityMetadata.proto"; +import "osmosis/tokenfactory/v1beta1/params.proto"; + +option go_package = "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types"; + +// Query defines the gRPC querier service. +service Query { + // Params defines a gRPC query method that returns the tokenfactory module's + // parameters. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/osmosis/tokenfactory/v1beta1/params"; + } + + // DenomAuthorityMetadata defines a gRPC query method for fetching + // DenomAuthorityMetadata for a particular denom. + rpc DenomAuthorityMetadata(QueryDenomAuthorityMetadataRequest) + returns (QueryDenomAuthorityMetadataResponse) { + option (google.api.http).get = + "/osmosis/tokenfactory/v1beta1/denoms/{denom}/authority_metadata"; + } + + // DenomsFromCreator defines a gRPC query method for fetching all + // denominations created by a specific admin/creator. + rpc DenomsFromCreator(QueryDenomsFromCreatorRequest) + returns (QueryDenomsFromCreatorResponse) { + option (google.api.http).get = + "/osmosis/tokenfactory/v1beta1/denoms_from_creator/{creator}"; + } +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryDenomAuthorityMetadataRequest defines the request structure for the +// DenomAuthorityMetadata gRPC query. +message QueryDenomAuthorityMetadataRequest { + string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; +} + +// QueryDenomAuthorityMetadataResponse defines the response structure for the +// DenomAuthorityMetadata gRPC query. +message QueryDenomAuthorityMetadataResponse { + DenomAuthorityMetadata authority_metadata = 1 [ + (gogoproto.moretags) = "yaml:\"authority_metadata\"", + (gogoproto.nullable) = false + ]; +} + +// QueryDenomsFromCreatorRequest defines the request structure for the +// DenomsFromCreator gRPC query. +message QueryDenomsFromCreatorRequest { + string creator = 1 [ (gogoproto.moretags) = "yaml:\"creator\"" ]; +} + +// QueryDenomsFromCreatorRequest defines the response structure for the +// DenomsFromCreator gRPC query. +message QueryDenomsFromCreatorResponse { + repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ]; +} diff --git a/proto/osmosis/tokenfactory/v1beta1/tx.proto b/proto/osmosis/tokenfactory/v1beta1/tx.proto new file mode 100755 index 000000000..5a95b7047 --- /dev/null +++ b/proto/osmosis/tokenfactory/v1beta1/tx.proto @@ -0,0 +1,109 @@ +syntax = "proto3"; +package osmosis.tokenfactory.v1beta1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/bank/v1beta1/bank.proto"; + +option go_package = "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types"; + +// Msg defines the tokefactory module's gRPC message service. +service Msg { + rpc CreateDenom(MsgCreateDenom) returns (MsgCreateDenomResponse); + rpc Mint(MsgMint) returns (MsgMintResponse); + rpc Burn(MsgBurn) returns (MsgBurnResponse); + rpc ChangeAdmin(MsgChangeAdmin) returns (MsgChangeAdminResponse); + rpc SetDenomMetadata(MsgSetDenomMetadata) + returns (MsgSetDenomMetadataResponse); + rpc ForceTransfer(MsgForceTransfer) returns (MsgForceTransferResponse); +} + +// MsgCreateDenom defines the message structure for the CreateDenom gRPC service +// method. It allows an account to create a new denom. It requires a sender +// address and a sub denomination. The (sender_address, sub_denomination) tuple +// must be unique and cannot be re-used. +// +// The resulting denom created is defined as +// . The resulting denom's admin is +// originally set to be the creator, but this can be changed later. The token +// denom does not indicate the current admin. +message MsgCreateDenom { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + // subdenom can be up to 44 "alphanumeric" characters long. + string subdenom = 2 [ (gogoproto.moretags) = "yaml:\"subdenom\"" ]; +} + +// MsgCreateDenomResponse is the return value of MsgCreateDenom +// It returns the full string of the newly created denom +message MsgCreateDenomResponse { + string new_token_denom = 1 + [ (gogoproto.moretags) = "yaml:\"new_token_denom\"" ]; +} + +// MsgMint is the sdk.Msg type for allowing an admin account to mint +// more of a token. For now, we only support minting to the sender account +message MsgMint { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; + string mintToAddress = 3 + [ (gogoproto.moretags) = "yaml:\"mint_to_address\"" ]; +} + +message MsgMintResponse {} + +// MsgBurn is the sdk.Msg type for allowing an admin account to burn +// a token. For now, we only support burning from the sender account. +message MsgBurn { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; + string burnFromAddress = 3 + [ (gogoproto.moretags) = "yaml:\"burn_from_address\"" ]; +} + +message MsgBurnResponse {} + +// MsgChangeAdmin is the sdk.Msg type for allowing an admin account to reassign +// adminship of a denom to a new account +message MsgChangeAdmin { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + string denom = 2 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + string new_admin = 3 [ (gogoproto.moretags) = "yaml:\"new_admin\"" ]; +} + +// MsgChangeAdminResponse defines the response structure for an executed +// MsgChangeAdmin message. +message MsgChangeAdminResponse {} + +// MsgSetDenomMetadata is the sdk.Msg type for allowing an admin account to set +// the denom's bank metadata +message MsgSetDenomMetadata { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.bank.v1beta1.Metadata metadata = 2 [ + (gogoproto.moretags) = "yaml:\"metadata\"", + (gogoproto.nullable) = false + ]; +} + +// MsgSetDenomMetadataResponse defines the response structure for an executed +// MsgSetDenomMetadata message. +message MsgSetDenomMetadataResponse {} + +message MsgForceTransfer { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; + string transferFromAddress = 3 + [ (gogoproto.moretags) = "yaml:\"transfer_from_address\"" ]; + string transferToAddress = 4 + [ (gogoproto.moretags) = "yaml:\"transfer_to_address\"" ]; +} + +message MsgForceTransferResponse {} \ No newline at end of file diff --git a/x/feeshare/genesis_test.go b/x/feeshare/genesis_test.go index 541417d22..797408d82 100644 --- a/x/feeshare/genesis_test.go +++ b/x/feeshare/genesis_test.go @@ -11,7 +11,7 @@ import ( "github.com/CosmosContracts/juno/v15/app" "github.com/CosmosContracts/juno/v15/x/feeshare" "github.com/CosmosContracts/juno/v15/x/feeshare/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" ) type GenesisTestSuite struct { diff --git a/x/feeshare/integration_test.go b/x/feeshare/integration_test.go index 814136856..778b9a4d2 100644 --- a/x/feeshare/integration_test.go +++ b/x/feeshare/integration_test.go @@ -3,13 +3,13 @@ package feeshare_test import ( "encoding/json" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + "cosmossdk.io/simapp" junoapp "github.com/CosmosContracts/juno/v15/app" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/CosmosContracts/juno/v15/x/mint/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/feeshare/keeper/keeper.go b/x/feeshare/keeper/keeper.go index 557af3995..773cdc5f3 100644 --- a/x/feeshare/keeper/keeper.go +++ b/x/feeshare/keeper/keeper.go @@ -3,11 +3,11 @@ package keeper import ( "fmt" + "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/tendermint/tendermint/libs/log" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" revtypes "github.com/CosmosContracts/juno/v15/x/feeshare/types" diff --git a/x/feeshare/keeper/keeper_test.go b/x/feeshare/keeper/keeper_test.go index 5c4743b23..054a74cd1 100644 --- a/x/feeshare/keeper/keeper_test.go +++ b/x/feeshare/keeper/keeper_test.go @@ -5,11 +5,11 @@ import ( "testing" "time" + tmrand "github.com/cometbft/cometbft/libs/rand" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - tmrand "github.com/tendermint/tendermint/libs/rand" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" diff --git a/x/feeshare/module.go b/x/feeshare/module.go index 85053054b..9aac445a7 100644 --- a/x/feeshare/module.go +++ b/x/feeshare/module.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand" + abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -16,7 +17,6 @@ import ( "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/CosmosContracts/juno/v15/x/feeshare/client/cli" "github.com/CosmosContracts/juno/v15/x/feeshare/keeper" diff --git a/x/feeshare/types/feeshare.pb.go b/x/feeshare/types/feeshare.pb.go index 3327bcc83..81a400508 100644 --- a/x/feeshare/types/feeshare.pb.go +++ b/x/feeshare/types/feeshare.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - proto "github.com/gogo/protobuf/proto" + proto "github.com/cosmos/gogoproto/proto" io "io" math "math" math_bits "math/bits" diff --git a/x/feeshare/types/genesis.pb.go b/x/feeshare/types/genesis.pb.go index ec9768848..c67c9ef91 100644 --- a/x/feeshare/types/genesis.pb.go +++ b/x/feeshare/types/genesis.pb.go @@ -7,7 +7,7 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/gogo/protobuf/proto" + proto "github.com/cosmos/gogoproto/proto" io "io" math "math" math_bits "math/bits" diff --git a/x/feeshare/types/query.pb.go b/x/feeshare/types/query.pb.go index 67983a6e1..4a925fa6e 100644 --- a/x/feeshare/types/query.pb.go +++ b/x/feeshare/types/query.pb.go @@ -8,8 +8,8 @@ import ( fmt "fmt" query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/x/feeshare/types/tx.pb.go b/x/feeshare/types/tx.pb.go index 456d0979a..eba3eeb02 100644 --- a/x/feeshare/types/tx.pb.go +++ b/x/feeshare/types/tx.pb.go @@ -7,8 +7,8 @@ import ( context "context" fmt "fmt" _ "github.com/cosmos/gogoproto/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/x/mint/client/rest/grpc_query_test.go b/x/mint/client/rest/grpc_query_test.go index 982c32214..f7c8a58fd 100644 --- a/x/mint/client/rest/grpc_query_test.go +++ b/x/mint/client/rest/grpc_query_test.go @@ -11,7 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" - "github.com/gogo/protobuf/proto" + "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/suite" minttypes "github.com/CosmosContracts/juno/v15/x/mint/types" diff --git a/x/mint/client/testutil/suite.go b/x/mint/client/testutil/suite.go index 12f3f8566..a7638c36d 100644 --- a/x/mint/client/testutil/suite.go +++ b/x/mint/client/testutil/suite.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" + tmcli "github.com/cometbft/cometbft/libs/cli" "github.com/stretchr/testify/suite" - tmcli "github.com/tendermint/tendermint/libs/cli" "github.com/CosmosContracts/juno/v15/x/mint/client/cli" minttypes "github.com/CosmosContracts/juno/v15/x/mint/types" diff --git a/x/mint/keeper/grpc_query_test.go b/x/mint/keeper/grpc_query_test.go index e2fb71c5f..8d22bf419 100644 --- a/x/mint/keeper/grpc_query_test.go +++ b/x/mint/keeper/grpc_query_test.go @@ -4,8 +4,8 @@ import ( gocontext "context" "testing" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/suite" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/CosmosContracts/juno/v15/app" "github.com/CosmosContracts/juno/v15/x/mint/types" diff --git a/x/mint/keeper/integration_test.go b/x/mint/keeper/integration_test.go index 9218885fd..36a630eb7 100644 --- a/x/mint/keeper/integration_test.go +++ b/x/mint/keeper/integration_test.go @@ -3,13 +3,13 @@ package keeper_test import ( "encoding/json" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" + dbm "github.com/cometbft/cometbft-db" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + "cosmossdk.io/simapp" junoapp "github.com/CosmosContracts/juno/v15/app" - "github.com/cosmos/cosmos-sdk/simapp" "github.com/CosmosContracts/juno/v15/x/mint/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 0fc908d91..935c5d0d1 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -1,7 +1,7 @@ package keeper import ( - "github.com/tendermint/tendermint/libs/log" + "github.com/cometbft/cometbft/libs/log" "github.com/CosmosContracts/juno/v15/x/mint/types" "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/mint/keeper/querier.go b/x/mint/keeper/querier.go index 0f1d24f23..bd4399a54 100644 --- a/x/mint/keeper/querier.go +++ b/x/mint/keeper/querier.go @@ -1,7 +1,7 @@ package keeper import ( - abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/cometbft/cometbft/abci/types" "github.com/CosmosContracts/juno/v15/x/mint/types" "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/mint/keeper/querier_test.go b/x/mint/keeper/querier_test.go index 1cd5bd7ce..6bd8d8581 100644 --- a/x/mint/keeper/querier_test.go +++ b/x/mint/keeper/querier_test.go @@ -11,7 +11,7 @@ import ( "github.com/CosmosContracts/juno/v15/x/mint/types" sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/cometbft/cometbft/abci/types" ) func TestNewQuerier(t *testing.T) { diff --git a/x/mint/module.go b/x/mint/module.go index a27df0d34..a1ede3e55 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -6,10 +6,10 @@ import ( "fmt" "math/rand" + abci "github.com/cometbft/cometbft/abci/types" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" - abci "github.com/tendermint/tendermint/abci/types" "github.com/CosmosContracts/juno/v15/x/mint/client/cli" "github.com/CosmosContracts/juno/v15/x/mint/client/rest" diff --git a/x/mint/module_test.go b/x/mint/module_test.go index 00b994a09..811dfc988 100644 --- a/x/mint/module_test.go +++ b/x/mint/module_test.go @@ -3,12 +3,12 @@ package mint_test import ( "testing" + abcitypes "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/require" - abcitypes "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "cosmossdk.io/simapp" "github.com/CosmosContracts/juno/v15/x/mint/types" - "github.com/cosmos/cosmos-sdk/simapp" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) diff --git a/x/mint/types/genesis.pb.go b/x/mint/types/genesis.pb.go index 5bf586341..d9c0f8732 100644 --- a/x/mint/types/genesis.pb.go +++ b/x/mint/types/genesis.pb.go @@ -6,7 +6,7 @@ package types import ( fmt "fmt" _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/gogo/protobuf/proto" + proto "github.com/cosmos/gogoproto/proto" io "io" math "math" math_bits "math/bits" diff --git a/x/mint/types/mint.pb.go b/x/mint/types/mint.pb.go index 730abfa9e..5f78dc8a2 100644 --- a/x/mint/types/mint.pb.go +++ b/x/mint/types/mint.pb.go @@ -7,7 +7,7 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/gogo/protobuf/proto" + proto "github.com/cosmos/gogoproto/proto" io "io" math "math" math_bits "math/bits" diff --git a/x/mint/types/query.pb.go b/x/mint/types/query.pb.go index 855eb759f..d569d9693 100644 --- a/x/mint/types/query.pb.go +++ b/x/mint/types/query.pb.go @@ -8,8 +8,8 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" - grpc1 "github.com/gogo/protobuf/grpc" - proto "github.com/gogo/protobuf/proto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" diff --git a/x/tokenfactory/README.md b/x/tokenfactory/README.md new file mode 100644 index 000000000..7d6644e45 --- /dev/null +++ b/x/tokenfactory/README.md @@ -0,0 +1,155 @@ +# Token Factory + +The tokenfactory module allows any account to create a new token with +the name `factory/{creator address}/{subdenom}`. Because tokens are +namespaced by creator address, this allows token minting to be +permissionless, due to not needing to resolve name collisions. A single +account can create multiple denoms, by providing a unique subdenom for each +created denom. Once a denom is created, the original creator is given +"admin" privileges over the asset. This allows them to: + +- Mint their denom to any account +- Burn their denom from any account +- Create a transfer of their denom between any two accounts +- Change the admin. In the future, more admin capabilities may be added. Admins + can choose to share admin privileges with other accounts using the authz + module. The `ChangeAdmin` functionality, allows changing the master admin + account, or even setting it to `""`, meaning no account has admin privileges + of the asset. + +## Messages + +### CreateDenom + +Creates a denom of `factory/{creator address}/{subdenom}` given the denom creator +address and the subdenom. Subdenoms can contain `[a-zA-Z0-9./]`. + +```go +message MsgCreateDenom { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + string subdenom = 2 [ (gogoproto.moretags) = "yaml:\"subdenom\"" ]; +} +``` + +**State Modifications:** + +- Fund community pool with the denom creation fee from the creator address, set + in `Params`. +- Set `DenomMetaData` via bank keeper. +- Set `AuthorityMetadata` for the given denom to store the admin for the created + denom `factory/{creator address}/{subdenom}`. Admin is automatically set as the + Msg sender. +- Add denom to the `CreatorPrefixStore`, where a state of denoms created per + creator is kept. + +### Mint + +Minting of a specific denom is only allowed for the current admin. +Note, the current admin is defaulted to the creator of the denom. + +```go +message MsgMint { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; +} +``` + +**State Modifications:** + +- Safety check the following + - Check that the denom minting is created via `tokenfactory` module + - Check that the sender of the message is the admin of the denom +- Mint designated amount of tokens for the denom via `bank` module + +### Burn + +Burning of a specific denom is only allowed for the current admin. +Note, the current admin is defaulted to the creator of the denom. + +```go +message MsgBurn { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.base.v1beta1.Coin amount = 2 [ + (gogoproto.moretags) = "yaml:\"amount\"", + (gogoproto.nullable) = false + ]; +} +``` + +**State Modifications:** + +- Saftey check the following + - Check that the denom minting is created via `tokenfactory` module + - Check that the sender of the message is the admin of the denom +- Burn designated amount of tokens for the denom via `bank` module + +### ChangeAdmin + +Change the admin of a denom. Note, this is only allowed to be called by the current admin of the denom. + +```go +message MsgChangeAdmin { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + string denom = 2 [ (gogoproto.moretags) = "yaml:\"denom\"" ]; + string newAdmin = 3 [ (gogoproto.moretags) = "yaml:\"new_admin\"" ]; +} +``` + +### SetDenomMetadata + +Setting of metadata for a specific denom is only allowed for the admin of the denom. +It allows the overwriting of the denom metadata in the bank module. + +```go +message MsgChangeAdmin { + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + cosmos.bank.v1beta1.Metadata metadata = 2 [ (gogoproto.moretags) = "yaml:\"metadata\"", (gogoproto.nullable) = false ]; +} +``` + +**State Modifications:** + +- Check that sender of the message is the admin of denom +- Modify `AuthorityMetadata` state entry to change the admin of the denom + +## Expectations from the chain + +The chain's bech32 prefix for addresses can be at most 16 characters long. + +This comes from denoms having a 128 byte maximum length, enforced from the SDK, +and us setting longest_subdenom to be 44 bytes. + +A token factory token's denom is: `factory/{creator address}/{subdenom}` + +Splitting up into sub-components, this has: + +- `len(factory) = 7` +- `2 * len("/") = 2` +- `len(longest_subdenom)` +- `len(creator_address) = len(bech32(longest_addr_length, chain_addr_prefix))`. + +Longest addr length at the moment is `32 bytes`. Due to SDK error correction +settings, this means `len(bech32(32, chain_addr_prefix)) = len(chain_addr_prefix) + 1 + 58`. +Adding this all, we have a total length constraint of `128 = 7 + 2 + len(longest_subdenom) + len(longest_chain_addr_prefix) + 1 + 58`. +Therefore `len(longest_subdenom) + len(longest_chain_addr_prefix) = 128 - (7 + 2 + 1 + 58) = 60`. + +The choice between how we standardized the split these 60 bytes between maxes +from longest_subdenom and longest_chain_addr_prefix is somewhat arbitrary. +Considerations going into this: + +- Per [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32) + the technically longest HRP for a 32 byte address ('data field') is 31 bytes. + (Comes from encode(data) = 59 bytes, and max length = 90 bytes) +- subdenom should be at least 32 bytes so hashes can go into it +- longer subdenoms are very helpful for creating human readable denoms +- chain addresses should prefer being smaller. The longest HRP in cosmos to date is 11 bytes. (`persistence`) + +For explicitness, its currently set to `len(longest_subdenom) = 44` and `len(longest_chain_addr_prefix) = 16`. + +Please note, if the SDK increases the maximum length of a denom from 128 bytes, +these caps should increase. + +So please don't make code rely on these max lengths for parsing. diff --git a/x/tokenfactory/bindings/custom_msg_test.go b/x/tokenfactory/bindings/custom_msg_test.go new file mode 100644 index 000000000..ba411ce1f --- /dev/null +++ b/x/tokenfactory/bindings/custom_msg_test.go @@ -0,0 +1,331 @@ +package bindings_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/app" + bindings "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings/types" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func TestCreateDenomMsg(t *testing.T) { + creator := RandomAccountAddress() + osmosis, ctx := SetupCustomApp(t, creator) + + lucky := RandomAccountAddress() + reflect := instantiateReflectContract(t, ctx, osmosis, lucky) + require.NotEmpty(t, reflect) + + // Fund reflect contract with 100 base denom creation fees + reflectAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, osmosis, reflect, reflectAmount) + + msg := bindings.TokenMsg{CreateDenom: &bindings.CreateDenom{ + Subdenom: "SUN", + }} + err := executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + // query the denom and see if it matches + query := bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "SUN", + }, + } + resp := bindings.FullDenomResponse{} + queryCustom(t, ctx, osmosis, reflect, query, &resp) + + require.Equal(t, resp.Denom, fmt.Sprintf("factory/%s/SUN", reflect.String())) +} + +func TestMintMsg(t *testing.T) { + creator := RandomAccountAddress() + osmosis, ctx := SetupCustomApp(t, creator) + + lucky := RandomAccountAddress() + reflect := instantiateReflectContract(t, ctx, osmosis, lucky) + require.NotEmpty(t, reflect) + + // Fund reflect contract with 100 base denom creation fees + reflectAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, osmosis, reflect, reflectAmount) + + // lucky was broke + balances := osmosis.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + // Create denom for minting + msg := bindings.TokenMsg{CreateDenom: &bindings.CreateDenom{ + Subdenom: "SUN", + }} + err := executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + sunDenom := fmt.Sprintf("factory/%s/%s", reflect.String(), msg.CreateDenom.Subdenom) + + amount, ok := sdk.NewIntFromString("808010808") + require.True(t, ok) + msg = bindings.TokenMsg{MintTokens: &bindings.MintTokens{ + Denom: sunDenom, + Amount: amount, + MintToAddress: lucky.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + balances = osmosis.BankKeeper.GetAllBalances(ctx, lucky) + require.Len(t, balances, 1) + coin := balances[0] + require.Equal(t, amount, coin.Amount) + require.Contains(t, coin.Denom, "factory/") + + // query the denom and see if it matches + query := bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "SUN", + }, + } + resp := bindings.FullDenomResponse{} + queryCustom(t, ctx, osmosis, reflect, query, &resp) + + require.Equal(t, resp.Denom, coin.Denom) + + // mint the same denom again + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + balances = osmosis.BankKeeper.GetAllBalances(ctx, lucky) + require.Len(t, balances, 1) + coin = balances[0] + require.Equal(t, amount.MulRaw(2), coin.Amount) + require.Contains(t, coin.Denom, "factory/") + + // query the denom and see if it matches + query = bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "SUN", + }, + } + resp = bindings.FullDenomResponse{} + queryCustom(t, ctx, osmosis, reflect, query, &resp) + + require.Equal(t, resp.Denom, coin.Denom) + + // now mint another amount / denom + // create it first + msg = bindings.TokenMsg{CreateDenom: &bindings.CreateDenom{ + Subdenom: "MOON", + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + moonDenom := fmt.Sprintf("factory/%s/%s", reflect.String(), msg.CreateDenom.Subdenom) + + amount = amount.SubRaw(1) + msg = bindings.TokenMsg{MintTokens: &bindings.MintTokens{ + Denom: moonDenom, + Amount: amount, + MintToAddress: lucky.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + balances = osmosis.BankKeeper.GetAllBalances(ctx, lucky) + require.Len(t, balances, 2) + coin = balances[0] + require.Equal(t, amount, coin.Amount) + require.Contains(t, coin.Denom, "factory/") + + // query the denom and see if it matches + query = bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "MOON", + }, + } + resp = bindings.FullDenomResponse{} + queryCustom(t, ctx, osmosis, reflect, query, &resp) + + require.Equal(t, resp.Denom, coin.Denom) + + // and check the first denom is unchanged + coin = balances[1] + require.Equal(t, amount.AddRaw(1).MulRaw(2), coin.Amount) + require.Contains(t, coin.Denom, "factory/") + + // query the denom and see if it matches + query = bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "SUN", + }, + } + resp = bindings.FullDenomResponse{} + queryCustom(t, ctx, osmosis, reflect, query, &resp) + + require.Equal(t, resp.Denom, coin.Denom) +} + +func TestForceTransfer(t *testing.T) { + creator := RandomAccountAddress() + osmosis, ctx := SetupCustomApp(t, creator) + + lucky := RandomAccountAddress() + rcpt := RandomAccountAddress() + reflect := instantiateReflectContract(t, ctx, osmosis, lucky) + require.NotEmpty(t, reflect) + + // Fund reflect contract with 100 base denom creation fees + reflectAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, osmosis, reflect, reflectAmount) + + // lucky was broke + balances := osmosis.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + // Create denom for minting + msg := bindings.TokenMsg{CreateDenom: &bindings.CreateDenom{ + Subdenom: "SUN", + }} + err := executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + sunDenom := fmt.Sprintf("factory/%s/%s", reflect.String(), msg.CreateDenom.Subdenom) + + amount, ok := sdk.NewIntFromString("808010808") + require.True(t, ok) + + // Mint new tokens to lucky + msg = bindings.TokenMsg{MintTokens: &bindings.MintTokens{ + Denom: sunDenom, + Amount: amount, + MintToAddress: lucky.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + // Force move 100 tokens from lucky to rcpt + msg = bindings.TokenMsg{ForceTransfer: &bindings.ForceTransfer{ + Denom: sunDenom, + Amount: sdk.NewInt(100), + FromAddress: lucky.String(), + ToAddress: rcpt.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + // check the balance of rcpt + balances = osmosis.BankKeeper.GetAllBalances(ctx, rcpt) + require.Len(t, balances, 1) + coin := balances[0] + require.Equal(t, sdk.NewInt(100), coin.Amount) +} + +func TestBurnMsg(t *testing.T) { + creator := RandomAccountAddress() + osmosis, ctx := SetupCustomApp(t, creator) + + lucky := RandomAccountAddress() + reflect := instantiateReflectContract(t, ctx, osmosis, lucky) + require.NotEmpty(t, reflect) + + // Fund reflect contract with 100 base denom creation fees + reflectAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, osmosis, reflect, reflectAmount) + + // lucky was broke + balances := osmosis.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + // Create denom for minting + msg := bindings.TokenMsg{CreateDenom: &bindings.CreateDenom{ + Subdenom: "SUN", + }} + err := executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + sunDenom := fmt.Sprintf("factory/%s/%s", reflect.String(), msg.CreateDenom.Subdenom) + + amount, ok := sdk.NewIntFromString("808010809") + require.True(t, ok) + + msg = bindings.TokenMsg{MintTokens: &bindings.MintTokens{ + Denom: sunDenom, + Amount: amount, + MintToAddress: lucky.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + // can burn from different address with burnFrom + amt, ok := sdk.NewIntFromString("1") + require.True(t, ok) + msg = bindings.TokenMsg{BurnTokens: &bindings.BurnTokens{ + Denom: sunDenom, + Amount: amt, + BurnFromAddress: lucky.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) + + // lucky needs to send balance to reflect contract to burn it + luckyBalance := osmosis.BankKeeper.GetAllBalances(ctx, lucky) + err = osmosis.BankKeeper.SendCoins(ctx, lucky, reflect, luckyBalance) + require.NoError(t, err) + + msg = bindings.TokenMsg{BurnTokens: &bindings.BurnTokens{ + Denom: sunDenom, + Amount: amount.Abs().Sub(sdk.NewInt(1)), + BurnFromAddress: reflect.String(), + }} + err = executeCustom(t, ctx, osmosis, reflect, lucky, msg, sdk.Coin{}) + require.NoError(t, err) +} + +type ReflectExec struct { + ReflectMsg *ReflectMsgs `json:"reflect_msg,omitempty"` + ReflectSubMsg *ReflectSubMsgs `json:"reflect_sub_msg,omitempty"` +} + +type ReflectMsgs struct { + Msgs []wasmvmtypes.CosmosMsg `json:"msgs"` +} + +type ReflectSubMsgs struct { + Msgs []wasmvmtypes.SubMsg `json:"msgs"` +} + +func executeCustom(t *testing.T, ctx sdk.Context, osmosis *app.TokenApp, contract sdk.AccAddress, sender sdk.AccAddress, msg bindings.TokenMsg, funds sdk.Coin) error { + wrapped := bindings.TokenFactoryMsg{ + Token: &msg, + } + customBz, err := json.Marshal(wrapped) + require.NoError(t, err) + + reflectMsg := ReflectExec{ + ReflectMsg: &ReflectMsgs{ + Msgs: []wasmvmtypes.CosmosMsg{{ + Custom: customBz, + }}, + }, + } + reflectBz, err := json.Marshal(reflectMsg) + require.NoError(t, err) + + // no funds sent if amount is 0 + var coins sdk.Coins + if !funds.Amount.IsNil() { + coins = sdk.Coins{funds} + } + + contractKeeper := keeper.NewDefaultPermissionKeeper(osmosis.WasmKeeper) + _, err = contractKeeper.Execute(ctx, contract, sender, reflectBz, coins) + return err +} diff --git a/x/tokenfactory/bindings/custom_query_test.go b/x/tokenfactory/bindings/custom_query_test.go new file mode 100644 index 000000000..278c60352 --- /dev/null +++ b/x/tokenfactory/bindings/custom_query_test.go @@ -0,0 +1,74 @@ +package bindings_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/app" + bindings "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings/types" +) + +func TestQueryFullDenom(t *testing.T) { + actor := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, actor) + + reflect := instantiateReflectContract(t, ctx, tokenz, actor) + require.NotEmpty(t, reflect) + + // query full denom + query := bindings.TokenQuery{ + FullDenom: &bindings.FullDenom{ + CreatorAddr: reflect.String(), + Subdenom: "ustart", + }, + } + resp := bindings.FullDenomResponse{} + queryCustom(t, ctx, tokenz, reflect, query, &resp) + + expected := fmt.Sprintf("factory/%s/ustart", reflect.String()) + require.EqualValues(t, expected, resp.Denom) +} + +type ReflectQuery struct { + Chain *ChainRequest `json:"chain,omitempty"` +} + +type ChainRequest struct { + Request wasmvmtypes.QueryRequest `json:"request"` +} + +type ChainResponse struct { + Data []byte `json:"data"` +} + +func queryCustom(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, contract sdk.AccAddress, request bindings.TokenQuery, response interface{}) { + wrapped := bindings.TokenFactoryQuery{ + Token: &request, + } + msgBz, err := json.Marshal(wrapped) + require.NoError(t, err) + fmt.Println(string(msgBz)) + + query := ReflectQuery{ + Chain: &ChainRequest{ + Request: wasmvmtypes.QueryRequest{Custom: msgBz}, + }, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + fmt.Println(string(queryBz)) + + resBz, err := tokenz.WasmKeeper.QuerySmart(ctx, contract, queryBz) + require.NoError(t, err) + var resp ChainResponse + err = json.Unmarshal(resBz, &resp) + require.NoError(t, err) + err = json.Unmarshal(resp.Data, response) + require.NoError(t, err) +} diff --git a/x/tokenfactory/bindings/helpers_test.go b/x/tokenfactory/bindings/helpers_test.go new file mode 100644 index 000000000..41d14131a --- /dev/null +++ b/x/tokenfactory/bindings/helpers_test.go @@ -0,0 +1,92 @@ +package bindings_test + +import ( + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/CosmosTokenFactory/token-factory/app" +) + +func CreateTestInput() (*app.TokenApp, sdk.Context) { + osmosis := app.Setup(false) + ctx := osmosis.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "osmosis-1", Time: time.Now().UTC()}) + return osmosis, ctx +} + +func FundAccount(t *testing.T, ctx sdk.Context, osmosis *app.TokenApp, acct sdk.AccAddress) { + err := simapp.FundAccount(osmosis.BankKeeper, ctx, acct, sdk.NewCoins( + sdk.NewCoin("uosmo", sdk.NewInt(10000000000)), + )) + require.NoError(t, err) +} + +// we need to make this deterministic (same every test run), as content might affect gas costs +func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) { + key := ed25519.GenPrivKey() + pub := key.PubKey() + addr := sdk.AccAddress(pub.Address()) + return key, pub, addr +} + +func RandomAccountAddress() sdk.AccAddress { + _, _, addr := keyPubAddr() + return addr +} + +func RandomBech32AccountAddress() string { + return RandomAccountAddress().String() +} + +func storeReflectCode(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, addr sdk.AccAddress) uint64 { + wasmCode, err := os.ReadFile("./testdata/token_reflect.wasm") + require.NoError(t, err) + + contractKeeper := keeper.NewDefaultPermissionKeeper(tokenz.WasmKeeper) + codeID, _, err := contractKeeper.Create(ctx, addr, wasmCode, nil) + require.NoError(t, err) + + return codeID +} + +func instantiateReflectContract(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, funder sdk.AccAddress) sdk.AccAddress { + initMsgBz := []byte("{}") + contractKeeper := keeper.NewDefaultPermissionKeeper(tokenz.WasmKeeper) + codeID := uint64(1) + addr, _, err := contractKeeper.Instantiate(ctx, codeID, funder, funder, initMsgBz, "demo contract", nil) + require.NoError(t, err) + + return addr +} + +func fundAccount(t *testing.T, ctx sdk.Context, tokenz *app.TokenApp, addr sdk.AccAddress, coins sdk.Coins) { + err := simapp.FundAccount( + tokenz.BankKeeper, + ctx, + addr, + coins, + ) + require.NoError(t, err) +} + +func SetupCustomApp(t *testing.T, addr sdk.AccAddress) (*app.TokenApp, sdk.Context) { + tokenz, ctx := CreateTestInput() + wasmKeeper := tokenz.WasmKeeper + + storeReflectCode(t, ctx, tokenz, addr) + + cInfo := wasmKeeper.GetCodeInfo(ctx, 1) + require.NotNil(t, cInfo) + + return tokenz, ctx +} diff --git a/x/tokenfactory/bindings/message_plugin.go b/x/tokenfactory/bindings/message_plugin.go new file mode 100644 index 000000000..b6acde281 --- /dev/null +++ b/x/tokenfactory/bindings/message_plugin.go @@ -0,0 +1,370 @@ +package bindings + +import ( + "encoding/json" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + bindingstypes "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings/types" + tokenfactorykeeper "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/keeper" + tokenfactorytypes "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +// CustomMessageDecorator returns decorator for custom CosmWasm bindings messages +func CustomMessageDecorator(bank *bankkeeper.BaseKeeper, tokenFactory *tokenfactorykeeper.Keeper) func(wasmkeeper.Messenger) wasmkeeper.Messenger { + return func(old wasmkeeper.Messenger) wasmkeeper.Messenger { + return &CustomMessenger{ + wrapped: old, + bank: bank, + tokenFactory: tokenFactory, + } + } +} + +type CustomMessenger struct { + wrapped wasmkeeper.Messenger + bank *bankkeeper.BaseKeeper + tokenFactory *tokenfactorykeeper.Keeper +} + +var _ wasmkeeper.Messenger = (*CustomMessenger)(nil) + +// DispatchMsg executes on the contractMsg. +func (m *CustomMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { + if msg.Custom != nil { + // only handle the happy path where this is really creating / minting / swapping ... + // leave everything else for the wrapped version + var contractMsg bindingstypes.TokenFactoryMsg + if err := json.Unmarshal(msg.Custom, &contractMsg); err != nil { + return nil, nil, sdkerrors.Wrap(err, "token factory msg") + } + if contractMsg.Token == nil { + return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "nil token field") + } + tokenMsg := contractMsg.Token + + if tokenMsg.CreateDenom != nil { + return m.createDenom(ctx, contractAddr, tokenMsg.CreateDenom) + } + if tokenMsg.MintTokens != nil { + return m.mintTokens(ctx, contractAddr, tokenMsg.MintTokens) + } + if tokenMsg.ChangeAdmin != nil { + return m.changeAdmin(ctx, contractAddr, tokenMsg.ChangeAdmin) + } + if tokenMsg.BurnTokens != nil { + return m.burnTokens(ctx, contractAddr, tokenMsg.BurnTokens) + } + if tokenMsg.SetMetadata != nil { + return m.setMetadata(ctx, contractAddr, tokenMsg.SetMetadata) + } + if tokenMsg.ForceTransfer != nil { + return m.forceTransfer(ctx, contractAddr, tokenMsg.ForceTransfer) + } + } + return m.wrapped.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) +} + +// createDenom creates a new token denom +func (m *CustomMessenger) createDenom(ctx sdk.Context, contractAddr sdk.AccAddress, createDenom *bindingstypes.CreateDenom) ([]sdk.Event, [][]byte, error) { + bz, err := PerformCreateDenom(m.tokenFactory, m.bank, ctx, contractAddr, createDenom) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform create denom") + } + // TODO: double check how this is all encoded to the contract + return nil, [][]byte{bz}, nil +} + +// PerformCreateDenom is used with createDenom to create a token denom; validates the msgCreateDenom. +func PerformCreateDenom(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, createDenom *bindingstypes.CreateDenom) ([]byte, error) { + if createDenom == nil { + return nil, wasmvmtypes.InvalidRequest{Err: "create denom null create denom"} + } + + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + + msgCreateDenom := tokenfactorytypes.NewMsgCreateDenom(contractAddr.String(), createDenom.Subdenom) + + if err := msgCreateDenom.ValidateBasic(); err != nil { + return nil, sdkerrors.Wrap(err, "failed validating MsgCreateDenom") + } + + // Create denom + resp, err := msgServer.CreateDenom( + sdk.WrapSDKContext(ctx), + msgCreateDenom, + ) + if err != nil { + return nil, sdkerrors.Wrap(err, "creating denom") + } + + if createDenom.Metadata != nil { + newDenom := resp.NewTokenDenom + err := PerformSetMetadata(f, b, ctx, contractAddr, newDenom, *createDenom.Metadata) + if err != nil { + return nil, sdkerrors.Wrap(err, "setting metadata") + } + } + + return resp.Marshal() +} + +// mintTokens mints tokens of a specified denom to an address. +func (m *CustomMessenger) mintTokens(ctx sdk.Context, contractAddr sdk.AccAddress, mint *bindingstypes.MintTokens) ([]sdk.Event, [][]byte, error) { + err := PerformMint(m.tokenFactory, m.bank, ctx, contractAddr, mint) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform mint") + } + return nil, nil, nil +} + +// PerformMint used with mintTokens to validate the mint message and mint through token factory. +func PerformMint(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, mint *bindingstypes.MintTokens) error { + if mint == nil { + return wasmvmtypes.InvalidRequest{Err: "mint token null mint"} + } + rcpt, err := parseAddress(mint.MintToAddress) + if err != nil { + return err + } + + coin := sdk.Coin{Denom: mint.Denom, Amount: mint.Amount} + sdkMsg := tokenfactorytypes.NewMsgMint(contractAddr.String(), coin) + + if err = sdkMsg.ValidateBasic(); err != nil { + return err + } + + // Mint through token factory / message server + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err = msgServer.Mint(sdk.WrapSDKContext(ctx), sdkMsg) + if err != nil { + return sdkerrors.Wrap(err, "minting coins from message") + } + + if b.BlockedAddr(rcpt) { + return sdkerrors.Wrapf(err, "minting coins to blocked address %s", rcpt.String()) + } + + err = b.SendCoins(ctx, contractAddr, rcpt, sdk.NewCoins(coin)) + if err != nil { + return sdkerrors.Wrap(err, "sending newly minted coins from message") + } + return nil +} + +// changeAdmin changes the admin. +func (m *CustomMessenger) changeAdmin(ctx sdk.Context, contractAddr sdk.AccAddress, changeAdmin *bindingstypes.ChangeAdmin) ([]sdk.Event, [][]byte, error) { + err := ChangeAdmin(m.tokenFactory, ctx, contractAddr, changeAdmin) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "failed to change admin") + } + return nil, nil, nil +} + +// ChangeAdmin is used with changeAdmin to validate changeAdmin messages and to dispatch. +func ChangeAdmin(f *tokenfactorykeeper.Keeper, ctx sdk.Context, contractAddr sdk.AccAddress, changeAdmin *bindingstypes.ChangeAdmin) error { + if changeAdmin == nil { + return wasmvmtypes.InvalidRequest{Err: "changeAdmin is nil"} + } + newAdminAddr, err := parseAddress(changeAdmin.NewAdminAddress) + if err != nil { + return err + } + + changeAdminMsg := tokenfactorytypes.NewMsgChangeAdmin(contractAddr.String(), changeAdmin.Denom, newAdminAddr.String()) + if err := changeAdminMsg.ValidateBasic(); err != nil { + return err + } + + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err = msgServer.ChangeAdmin(sdk.WrapSDKContext(ctx), changeAdminMsg) + if err != nil { + return sdkerrors.Wrap(err, "failed changing admin from message") + } + return nil +} + +// burnTokens burns tokens. +func (m *CustomMessenger) burnTokens(ctx sdk.Context, contractAddr sdk.AccAddress, burn *bindingstypes.BurnTokens) ([]sdk.Event, [][]byte, error) { + err := PerformBurn(m.tokenFactory, ctx, contractAddr, burn) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform burn") + } + return nil, nil, nil +} + +// PerformBurn performs token burning after validating tokenBurn message. +func PerformBurn(f *tokenfactorykeeper.Keeper, ctx sdk.Context, contractAddr sdk.AccAddress, burn *bindingstypes.BurnTokens) error { + if burn == nil { + return wasmvmtypes.InvalidRequest{Err: "burn token null mint"} + } + + coin := sdk.Coin{Denom: burn.Denom, Amount: burn.Amount} + sdkMsg := tokenfactorytypes.NewMsgBurn(contractAddr.String(), coin) + if burn.BurnFromAddress != "" { + sdkMsg = tokenfactorytypes.NewMsgBurnFrom(contractAddr.String(), coin, burn.BurnFromAddress) + } + + if err := sdkMsg.ValidateBasic(); err != nil { + return err + } + + // Burn through token factory / message server + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err := msgServer.Burn(sdk.WrapSDKContext(ctx), sdkMsg) + if err != nil { + return sdkerrors.Wrap(err, "burning coins from message") + } + return nil +} + +// forceTransfer moves tokens. +func (m *CustomMessenger) forceTransfer(ctx sdk.Context, contractAddr sdk.AccAddress, forcetransfer *bindingstypes.ForceTransfer) ([]sdk.Event, [][]byte, error) { + err := PerformForceTransfer(m.tokenFactory, ctx, contractAddr, forcetransfer) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform force transfer") + } + return nil, nil, nil +} + +// PerformForceTransfer performs token moving after validating tokenForceTransfer message. +func PerformForceTransfer(f *tokenfactorykeeper.Keeper, ctx sdk.Context, contractAddr sdk.AccAddress, forcetransfer *bindingstypes.ForceTransfer) error { + if forcetransfer == nil { + return wasmvmtypes.InvalidRequest{Err: "force transfer null"} + } + + _, err := parseAddress(forcetransfer.FromAddress) + if err != nil { + return err + } + + _, err = parseAddress(forcetransfer.ToAddress) + if err != nil { + return err + } + + coin := sdk.Coin{Denom: forcetransfer.Denom, Amount: forcetransfer.Amount} + sdkMsg := tokenfactorytypes.NewMsgForceTransfer(contractAddr.String(), coin, forcetransfer.FromAddress, forcetransfer.ToAddress) + + if err := sdkMsg.ValidateBasic(); err != nil { + return err + } + + // Transfer through token factory / message server + msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) + _, err = msgServer.ForceTransfer(sdk.WrapSDKContext(ctx), sdkMsg) + if err != nil { + return sdkerrors.Wrap(err, "force transferring from message") + } + return nil +} + +// createDenom creates a new token denom +func (m *CustomMessenger) setMetadata(ctx sdk.Context, contractAddr sdk.AccAddress, setMetadata *bindingstypes.SetMetadata) ([]sdk.Event, [][]byte, error) { + err := PerformSetMetadata(m.tokenFactory, m.bank, ctx, contractAddr, setMetadata.Denom, setMetadata.Metadata) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "perform create denom") + } + return nil, nil, nil +} + +// PerformSetMetadata is used with setMetadata to add new metadata +// It also is called inside CreateDenom if optional metadata field is set +func PerformSetMetadata(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, denom string, metadata bindingstypes.Metadata) error { + // ensure contract address is admin of denom + auth, err := f.GetAuthorityMetadata(ctx, denom) + if err != nil { + return err + } + if auth.Admin != contractAddr.String() { + return wasmvmtypes.InvalidRequest{Err: "only admin can set metadata"} + } + + // ensure we are setting proper denom metadata (bank uses Base field, fill it if missing) + if metadata.Base == "" { + metadata.Base = denom + } else if metadata.Base != denom { + // this is the key that we set + return wasmvmtypes.InvalidRequest{Err: "Base must be the same as denom"} + } + + // Create and validate the metadata + bankMetadata := WasmMetadataToSdk(metadata) + if err := bankMetadata.Validate(); err != nil { + return err + } + + b.SetDenomMetaData(ctx, bankMetadata) + return nil +} + +// GetFullDenom is a function, not method, so the message_plugin can use it +func GetFullDenom(contract string, subDenom string) (string, error) { + // Address validation + if _, err := parseAddress(contract); err != nil { + return "", err + } + fullDenom, err := tokenfactorytypes.GetTokenDenom(contract, subDenom) + if err != nil { + return "", sdkerrors.Wrap(err, "validate sub-denom") + } + + return fullDenom, nil +} + +// parseAddress parses address from bech32 string and verifies its format. +func parseAddress(addr string) (sdk.AccAddress, error) { + parsed, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, sdkerrors.Wrap(err, "address from bech32") + } + err = sdk.VerifyAddressFormat(parsed) + if err != nil { + return nil, sdkerrors.Wrap(err, "verify address format") + } + return parsed, nil +} + +func WasmMetadataToSdk(metadata bindingstypes.Metadata) banktypes.Metadata { + denoms := []*banktypes.DenomUnit{} + for _, unit := range metadata.DenomUnits { + denoms = append(denoms, &banktypes.DenomUnit{ + Denom: unit.Denom, + Exponent: unit.Exponent, + Aliases: unit.Aliases, + }) + } + return banktypes.Metadata{ + Description: metadata.Description, + Display: metadata.Display, + Base: metadata.Base, + Name: metadata.Name, + Symbol: metadata.Symbol, + DenomUnits: denoms, + } +} + +func SdkMetadataToWasm(metadata banktypes.Metadata) *bindingstypes.Metadata { + denoms := []bindingstypes.DenomUnit{} + for _, unit := range metadata.DenomUnits { + denoms = append(denoms, bindingstypes.DenomUnit{ + Denom: unit.Denom, + Exponent: unit.Exponent, + Aliases: unit.Aliases, + }) + } + return &bindingstypes.Metadata{ + Description: metadata.Description, + Display: metadata.Display, + Base: metadata.Base, + Name: metadata.Name, + Symbol: metadata.Symbol, + DenomUnits: denoms, + } +} diff --git a/x/tokenfactory/bindings/queries.go b/x/tokenfactory/bindings/queries.go new file mode 100644 index 000000000..b648b6468 --- /dev/null +++ b/x/tokenfactory/bindings/queries.go @@ -0,0 +1,57 @@ +package bindings + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + bindingstypes "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings/types" + tokenfactorykeeper "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/keeper" +) + +type QueryPlugin struct { + bankKeeper *bankkeeper.BaseKeeper + tokenFactoryKeeper *tokenfactorykeeper.Keeper +} + +// NewQueryPlugin returns a reference to a new QueryPlugin. +func NewQueryPlugin(b *bankkeeper.BaseKeeper, tfk *tokenfactorykeeper.Keeper) *QueryPlugin { + return &QueryPlugin{ + bankKeeper: b, + tokenFactoryKeeper: tfk, + } +} + +// GetDenomAdmin is a query to get denom admin. +func (qp QueryPlugin) GetDenomAdmin(ctx sdk.Context, denom string) (*bindingstypes.AdminResponse, error) { + metadata, err := qp.tokenFactoryKeeper.GetAuthorityMetadata(ctx, denom) + if err != nil { + return nil, fmt.Errorf("failed to get admin for denom: %s", denom) + } + return &bindingstypes.AdminResponse{Admin: metadata.Admin}, nil +} + +func (qp QueryPlugin) GetDenomsByCreator(ctx sdk.Context, creator string) (*bindingstypes.DenomsByCreatorResponse, error) { + // TODO: validate creator address + denoms := qp.tokenFactoryKeeper.GetDenomsFromCreator(ctx, creator) + return &bindingstypes.DenomsByCreatorResponse{Denoms: denoms}, nil +} + +func (qp QueryPlugin) GetMetadata(ctx sdk.Context, denom string) (*bindingstypes.MetadataResponse, error) { + metadata, found := qp.bankKeeper.GetDenomMetaData(ctx, denom) + var parsed *bindingstypes.Metadata + if found { + parsed = SdkMetadataToWasm(metadata) + } + return &bindingstypes.MetadataResponse{Metadata: parsed}, nil +} + +func (qp QueryPlugin) GetParams(ctx sdk.Context) (*bindingstypes.ParamsResponse, error) { + params := qp.tokenFactoryKeeper.GetParams(ctx) + return &bindingstypes.ParamsResponse{ + Params: bindingstypes.Params{ + DenomCreationFee: ConvertSdkCoinsToWasmCoins(params.DenomCreationFee), + }, + }, nil +} diff --git a/x/tokenfactory/bindings/query_plugin.go b/x/tokenfactory/bindings/query_plugin.go new file mode 100644 index 000000000..cbef51ac7 --- /dev/null +++ b/x/tokenfactory/bindings/query_plugin.go @@ -0,0 +1,122 @@ +package bindings + +import ( + "encoding/json" + "fmt" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + bindingstypes "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings/types" +) + +// 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 bindingstypes.TokenFactoryQuery + if err := json.Unmarshal(request, &contractQuery); err != nil { + return nil, sdkerrors.Wrap(err, "osmosis query") + } + if contractQuery.Token == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "nil token field") + } + tokenQuery := contractQuery.Token + + switch { + case tokenQuery.FullDenom != nil: + creator := tokenQuery.FullDenom.CreatorAddr + subdenom := tokenQuery.FullDenom.Subdenom + + fullDenom, err := GetFullDenom(creator, subdenom) + if err != nil { + return nil, sdkerrors.Wrap(err, "osmo full denom query") + } + + res := bindingstypes.FullDenomResponse{ + Denom: fullDenom, + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, sdkerrors.Wrap(err, "failed to marshal FullDenomResponse") + } + + return bz, nil + + case tokenQuery.Admin != nil: + res, err := qp.GetDenomAdmin(ctx, tokenQuery.Admin.Denom) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal AdminResponse: %w", err) + } + + return bz, nil + + case tokenQuery.Metadata != nil: + res, err := qp.GetMetadata(ctx, tokenQuery.Metadata.Denom) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal MetadataResponse: %w", err) + } + + return bz, nil + + case tokenQuery.DenomsByCreator != nil: + res, err := qp.GetDenomsByCreator(ctx, tokenQuery.DenomsByCreator.Creator) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal DenomsByCreatorResponse: %w", err) + } + + return bz, nil + + case tokenQuery.Params != nil: + res, err := qp.GetParams(ctx) + if err != nil { + return nil, err + } + + bz, err := json.Marshal(res) + if err != nil { + return nil, fmt.Errorf("failed to JSON marshal ParamsResponse: %w", err) + } + + return bz, nil + + default: + return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown token query variant"} + } + } +} + +// 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: tokenfactory tokens have 18 decimal places, so 10^22 is common, no longer in u64 range + Amount: coin.Amount.String(), + } +} diff --git a/x/tokenfactory/bindings/testdata/download_releases.sh b/x/tokenfactory/bindings/testdata/download_releases.sh new file mode 100755 index 000000000..5413f3bf7 --- /dev/null +++ b/x/tokenfactory/bindings/testdata/download_releases.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -o errexit -o nounset -o pipefail +command -v shellcheck > /dev/null && shellcheck "$0" + +if [ $# -ne 1 ]; then + echo "Usage: ./download_releases.sh RELEASE_TAG" + exit 1 +fi + +tag="$1" + +# From CosmosContracts/token-bindings + +url="https://github.com/CosmWasm/token-bindings/releases/download/$tag/token_reflect.wasm" +echo "Downloading $url ..." +wget -O "token_reflect.wasm" "$url" + +rm -f version.txt +echo "$tag" >version.txt \ No newline at end of file diff --git a/x/tokenfactory/bindings/testdata/token_reflect.wasm b/x/tokenfactory/bindings/testdata/token_reflect.wasm new file mode 100755 index 000000000..c27ec80a0 Binary files /dev/null and b/x/tokenfactory/bindings/testdata/token_reflect.wasm differ diff --git a/x/tokenfactory/bindings/testdata/version.txt b/x/tokenfactory/bindings/testdata/version.txt new file mode 100644 index 000000000..f979adec6 --- /dev/null +++ b/x/tokenfactory/bindings/testdata/version.txt @@ -0,0 +1 @@ +v0.9.0 diff --git a/x/tokenfactory/bindings/types/msg.go b/x/tokenfactory/bindings/types/msg.go new file mode 100644 index 000000000..4e2735472 --- /dev/null +++ b/x/tokenfactory/bindings/types/msg.go @@ -0,0 +1,68 @@ +package types + +import sdk "github.com/cosmos/cosmos-sdk/types" + +type TokenFactoryMsg struct { + Token *TokenMsg `json:"token,omitempty"` +} + +type TokenMsg struct { + /// Contracts can create denoms, namespaced under the contract's address. + /// A contract may create any number of independent sub-denoms. + CreateDenom *CreateDenom `json:"create_denom,omitempty"` + /// Contracts can change the admin of a denom that they are the admin of. + ChangeAdmin *ChangeAdmin `json:"change_admin,omitempty"` + /// Contracts can mint native tokens for an existing factory denom + /// that they are the admin of. + MintTokens *MintTokens `json:"mint_tokens,omitempty"` + /// Contracts can burn native tokens for an existing factory denom + /// that they are the admin of. + /// Currently, the burn from address must be the admin contract. + BurnTokens *BurnTokens `json:"burn_tokens,omitempty"` + /// Sets the metadata on a denom which the contract controls + SetMetadata *SetMetadata `json:"set_metadata,omitempty"` + /// Forces a transfer of tokens from one address to another. + ForceTransfer *ForceTransfer `json:"force_transfer,omitempty"` +} + +// CreateDenom creates a new factory denom, of denomination: +// factory/{creating contract address}/{Subdenom} +// Subdenom can be of length at most 44 characters, in [0-9a-zA-Z./] +// The (creating contract address, subdenom) pair must be unique. +// The created denom's admin is the creating contract address, +// but this admin can be changed using the ChangeAdmin binding. +type CreateDenom struct { + Subdenom string `json:"subdenom"` + Metadata *Metadata `json:"metadata,omitempty"` +} + +// ChangeAdmin changes the admin for a factory denom. +// If the NewAdminAddress is empty, the denom has no admin. +type ChangeAdmin struct { + Denom string `json:"denom"` + NewAdminAddress string `json:"new_admin_address"` +} + +type MintTokens struct { + Denom string `json:"denom"` + Amount sdk.Int `json:"amount"` + MintToAddress string `json:"mint_to_address"` +} + +type BurnTokens struct { + Denom string `json:"denom"` + Amount sdk.Int `json:"amount"` + BurnFromAddress string `json:"burn_from_address"` +} + +type SetMetadata struct { + Denom string `json:"denom"` + Metadata Metadata `json:"metadata"` +} + +type ForceTransfer struct { + Denom string `json:"denom"` + Amount sdk.Int `json:"amount"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` +} diff --git a/x/tokenfactory/bindings/types/query.go b/x/tokenfactory/bindings/types/query.go new file mode 100644 index 000000000..f2dab4994 --- /dev/null +++ b/x/tokenfactory/bindings/types/query.go @@ -0,0 +1,59 @@ +package types + +type TokenFactoryQuery struct { + Token *TokenQuery `json:"token,omitempty"` +} + +// See https://github.com/CosmWasm/token-bindings/blob/main/packages/bindings/src/query.rs +type TokenQuery struct { + /// Given a subdenom minted by a contract via `OsmosisMsg::MintTokens`, + /// returns the full denom as used by `BankMsg::Send`. + FullDenom *FullDenom `json:"full_denom,omitempty"` + Admin *DenomAdmin `json:"admin,omitempty"` + Metadata *GetMetadata `json:"metadata,omitempty"` + DenomsByCreator *DenomsByCreator `json:"denoms_by_creator,omitempty"` + Params *GetParams `json:"params,omitempty"` +} + +// query types + +type FullDenom struct { + CreatorAddr string `json:"creator_addr"` + Subdenom string `json:"subdenom"` +} + +type GetMetadata struct { + Denom string `json:"denom"` +} + +type DenomAdmin struct { + Denom string `json:"denom"` +} + +type DenomsByCreator struct { + Creator string `json:"creator"` +} + +type GetParams struct{} + +// responses + +type FullDenomResponse struct { + Denom string `json:"denom"` +} + +type AdminResponse struct { + Admin string `json:"admin"` +} + +type MetadataResponse struct { + Metadata *Metadata `json:"metadata,omitempty"` +} + +type DenomsByCreatorResponse struct { + Denoms []string `json:"denoms"` +} + +type ParamsResponse struct { + Params Params `json:"params"` +} diff --git a/x/tokenfactory/bindings/types/types.go b/x/tokenfactory/bindings/types/types.go new file mode 100644 index 000000000..2c75feebb --- /dev/null +++ b/x/tokenfactory/bindings/types/types.go @@ -0,0 +1,37 @@ +package types + +import ( + wasmvmtypes "github.com/CosmWasm/wasmvm/types" +) + +type Metadata struct { + Description string `json:"description"` + // DenomUnits represents the list of DenomUnit's for a given coin + DenomUnits []DenomUnit `json:"denom_units"` + // Base represents the base denom (should be the DenomUnit with exponent = 0). + Base string `json:"base"` + // Display indicates the suggested denom that should be displayed in clients. + Display string `json:"display"` + // Name defines the name of the token (eg: Cosmos Atom) + Name string `json:"name"` + // Symbol is the token symbol usually shown on exchanges (eg: ATOM). + // This can be the same as the display. + Symbol string `json:"symbol"` +} + +type DenomUnit struct { + // Denom represents the string name of the given denom unit (e.g uatom). + Denom string `json:"denom"` + // Exponent represents power of 10 exponent that one must + // raise the base_denom to in order to equal the given DenomUnit's denom + // 1 denom = 1^exponent base_denom + // (e.g. with a base_denom of uatom, one can create a DenomUnit of 'atom' with + // exponent = 6, thus: 1 atom = 10^6 uatom). + Exponent uint32 `json:"exponent"` + // Aliases is a list of string aliases for the given denom + Aliases []string `json:"aliases"` +} + +type Params struct { + DenomCreationFee []wasmvmtypes.Coin `json:"denom_creation_fee"` +} diff --git a/x/tokenfactory/bindings/validate_msg_test.go b/x/tokenfactory/bindings/validate_msg_test.go new file mode 100644 index 000000000..dbc124dd5 --- /dev/null +++ b/x/tokenfactory/bindings/validate_msg_test.go @@ -0,0 +1,414 @@ +package bindings_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + + wasmbinding "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings" + bindings "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings/types" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + + "github.com/stretchr/testify/require" +) + +func TestCreateDenom(t *testing.T) { + actor := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, actor) + + // Fund actor with 100 base denom creation fees + actorAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, tokenz, actor, actorAmount) + + specs := map[string]struct { + createDenom *bindings.CreateDenom + expErr bool + }{ + "valid sub-denom": { + createDenom: &bindings.CreateDenom{ + Subdenom: "MOON", + }, + }, + "empty sub-denom": { + createDenom: &bindings.CreateDenom{ + Subdenom: "", + }, + expErr: false, + }, + "invalid sub-denom": { + createDenom: &bindings.CreateDenom{ + Subdenom: "sub-denom_2", + }, + expErr: true, + }, + "null create denom": { + createDenom: nil, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // when + _, gotErr := wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, actor, spec.createDenom) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestChangeAdmin(t *testing.T) { + const validDenom = "validdenom" + + tokenCreator := RandomAccountAddress() + + specs := map[string]struct { + actor sdk.AccAddress + changeAdmin *bindings.ChangeAdmin + + expErrMsg string + }{ + "valid": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("factory/%s/%s", tokenCreator.String(), validDenom), + NewAdminAddress: RandomBech32AccountAddress(), + }, + actor: tokenCreator, + }, + "typo in factory in denom name": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("facory/%s/%s", tokenCreator.String(), validDenom), + NewAdminAddress: RandomBech32AccountAddress(), + }, + actor: tokenCreator, + expErrMsg: "denom prefix is incorrect. Is: facory. Should be: factory: invalid denom", + }, + "invalid address in denom": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("factory/%s/%s", RandomBech32AccountAddress(), validDenom), + NewAdminAddress: RandomBech32AccountAddress(), + }, + actor: tokenCreator, + expErrMsg: "failed changing admin from message: unauthorized account", + }, + "other denom name in 3 part name": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("factory/%s/%s", tokenCreator.String(), "invalid denom"), + NewAdminAddress: RandomBech32AccountAddress(), + }, + actor: tokenCreator, + expErrMsg: fmt.Sprintf("invalid denom: factory/%s/invalid denom", tokenCreator.String()), + }, + "empty denom": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: "", + NewAdminAddress: RandomBech32AccountAddress(), + }, + actor: tokenCreator, + expErrMsg: "invalid denom: ", + }, + "empty address": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("factory/%s/%s", tokenCreator.String(), validDenom), + NewAdminAddress: "", + }, + actor: tokenCreator, + expErrMsg: "address from bech32: empty address string is not allowed", + }, + "creator is a different address": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("factory/%s/%s", tokenCreator.String(), validDenom), + NewAdminAddress: RandomBech32AccountAddress(), + }, + actor: RandomAccountAddress(), + expErrMsg: "failed changing admin from message: unauthorized account", + }, + "change to the same address": { + changeAdmin: &bindings.ChangeAdmin{ + Denom: fmt.Sprintf("factory/%s/%s", tokenCreator.String(), validDenom), + NewAdminAddress: tokenCreator.String(), + }, + actor: tokenCreator, + }, + "nil binding": { + actor: tokenCreator, + expErrMsg: "invalid request: changeAdmin is nil - original request: ", + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // Setup + tokenz, ctx := SetupCustomApp(t, tokenCreator) + + // Fund actor with 100 base denom creation fees + actorAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, tokenz, tokenCreator, actorAmount) + + _, err := wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, tokenCreator, &bindings.CreateDenom{ + Subdenom: validDenom, + }) + require.NoError(t, err) + + err = wasmbinding.ChangeAdmin(&tokenz.TokenFactoryKeeper, ctx, spec.actor, spec.changeAdmin) + if len(spec.expErrMsg) > 0 { + require.Error(t, err) + actualErrMsg := err.Error() + require.Equal(t, spec.expErrMsg, actualErrMsg) + return + } + require.NoError(t, err) + }) + } +} + +func TestMint(t *testing.T) { + creator := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, creator) + + // Fund actor with 100 base denom creation fees + tokenCreationFeeAmt := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, tokenz, creator, tokenCreationFeeAmt) + + // Create denoms for valid mint tests + validDenom := bindings.CreateDenom{ + Subdenom: "MOON", + } + _, err := wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &validDenom) + require.NoError(t, err) + + emptyDenom := bindings.CreateDenom{ + Subdenom: "", + } + _, err = wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &emptyDenom) + require.NoError(t, err) + + validDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), validDenom.Subdenom) + emptyDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), emptyDenom.Subdenom) + + lucky := RandomAccountAddress() + + // lucky was broke + balances := tokenz.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + amount, ok := sdk.NewIntFromString("8080") + require.True(t, ok) + + specs := map[string]struct { + mint *bindings.MintTokens + expErr bool + }{ + "valid mint": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount, + MintToAddress: lucky.String(), + }, + }, + "empty sub-denom": { + mint: &bindings.MintTokens{ + Denom: emptyDenomStr, + Amount: amount, + MintToAddress: lucky.String(), + }, + expErr: false, + }, + "nonexistent sub-denom": { + mint: &bindings.MintTokens{ + Denom: fmt.Sprintf("factory/%s/%s", creator.String(), "SUN"), + Amount: amount, + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "invalid sub-denom": { + mint: &bindings.MintTokens{ + Denom: "sub-denom_2", + Amount: amount, + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "zero amount": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: sdk.ZeroInt(), + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "negative amount": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount.Neg(), + MintToAddress: lucky.String(), + }, + expErr: true, + }, + "empty recipient": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount, + MintToAddress: "", + }, + expErr: true, + }, + "invalid recipient": { + mint: &bindings.MintTokens{ + Denom: validDenomStr, + Amount: amount, + MintToAddress: "invalid", + }, + expErr: true, + }, + "null mint": { + mint: nil, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // when + gotErr := wasmbinding.PerformMint(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, spec.mint) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestBurn(t *testing.T) { + creator := RandomAccountAddress() + tokenz, ctx := SetupCustomApp(t, creator) + + // Fund actor with 100 base denom creation fees + tokenCreationFeeAmt := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100))) + fundAccount(t, ctx, tokenz, creator, tokenCreationFeeAmt) + + // Create denoms for valid burn tests + validDenom := bindings.CreateDenom{ + Subdenom: "MOON", + } + _, err := wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &validDenom) + require.NoError(t, err) + + emptyDenom := bindings.CreateDenom{ + Subdenom: "", + } + _, err = wasmbinding.PerformCreateDenom(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, &emptyDenom) + require.NoError(t, err) + + lucky := RandomAccountAddress() + + // lucky was broke + balances := tokenz.BankKeeper.GetAllBalances(ctx, lucky) + require.Empty(t, balances) + + validDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), validDenom.Subdenom) + emptyDenomStr := fmt.Sprintf("factory/%s/%s", creator.String(), emptyDenom.Subdenom) + mintAmount, ok := sdk.NewIntFromString("8080") + require.True(t, ok) + + specs := map[string]struct { + burn *bindings.BurnTokens + expErr bool + }{ + "valid burn": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: false, + }, + "non admin address": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: mintAmount, + BurnFromAddress: lucky.String(), + }, + expErr: true, + }, + "empty sub-denom": { + burn: &bindings.BurnTokens{ + Denom: emptyDenomStr, + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: false, + }, + "invalid sub-denom": { + burn: &bindings.BurnTokens{ + Denom: "sub-denom_2", + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + "non-minted denom": { + burn: &bindings.BurnTokens{ + Denom: fmt.Sprintf("factory/%s/%s", creator.String(), "SUN"), + Amount: mintAmount, + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + "zero amount": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: sdk.ZeroInt(), + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + "negative amount": { + burn: nil, + expErr: true, + }, + "null burn": { + burn: &bindings.BurnTokens{ + Denom: validDenomStr, + Amount: mintAmount.Neg(), + BurnFromAddress: creator.String(), + }, + expErr: true, + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // Mint valid denom str and empty denom string for burn test + mintBinding := &bindings.MintTokens{ + Denom: validDenomStr, + Amount: mintAmount, + MintToAddress: creator.String(), + } + err := wasmbinding.PerformMint(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, mintBinding) + require.NoError(t, err) + + emptyDenomMintBinding := &bindings.MintTokens{ + Denom: emptyDenomStr, + Amount: mintAmount, + MintToAddress: creator.String(), + } + err = wasmbinding.PerformMint(&tokenz.TokenFactoryKeeper, &tokenz.BankKeeper, ctx, creator, emptyDenomMintBinding) + require.NoError(t, err) + + // when + gotErr := wasmbinding.PerformBurn(&tokenz.TokenFactoryKeeper, ctx, creator, spec.burn) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} diff --git a/x/tokenfactory/bindings/validate_queries_test.go b/x/tokenfactory/bindings/validate_queries_test.go new file mode 100644 index 000000000..78a84b921 --- /dev/null +++ b/x/tokenfactory/bindings/validate_queries_test.go @@ -0,0 +1,115 @@ +package bindings_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + wasmbinding "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/bindings" +) + +func TestFullDenom(t *testing.T) { + actor := RandomAccountAddress() + + specs := map[string]struct { + addr string + subdenom string + expFullDenom string + expErr bool + }{ + "valid address": { + addr: actor.String(), + subdenom: "subDenom1", + expFullDenom: fmt.Sprintf("factory/%s/subDenom1", actor.String()), + }, + "empty address": { + addr: "", + subdenom: "subDenom1", + expErr: true, + }, + "invalid address": { + addr: "invalid", + subdenom: "subDenom1", + expErr: true, + }, + "empty sub-denom": { + addr: actor.String(), + subdenom: "", + expFullDenom: fmt.Sprintf("factory/%s/", actor.String()), + }, + "invalid sub-denom (contains underscore)": { + addr: actor.String(), + subdenom: "sub_denom", + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // when + gotFullDenom, gotErr := wasmbinding.GetFullDenom(spec.addr, spec.subdenom) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expFullDenom, gotFullDenom, "exp %s but got %s", spec.expFullDenom, gotFullDenom) + }) + } +} + +func TestDenomAdmin(t *testing.T) { + addr := RandomAccountAddress() + app, ctx := SetupCustomApp(t, addr) + + // set token creation fee to zero to make testing easier + tfParams := app.TokenFactoryKeeper.GetParams(ctx) + tfParams.DenomCreationFee = sdk.NewCoins() + app.TokenFactoryKeeper.SetParams(ctx, tfParams) + + // create a subdenom via the token factory + admin := sdk.AccAddress([]byte("addr1_______________")) + tfDenom, err := app.TokenFactoryKeeper.CreateDenom(ctx, admin.String(), "subdenom") + require.NoError(t, err) + require.NotEmpty(t, tfDenom) + + queryPlugin := wasmbinding.NewQueryPlugin(&app.BankKeeper, &app.TokenFactoryKeeper) + + testCases := []struct { + name string + denom string + expectErr bool + expectAdmin string + }{ + { + name: "valid token factory denom", + denom: tfDenom, + expectAdmin: admin.String(), + }, + { + name: "invalid token factory denom", + denom: "uosmo", + expectErr: false, + expectAdmin: "", + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + resp, err := queryPlugin.GetDenomAdmin(ctx, tc.denom) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.NotNil(t, resp) + require.Equal(t, tc.expectAdmin, resp.Admin) + } + }) + } +} diff --git a/x/tokenfactory/bindings/wasm.go b/x/tokenfactory/bindings/wasm.go new file mode 100644 index 000000000..cb4d86430 --- /dev/null +++ b/x/tokenfactory/bindings/wasm.go @@ -0,0 +1,29 @@ +package bindings + +import ( + "github.com/CosmWasm/wasmd/x/wasm" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + + tokenfactorykeeper "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" +) + +func RegisterCustomPlugins( + bank *bankkeeper.BaseKeeper, + tokenFactory *tokenfactorykeeper.Keeper, +) []wasmkeeper.Option { + wasmQueryPlugin := NewQueryPlugin(bank, tokenFactory) + + queryPluginOpt := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{ + Custom: CustomQuerier(wasmQueryPlugin), + }) + messengerDecoratorOpt := wasmkeeper.WithMessageHandlerDecorator( + CustomMessageDecorator(bank, tokenFactory), + ) + + return []wasm.Option{ + queryPluginOpt, + messengerDecoratorOpt, + } +} diff --git a/x/tokenfactory/client/cli/query.go b/x/tokenfactory/client/cli/query.go new file mode 100644 index 000000000..421a10c74 --- /dev/null +++ b/x/tokenfactory/client/cli/query.go @@ -0,0 +1,122 @@ +package cli + +import ( + "fmt" + + // "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + // "github.com/cosmos/cosmos-sdk/client/flags" + // sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd() *cobra.Command { + // Group tokenfactory queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + GetParams(), + GetCmdDenomAuthorityMetadata(), + GetCmdDenomsFromCreator(), + ) + + return cmd +} + +// GetParams returns the params for the module +func GetParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params [flags]", + Short: "Get the params for the x/tokenfactory module", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdDenomAuthorityMetadata returns the authority metadata for a queried denom +func GetCmdDenomAuthorityMetadata() *cobra.Command { + cmd := &cobra.Command{ + Use: "denom-authority-metadata [denom] [flags]", + Short: "Get the authority metadata for a specific denom", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.DenomAuthorityMetadata(cmd.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: args[0], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdDenomsFromCreator a command to get a list of all tokens created by a specific creator address +func GetCmdDenomsFromCreator() *cobra.Command { + cmd := &cobra.Command{ + Use: "denoms-from-creator [creator address] [flags]", + Short: "Returns a list of all tokens created by a specific creator address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.DenomsFromCreator(cmd.Context(), &types.QueryDenomsFromCreatorRequest{ + Creator: args[0], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/tokenfactory/client/cli/tx.go b/x/tokenfactory/client/cli/tx.go new file mode 100644 index 000000000..5bde09974 --- /dev/null +++ b/x/tokenfactory/client/cli/tx.go @@ -0,0 +1,333 @@ +package cli + +import ( + "fmt" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + NewCreateDenomCmd(), + NewMintCmd(), + NewMintToCmd(), + NewBurnCmd(), + NewBurnFromCmd(), + NewForceTransferCmd(), + NewChangeAdminCmd(), + NewModifyDenomMetadataCmd(), + ) + + return cmd +} + +// NewCreateDenomCmd broadcast MsgCreateDenom +func NewCreateDenomCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "create-denom [subdenom] [flags]", + Short: "create a new denom from an account", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + msg := types.NewMsgCreateDenom( + clientCtx.GetFromAddress().String(), + args[0], + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewMintCmd broadcast MsgMint +func NewMintCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "mint [amount] [flags]", + Short: "Mint a denom to your address. Must have admin authority to do so.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgMint( + clientCtx.GetFromAddress().String(), + amount, + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewMintToCmd broadcast MsgMintTo +func NewMintToCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "mint-to [address] [amount] [flags]", + Short: "Mint a denom to an address. Must have admin authority to do so.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + toAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgMintTo( + clientCtx.GetFromAddress().String(), + amount, + toAddr.String(), + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewBurnCmd broadcast MsgBurn +func NewBurnCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "burn [amount] [flags]", + Short: "Burn tokens from an address. Must have admin authority to do so.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgBurn( + clientCtx.GetFromAddress().String(), + amount, + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewBurnFromCmd broadcast MsgBurnFrom +func NewBurnFromCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "burn-from [address] [amount] [flags]", + Short: "Burn tokens from an address. Must have admin authority to do so.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + fromAddr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + + msg := types.NewMsgBurnFrom( + clientCtx.GetFromAddress().String(), + amount, + fromAddr.String(), + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewForceTransferCmd broadcast MsgForceTransfer +func NewForceTransferCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "force-transfer [amount] [transfer-from-address] [transfer-to-address] [flags]", + Short: "Force transfer tokens from one address to another address. Must have admin authority to do so.", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + amount, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := types.NewMsgForceTransfer( + clientCtx.GetFromAddress().String(), + amount, + args[1], + args[2], + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewChangeAdminCmd broadcast MsgChangeAdmin +func NewChangeAdminCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "change-admin [denom] [new-admin-address] [flags]", + Short: "Changes the admin address for a factory-created denom. Must have admin authority to do so.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + msg := types.NewMsgChangeAdmin( + clientCtx.GetFromAddress().String(), + args[0], + args[1], + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewModifyDenomMetadataCmd broadcast a Bank Metadata modification transaction +func NewModifyDenomMetadataCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "modify-metadata [denom] [ticker-symbol] [description] [exponent] [flags]", + Short: "Changes the base data for frontends to query the data of.", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + fullDenom, ticker, desc := args[0], strings.ToUpper(args[1]), args[2] + + if !strings.HasPrefix(fullDenom, "factory/") { + return fmt.Errorf("denom must start with factory/") + } + + if len(ticker) == 0 { + return fmt.Errorf("ticker cannot be empty") + } + + // Exponent Checks + exponent, err := strconv.ParseUint(args[3], 10, 32) + if err != nil { + return err + } + + bankMetadata := banktypes.Metadata{ + Description: desc, + Display: fullDenom, + Symbol: ticker, + Name: fullDenom, + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: fullDenom, + Exponent: 0, // must be 0 for the base denom + Aliases: []string{ticker}, + }, + { + Denom: ticker, + Exponent: uint32(exponent), + Aliases: []string{fullDenom}, + }, + }, + Base: fullDenom, + } + + msg := types.NewMsgSetDenomMetadata( + clientCtx.GetFromAddress().String(), + bankMetadata, + ) + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/tokenfactory/keeper/admins.go b/x/tokenfactory/keeper/admins.go new file mode 100644 index 000000000..c1294f536 --- /dev/null +++ b/x/tokenfactory/keeper/admins.go @@ -0,0 +1,49 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/gogo/protobuf/proto" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +// GetAuthorityMetadata returns the authority metadata for a specific denom +func (k Keeper) GetAuthorityMetadata(ctx sdk.Context, denom string) (types.DenomAuthorityMetadata, error) { + bz := k.GetDenomPrefixStore(ctx, denom).Get([]byte(types.DenomAuthorityMetadataKey)) + + metadata := types.DenomAuthorityMetadata{} + err := proto.Unmarshal(bz, &metadata) + if err != nil { + return types.DenomAuthorityMetadata{}, err + } + return metadata, nil +} + +// setAuthorityMetadata stores authority metadata for a specific denom +func (k Keeper) setAuthorityMetadata(ctx sdk.Context, denom string, metadata types.DenomAuthorityMetadata) error { + err := metadata.Validate() + if err != nil { + return err + } + + store := k.GetDenomPrefixStore(ctx, denom) + + bz, err := proto.Marshal(&metadata) + if err != nil { + return err + } + + store.Set([]byte(types.DenomAuthorityMetadataKey), bz) + return nil +} + +func (k Keeper) setAdmin(ctx sdk.Context, denom string, admin string) error { + metadata, err := k.GetAuthorityMetadata(ctx, denom) + if err != nil { + return err + } + + metadata.Admin = admin + + return k.setAuthorityMetadata(ctx, denom, metadata) +} diff --git a/x/tokenfactory/keeper/admins_test.go b/x/tokenfactory/keeper/admins_test.go new file mode 100644 index 000000000..b059c3195 --- /dev/null +++ b/x/tokenfactory/keeper/admins_test.go @@ -0,0 +1,522 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func (suite *KeeperTestSuite) TestAdminMsgs() { + addr0bal := int64(0) + addr1bal := int64(0) + + bankKeeper := suite.App.BankKeeper + + suite.CreateDefaultDenom() + // Make sure that the admin is set correctly + queryRes, err := suite.queryClient.DenomAuthorityMetadata(suite.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: suite.defaultDenom, + }) + suite.Require().NoError(err) + suite.Require().Equal(suite.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin) + + // Test minting to admins own account + _, err = suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 10))) + addr0bal += 10 + suite.Require().NoError(err) + suite.Require().True(bankKeeper.GetBalance(suite.Ctx, suite.TestAccs[0], suite.defaultDenom).Amount.Int64() == addr0bal, bankKeeper.GetBalance(suite.Ctx, suite.TestAccs[0], suite.defaultDenom)) + + // Test minting to a different account + _, err = suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMintTo(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 10), suite.TestAccs[1].String())) + addr1bal += 10 + suite.Require().NoError(err) + suite.Require().True(suite.App.BankKeeper.GetBalance(suite.Ctx, suite.TestAccs[1], suite.defaultDenom).Amount.Int64() == addr1bal, suite.App.BankKeeper.GetBalance(suite.Ctx, suite.TestAccs[1], suite.defaultDenom)) + + // Test force transferring + _, err = suite.msgServer.ForceTransfer(sdk.WrapSDKContext(suite.Ctx), types.NewMsgForceTransfer(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 5), suite.TestAccs[1].String(), suite.TestAccs[0].String())) + addr1bal -= 5 + addr0bal += 5 + suite.Require().NoError(err) + suite.Require().True(suite.App.BankKeeper.GetBalance(suite.Ctx, suite.TestAccs[0], suite.defaultDenom).Amount.Int64() == addr0bal, suite.App.BankKeeper.GetBalance(suite.Ctx, suite.TestAccs[0], suite.defaultDenom)) + suite.Require().True(suite.App.BankKeeper.GetBalance(suite.Ctx, suite.TestAccs[1], suite.defaultDenom).Amount.Int64() == addr1bal, suite.App.BankKeeper.GetBalance(suite.Ctx, suite.TestAccs[1], suite.defaultDenom)) + + // Test burning from own account + _, err = suite.msgServer.Burn(sdk.WrapSDKContext(suite.Ctx), types.NewMsgBurn(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 5))) + suite.Require().NoError(err) + suite.Require().True(bankKeeper.GetBalance(suite.Ctx, suite.TestAccs[1], suite.defaultDenom).Amount.Int64() == addr1bal) + + // Test Change Admin + _, err = suite.msgServer.ChangeAdmin(sdk.WrapSDKContext(suite.Ctx), types.NewMsgChangeAdmin(suite.TestAccs[0].String(), suite.defaultDenom, suite.TestAccs[1].String())) + suite.Require().NoError(err) + queryRes, err = suite.queryClient.DenomAuthorityMetadata(suite.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: suite.defaultDenom, + }) + suite.Require().NoError(err) + suite.Require().Equal(suite.TestAccs[1].String(), queryRes.AuthorityMetadata.Admin) + + // Make sure old admin can no longer do actions + _, err = suite.msgServer.Burn(sdk.WrapSDKContext(suite.Ctx), types.NewMsgBurn(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 5))) + suite.Require().Error(err) + + // Make sure the new admin works + _, err = suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMint(suite.TestAccs[1].String(), sdk.NewInt64Coin(suite.defaultDenom, 5))) + addr1bal += 5 + suite.Require().NoError(err) + suite.Require().True(bankKeeper.GetBalance(suite.Ctx, suite.TestAccs[1], suite.defaultDenom).Amount.Int64() == addr1bal) + + // Try setting admin to empty + _, err = suite.msgServer.ChangeAdmin(sdk.WrapSDKContext(suite.Ctx), types.NewMsgChangeAdmin(suite.TestAccs[1].String(), suite.defaultDenom, "")) + suite.Require().NoError(err) + queryRes, err = suite.queryClient.DenomAuthorityMetadata(suite.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: suite.defaultDenom, + }) + suite.Require().NoError(err) + suite.Require().Equal("", queryRes.AuthorityMetadata.Admin) +} + +// TestMintDenom ensures the following properties of the MintMessage: +// * Noone can mint tokens for a denom that doesn't exist +// * Only the admin of a denom can mint tokens for it +// * The admin of a denom can mint tokens for it +func (suite *KeeperTestSuite) TestMintDenom() { + balances := make(map[string]int64) + for _, acc := range suite.TestAccs { + balances[acc.String()] = 0 + } + + // Create a denom + suite.CreateDefaultDenom() + + for _, tc := range []struct { + desc string + mintMsg types.MsgMint + expectPass bool + }{ + { + desc: "denom does not exist", + mintMsg: *types.NewMsgMint( + suite.TestAccs[0].String(), + sdk.NewInt64Coin("factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/evmos", 10), + ), + expectPass: false, + }, + { + desc: "mint is not by the admin", + mintMsg: *types.NewMsgMintTo( + suite.TestAccs[1].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + suite.TestAccs[0].String(), + ), + expectPass: false, + }, + { + desc: "success case - mint to self", + mintMsg: *types.NewMsgMint( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + ), + expectPass: true, + }, + { + desc: "success case - mint to another address", + mintMsg: *types.NewMsgMintTo( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + suite.TestAccs[1].String(), + ), + expectPass: true, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + _, err := suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), &tc.mintMsg) + if tc.expectPass { + suite.Require().NoError(err) + balances[tc.mintMsg.MintToAddress] += tc.mintMsg.Amount.Amount.Int64() + } else { + suite.Require().Error(err) + } + + mintToAddr, _ := sdk.AccAddressFromBech32(tc.mintMsg.MintToAddress) + bal := suite.App.BankKeeper.GetBalance(suite.Ctx, mintToAddr, suite.defaultDenom).Amount + suite.Require().Equal(bal.Int64(), balances[tc.mintMsg.MintToAddress]) + }) + } +} + +func (suite *KeeperTestSuite) TestBurnDenom() { + // Create a denom. + suite.CreateDefaultDenom() + + // mint 1000 default token for all testAccs + balances := make(map[string]int64) + for _, acc := range suite.TestAccs { + _, err := suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMintTo(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 1000), acc.String())) + suite.Require().NoError(err) + balances[acc.String()] = 1000 + } + + for _, tc := range []struct { + desc string + burnMsg types.MsgBurn + expectPass bool + }{ + { + desc: "denom does not exist", + burnMsg: *types.NewMsgBurn( + suite.TestAccs[0].String(), + sdk.NewInt64Coin("factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/evmos", 10), + ), + expectPass: false, + }, + { + desc: "burn is not by the admin", + burnMsg: *types.NewMsgBurnFrom( + suite.TestAccs[1].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + suite.TestAccs[0].String(), + ), + expectPass: false, + }, + { + desc: "burn more than balance", + burnMsg: *types.NewMsgBurn( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10000), + ), + expectPass: false, + }, + { + desc: "success case - burn from self", + burnMsg: *types.NewMsgBurn( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + ), + expectPass: true, + }, + { + desc: "success case - burn from another address", + burnMsg: *types.NewMsgBurnFrom( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + suite.TestAccs[1].String(), + ), + expectPass: true, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + _, err := suite.msgServer.Burn(sdk.WrapSDKContext(suite.Ctx), &tc.burnMsg) + if tc.expectPass { + suite.Require().NoError(err) + balances[tc.burnMsg.BurnFromAddress] -= tc.burnMsg.Amount.Amount.Int64() + } else { + suite.Require().Error(err) + } + + burnFromAddr, _ := sdk.AccAddressFromBech32(tc.burnMsg.BurnFromAddress) + bal := suite.App.BankKeeper.GetBalance(suite.Ctx, burnFromAddr, suite.defaultDenom).Amount + suite.Require().Equal(bal.Int64(), balances[tc.burnMsg.BurnFromAddress]) + }) + } +} + +func (suite *KeeperTestSuite) TestForceTransferDenom() { + // Create a denom. + suite.CreateDefaultDenom() + + // mint 1000 default token for all testAccs + balances := make(map[string]int64) + for _, acc := range suite.TestAccs { + _, err := suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMintTo(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 1000), acc.String())) + suite.Require().NoError(err) + balances[acc.String()] = 1000 + } + + for _, tc := range []struct { + desc string + forceTransferMsg types.MsgForceTransfer + expectPass bool + }{ + { + desc: "valid force transfer", + forceTransferMsg: *types.NewMsgForceTransfer( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + suite.TestAccs[1].String(), + suite.TestAccs[2].String(), + ), + expectPass: true, + }, + { + desc: "denom does not exist", + forceTransferMsg: *types.NewMsgForceTransfer( + suite.TestAccs[0].String(), + sdk.NewInt64Coin("factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/evmos", 10), + suite.TestAccs[1].String(), + suite.TestAccs[2].String(), + ), + expectPass: false, + }, + { + desc: "forceTransfer is not by the admin", + forceTransferMsg: *types.NewMsgForceTransfer( + suite.TestAccs[1].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10), + suite.TestAccs[1].String(), + suite.TestAccs[2].String(), + ), + expectPass: false, + }, + { + desc: "forceTransfer is greater than the balance of", + forceTransferMsg: *types.NewMsgForceTransfer( + suite.TestAccs[0].String(), + sdk.NewInt64Coin(suite.defaultDenom, 10000), + suite.TestAccs[1].String(), + suite.TestAccs[2].String(), + ), + expectPass: false, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + _, err := suite.msgServer.ForceTransfer(sdk.WrapSDKContext(suite.Ctx), &tc.forceTransferMsg) + if tc.expectPass { + suite.Require().NoError(err) + + balances[tc.forceTransferMsg.TransferFromAddress] -= tc.forceTransferMsg.Amount.Amount.Int64() + balances[tc.forceTransferMsg.TransferToAddress] += tc.forceTransferMsg.Amount.Amount.Int64() + } else { + suite.Require().Error(err) + } + + fromAddr, err := sdk.AccAddressFromBech32(tc.forceTransferMsg.TransferFromAddress) + suite.Require().NoError(err) + fromBal := suite.App.BankKeeper.GetBalance(suite.Ctx, fromAddr, suite.defaultDenom).Amount + suite.Require().True(fromBal.Int64() == balances[tc.forceTransferMsg.TransferFromAddress]) + + toAddr, err := sdk.AccAddressFromBech32(tc.forceTransferMsg.TransferToAddress) + suite.Require().NoError(err) + toBal := suite.App.BankKeeper.GetBalance(suite.Ctx, toAddr, suite.defaultDenom).Amount + suite.Require().True(toBal.Int64() == balances[tc.forceTransferMsg.TransferToAddress]) + }) + } +} + +func (suite *KeeperTestSuite) TestChangeAdminDenom() { + for _, tc := range []struct { + desc string + msgChangeAdmin func(denom string) *types.MsgChangeAdmin + expectedChangeAdminPass bool + expectedAdminIndex int + msgMint func(denom string) *types.MsgMint + expectedMintPass bool + }{ + { + desc: "creator admin can't mint after setting to '' ", + msgChangeAdmin: func(denom string) *types.MsgChangeAdmin { + return types.NewMsgChangeAdmin(suite.TestAccs[0].String(), denom, "") + }, + expectedChangeAdminPass: true, + expectedAdminIndex: -1, + msgMint: func(denom string) *types.MsgMint { + return types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(denom, 5)) + }, + expectedMintPass: false, + }, + { + desc: "non-admins can't change the existing admin", + msgChangeAdmin: func(denom string) *types.MsgChangeAdmin { + return types.NewMsgChangeAdmin(suite.TestAccs[1].String(), denom, suite.TestAccs[2].String()) + }, + expectedChangeAdminPass: false, + expectedAdminIndex: 0, + }, + { + desc: "success change admin", + msgChangeAdmin: func(denom string) *types.MsgChangeAdmin { + return types.NewMsgChangeAdmin(suite.TestAccs[0].String(), denom, suite.TestAccs[1].String()) + }, + expectedAdminIndex: 1, + expectedChangeAdminPass: true, + msgMint: func(denom string) *types.MsgMint { + return types.NewMsgMint(suite.TestAccs[1].String(), sdk.NewInt64Coin(denom, 5)) + }, + expectedMintPass: true, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + // setup test + suite.SetupTest() + + // Create a denom and mint + res, err := suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.Require().NoError(err) + + testDenom := res.GetNewTokenDenom() + + _, err = suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(testDenom, 10))) + suite.Require().NoError(err) + + _, err = suite.msgServer.ChangeAdmin(sdk.WrapSDKContext(suite.Ctx), tc.msgChangeAdmin(testDenom)) + if tc.expectedChangeAdminPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + queryRes, err := suite.queryClient.DenomAuthorityMetadata(suite.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: testDenom, + }) + suite.Require().NoError(err) + + // expectedAdminIndex with negative value is assumed as admin with value of "" + const emptyStringAdminIndexFlag = -1 + if tc.expectedAdminIndex == emptyStringAdminIndexFlag { + suite.Require().Equal("", queryRes.AuthorityMetadata.Admin) + } else { + suite.Require().Equal(suite.TestAccs[tc.expectedAdminIndex].String(), queryRes.AuthorityMetadata.Admin) + } + + // we test mint to test if admin authority is performed properly after admin change. + if tc.msgMint != nil { + _, err := suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), tc.msgMint(testDenom)) + if tc.expectedMintPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + } + }) + } +} + +func (suite *KeeperTestSuite) TestSetDenomMetaData() { + // setup test + suite.SetupTest() + suite.CreateDefaultDenom() + + for _, tc := range []struct { + desc string + msgSetDenomMetadata types.MsgSetDenomMetadata + expectedPass bool + }{ + { + desc: "successful set denom metadata", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[0].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: suite.defaultDenom, + Exponent: 0, + }, + { + Denom: "uosmo", + Exponent: 6, + }, + }, + Base: suite.defaultDenom, + Display: "uosmo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: true, + }, + { + desc: "non existent factory denom name", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[0].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: fmt.Sprintf("factory/%s/litecoin", suite.TestAccs[0].String()), + Exponent: 0, + }, + { + Denom: "uosmo", + Exponent: 6, + }, + }, + Base: fmt.Sprintf("factory/%s/litecoin", suite.TestAccs[0].String()), + Display: "uosmo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: false, + }, + { + desc: "non-factory denom", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[0].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "uosmo", + Exponent: 0, + }, + { + Denom: "uosmoo", + Exponent: 6, + }, + }, + Base: "uosmo", + Display: "uosmoo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: false, + }, + { + desc: "wrong admin", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[1].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: suite.defaultDenom, + Exponent: 0, + }, + { + Denom: "uosmo", + Exponent: 6, + }, + }, + Base: suite.defaultDenom, + Display: "uosmo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: false, + }, + { + desc: "invalid metadata (missing display denom unit)", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[0].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: suite.defaultDenom, + Exponent: 0, + }, + }, + Base: suite.defaultDenom, + Display: "uosmo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: false, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + bankKeeper := suite.App.BankKeeper + res, err := suite.msgServer.SetDenomMetadata(sdk.WrapSDKContext(suite.Ctx), &tc.msgSetDenomMetadata) + if tc.expectedPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + md, found := bankKeeper.GetDenomMetaData(suite.Ctx, suite.defaultDenom) + suite.Require().True(found) + suite.Require().Equal(tc.msgSetDenomMetadata.Metadata.Name, md.Name) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/x/tokenfactory/keeper/bankactions.go b/x/tokenfactory/keeper/bankactions.go new file mode 100644 index 000000000..dff42306d --- /dev/null +++ b/x/tokenfactory/keeper/bankactions.go @@ -0,0 +1,86 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func (k Keeper) mintTo(ctx sdk.Context, amount sdk.Coin, mintTo string) error { + // verify that denom is an x/tokenfactory denom + _, _, err := types.DeconstructDenom(amount.Denom) + if err != nil { + return err + } + + err = k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) + if err != nil { + return err + } + + addr, err := sdk.AccAddressFromBech32(mintTo) + if err != nil { + return err + } + + if k.bankKeeper.BlockedAddr(addr) { + return fmt.Errorf("failed to mint to blocked address: %s", addr) + } + + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, + addr, + sdk.NewCoins(amount)) +} + +func (k Keeper) burnFrom(ctx sdk.Context, amount sdk.Coin, burnFrom string) error { + // verify that denom is an x/tokenfactory denom + _, _, err := types.DeconstructDenom(amount.Denom) + if err != nil { + return err + } + + addr, err := sdk.AccAddressFromBech32(burnFrom) + if err != nil { + return err + } + + if k.bankKeeper.BlockedAddr(addr) { + return fmt.Errorf("failed to burn from blocked address: %s", addr) + } + + err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, + addr, + types.ModuleName, + sdk.NewCoins(amount)) + if err != nil { + return err + } + + return k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) +} + +func (k Keeper) forceTransfer(ctx sdk.Context, amount sdk.Coin, fromAddr string, toAddr string) error { + // verify that denom is an x/tokenfactory denom + _, _, err := types.DeconstructDenom(amount.Denom) + if err != nil { + return err + } + + fromSdkAddr, err := sdk.AccAddressFromBech32(fromAddr) + if err != nil { + return err + } + + toSdkAddr, err := sdk.AccAddressFromBech32(toAddr) + if err != nil { + return err + } + + if k.bankKeeper.BlockedAddr(toSdkAddr) { + return fmt.Errorf("failed to force transfer to blocked address: %s", toSdkAddr) + } + + return k.bankKeeper.SendCoins(ctx, fromSdkAddr, toSdkAddr, sdk.NewCoins(amount)) +} diff --git a/x/tokenfactory/keeper/createdenom.go b/x/tokenfactory/keeper/createdenom.go new file mode 100644 index 000000000..6658e55a6 --- /dev/null +++ b/x/tokenfactory/keeper/createdenom.go @@ -0,0 +1,95 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +// ConvertToBaseToken converts a fee amount in a whitelisted fee token to the base fee token amount +func (k Keeper) CreateDenom(ctx sdk.Context, creatorAddr string, subdenom string) (newTokenDenom string, err error) { + denom, err := k.validateCreateDenom(ctx, creatorAddr, subdenom) + if err != nil { + return "", err + } + + err = k.chargeForCreateDenom(ctx, creatorAddr, subdenom) + if err != nil { + return "", err + } + + err = k.createDenomAfterValidation(ctx, creatorAddr, denom) + return denom, err +} + +// Runs CreateDenom logic after the charge and all denom validation has been handled. +// Made into a second function for genesis initialization. +func (k Keeper) createDenomAfterValidation(ctx sdk.Context, creatorAddr string, denom string) (err error) { + denomMetaData := banktypes.Metadata{ + DenomUnits: []*banktypes.DenomUnit{{ + Denom: denom, + Exponent: 0, + }}, + Base: denom, + } + + k.bankKeeper.SetDenomMetaData(ctx, denomMetaData) + + authorityMetadata := types.DenomAuthorityMetadata{ + Admin: creatorAddr, + } + err = k.setAuthorityMetadata(ctx, denom, authorityMetadata) + if err != nil { + return err + } + + k.addDenomFromCreator(ctx, creatorAddr, denom) + return nil +} + +func (k Keeper) validateCreateDenom(ctx sdk.Context, creatorAddr string, subdenom string) (newTokenDenom string, err error) { + // Temporary check until IBC bug is sorted out + if k.bankKeeper.HasSupply(ctx, subdenom) { + return "", fmt.Errorf("temporary error until IBC bug is sorted out, " + + "can't create subdenoms that are the same as a native denom") + } + + denom, err := types.GetTokenDenom(creatorAddr, subdenom) + if err != nil { + return "", err + } + + _, found := k.bankKeeper.GetDenomMetaData(ctx, denom) + if found { + return "", types.ErrDenomExists + } + + return denom, nil +} + +func (k Keeper) chargeForCreateDenom(ctx sdk.Context, creatorAddr string, _ string) (err error) { + params := k.GetParams(ctx) + + // if DenomCreationFee is non-zero, transfer the tokens from the creator + // account to community pool + if params.DenomCreationFee != nil { + accAddr, err := sdk.AccAddressFromBech32(creatorAddr) + if err != nil { + return err + } + + if err := k.communityPoolKeeper.FundCommunityPool(ctx, params.DenomCreationFee, accAddr); err != nil { + return err + } + } + + // if DenomCreationGasConsume is non-zero, consume the gas + if params.DenomCreationGasConsume != 0 { + ctx.GasMeter().ConsumeGas(params.DenomCreationGasConsume, "consume denom creation gas") + } + + return nil +} diff --git a/x/tokenfactory/keeper/createdenom_test.go b/x/tokenfactory/keeper/createdenom_test.go new file mode 100644 index 000000000..889758da5 --- /dev/null +++ b/x/tokenfactory/keeper/createdenom_test.go @@ -0,0 +1,163 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/testhelpers" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func (suite *KeeperTestSuite) TestMsgCreateDenom() { + var ( + tokenFactoryKeeper = suite.App.TokenFactoryKeeper + bankKeeper = suite.App.BankKeeper + denomCreationFee = tokenFactoryKeeper.GetParams(suite.Ctx).DenomCreationFee + ) + + // Get balance of acc 0 before creating a denom + preCreateBalance := bankKeeper.GetBalance(suite.Ctx, suite.TestAccs[0], denomCreationFee[0].Denom) + + // Creating a denom should work + res, err := suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.Require().NoError(err) + suite.Require().NotEmpty(res.GetNewTokenDenom()) + + // Make sure that the admin is set correctly + queryRes, err := suite.queryClient.DenomAuthorityMetadata(suite.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: res.GetNewTokenDenom(), + }) + suite.Require().NoError(err) + suite.Require().Equal(suite.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin) + + // Make sure that creation fee was deducted + postCreateBalance := bankKeeper.GetBalance(suite.Ctx, suite.TestAccs[0], tokenFactoryKeeper.GetParams(suite.Ctx).DenomCreationFee[0].Denom) + suite.Require().True(preCreateBalance.Sub(postCreateBalance).IsEqual(denomCreationFee[0])) + + // Make sure that a second version of the same denom can't be recreated + _, err = suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.Require().Error(err) + + // Creating a second denom should work + res, err = suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "litecoin")) + suite.Require().NoError(err) + suite.Require().NotEmpty(res.GetNewTokenDenom()) + + // Try querying all the denoms created by suite.TestAccs[0] + queryRes2, err := suite.queryClient.DenomsFromCreator(suite.Ctx.Context(), &types.QueryDenomsFromCreatorRequest{ + Creator: suite.TestAccs[0].String(), + }) + suite.Require().NoError(err) + suite.Require().Len(queryRes2.Denoms, 2) + + // Make sure that a second account can create a denom with the same subdenom + res, err = suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[1].String(), "bitcoin")) + suite.Require().NoError(err) + suite.Require().NotEmpty(res.GetNewTokenDenom()) + + // Make sure that an address with a "/" in it can't create denoms + _, err = suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom("osmosis.eth/creator", "bitcoin")) + suite.Require().Error(err) +} + +func (suite *KeeperTestSuite) TestCreateDenom() { + var ( + primaryDenom = types.DefaultParams().DenomCreationFee[0].Denom + secondaryDenom = testhelpers.SecondaryDenom + defaultDenomCreationFee = types.Params{DenomCreationFee: sdk.NewCoins(sdk.NewCoin(primaryDenom, sdk.NewInt(50000000)))} + twoDenomCreationFee = types.Params{DenomCreationFee: sdk.NewCoins(sdk.NewCoin(primaryDenom, sdk.NewInt(50000000)), sdk.NewCoin(secondaryDenom, sdk.NewInt(50000000)))} + nilCreationFee = types.Params{DenomCreationFee: nil} + largeCreationFee = types.Params{DenomCreationFee: sdk.NewCoins(sdk.NewCoin(primaryDenom, sdk.NewInt(5000000000)))} + ) + + for _, tc := range []struct { + desc string + denomCreationFee types.Params + setup func() + subdenom string + valid bool + }{ + { + desc: "subdenom too long", + denomCreationFee: defaultDenomCreationFee, + subdenom: "assadsadsadasdasdsadsadsadsadsadsadsklkadaskkkdasdasedskhanhassyeunganassfnlksdflksafjlkasd", + valid: false, + }, + { + desc: "subdenom and creator pair already exists", + denomCreationFee: defaultDenomCreationFee, + setup: func() { + _, err := suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.Require().NoError(err) + }, + subdenom: "bitcoin", + valid: false, + }, + { + desc: "success case: defaultDenomCreationFee", + denomCreationFee: defaultDenomCreationFee, + subdenom: "evmos", + valid: true, + }, + { + desc: "success case: twoDenomCreationFee", + denomCreationFee: twoDenomCreationFee, + subdenom: "catcoin", + valid: true, + }, + { + desc: "success case: nilCreationFee", + denomCreationFee: nilCreationFee, + subdenom: "czcoin", + valid: true, + }, + { + desc: "account doesn't have enough to pay for denom creation fee", + denomCreationFee: largeCreationFee, + subdenom: "tooexpensive", + valid: false, + }, + { + desc: "subdenom having invalid characters", + denomCreationFee: defaultDenomCreationFee, + subdenom: "bit/***///&&&/coin", + valid: false, + }, + } { + suite.SetupTest() + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + if tc.setup != nil { + tc.setup() + } + tokenFactoryKeeper := suite.App.TokenFactoryKeeper + bankKeeper := suite.App.BankKeeper + // Set denom creation fee in params + tokenFactoryKeeper.SetParams(suite.Ctx, tc.denomCreationFee) + denomCreationFee := tokenFactoryKeeper.GetParams(suite.Ctx).DenomCreationFee + suite.Require().Equal(tc.denomCreationFee.DenomCreationFee, denomCreationFee) + + // note balance, create a tokenfactory denom, then note balance again + preCreateBalance := bankKeeper.GetAllBalances(suite.Ctx, suite.TestAccs[0]) + res, err := suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), tc.subdenom)) + postCreateBalance := bankKeeper.GetAllBalances(suite.Ctx, suite.TestAccs[0]) + if tc.valid { + suite.Require().NoError(err) + suite.Require().True(preCreateBalance.Sub(postCreateBalance).IsEqual(denomCreationFee)) + + // Make sure that the admin is set correctly + queryRes, err := suite.queryClient.DenomAuthorityMetadata(suite.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{ + Denom: res.GetNewTokenDenom(), + }) + + suite.Require().NoError(err) + suite.Require().Equal(suite.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin) + + } else { + suite.Require().Error(err) + // Ensure we don't charge if we expect an error + suite.Require().True(preCreateBalance.IsEqual(postCreateBalance)) + } + }) + } +} diff --git a/x/tokenfactory/keeper/creators.go b/x/tokenfactory/keeper/creators.go new file mode 100644 index 000000000..d200c0603 --- /dev/null +++ b/x/tokenfactory/keeper/creators.go @@ -0,0 +1,29 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) addDenomFromCreator(ctx sdk.Context, creator, denom string) { + store := k.GetCreatorPrefixStore(ctx, creator) + store.Set([]byte(denom), []byte(denom)) +} + +func (k Keeper) GetDenomsFromCreator(ctx sdk.Context, creator string) []string { + store := k.GetCreatorPrefixStore(ctx, creator) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + denoms := []string{} + for ; iterator.Valid(); iterator.Next() { + denoms = append(denoms, string(iterator.Key())) + } + return denoms +} + +func (k Keeper) GetAllDenomsIterator(ctx sdk.Context) sdk.Iterator { + return k.GetCreatorsPrefixStore(ctx).Iterator(nil, nil) +} + +// TODO: Get all denoms a user is the admin of currently diff --git a/x/tokenfactory/keeper/genesis.go b/x/tokenfactory/keeper/genesis.go new file mode 100644 index 000000000..bd8c82de5 --- /dev/null +++ b/x/tokenfactory/keeper/genesis.go @@ -0,0 +1,58 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +// InitGenesis initializes the tokenfactory module's state from a provided genesis +// state. +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + k.CreateModuleAccount(ctx) + + if genState.Params.DenomCreationFee == nil { + genState.Params.DenomCreationFee = sdk.NewCoins() + } + k.SetParams(ctx, genState.Params) + + for _, genDenom := range genState.GetFactoryDenoms() { + creator, _, err := types.DeconstructDenom(genDenom.GetDenom()) + if err != nil { + panic(err) + } + err = k.createDenomAfterValidation(ctx, creator, genDenom.GetDenom()) + if err != nil { + panic(err) + } + err = k.setAuthorityMetadata(ctx, genDenom.GetDenom(), genDenom.GetAuthorityMetadata()) + if err != nil { + panic(err) + } + } +} + +// ExportGenesis returns the tokenfactory module's exported genesis. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genDenoms := []types.GenesisDenom{} + iterator := k.GetAllDenomsIterator(ctx) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + denom := string(iterator.Value()) + + authorityMetadata, err := k.GetAuthorityMetadata(ctx, denom) + if err != nil { + panic(err) + } + + genDenoms = append(genDenoms, types.GenesisDenom{ + Denom: denom, + AuthorityMetadata: authorityMetadata, + }) + } + + return &types.GenesisState{ + FactoryDenoms: genDenoms, + Params: k.GetParams(ctx), + } +} diff --git a/x/tokenfactory/keeper/genesis_test.go b/x/tokenfactory/keeper/genesis_test.go new file mode 100644 index 000000000..862cbbdd8 --- /dev/null +++ b/x/tokenfactory/keeper/genesis_test.go @@ -0,0 +1,59 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func (suite *KeeperTestSuite) TestGenesis() { + genesisState := types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + }, + }, + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/diff-admin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "cosmos15czt5nhlnvayqq37xun9s9yus0d6y26dx74r5p", + }, + }, + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/litecoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + }, + }, + }, + } + + suite.SetupTestForInitGenesis() + app := suite.App + + // Test both with bank denom metadata set, and not set. + for i, denom := range genesisState.FactoryDenoms { + // hacky, sets bank metadata to exist if i != 0, to cover both cases. + if i != 0 { + app.BankKeeper.SetDenomMetaData(suite.Ctx, banktypes.Metadata{Base: denom.GetDenom()}) + } + } + + // check before initGenesis that the module account is nil + tokenfactoryModuleAccount := app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName)) + suite.Require().Nil(tokenfactoryModuleAccount) + + app.TokenFactoryKeeper.SetParams(suite.Ctx, types.Params{DenomCreationFee: sdk.Coins{sdk.NewInt64Coin("uosmo", 100)}}) + app.TokenFactoryKeeper.InitGenesis(suite.Ctx, genesisState) + + // check that the module account is now initialized + tokenfactoryModuleAccount = app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName)) + suite.Require().NotNil(tokenfactoryModuleAccount) + + exportedGenesis := app.TokenFactoryKeeper.ExportGenesis(suite.Ctx) + suite.Require().NotNil(exportedGenesis) + suite.Require().Equal(genesisState, *exportedGenesis) +} diff --git a/x/tokenfactory/keeper/grpc_query.go b/x/tokenfactory/keeper/grpc_query.go new file mode 100644 index 000000000..3ed6e27c9 --- /dev/null +++ b/x/tokenfactory/keeper/grpc_query.go @@ -0,0 +1,35 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +var _ types.QueryServer = Keeper{} + +func (k Keeper) Params(ctx context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + params := k.GetParams(sdkCtx) + + return &types.QueryParamsResponse{Params: params}, nil +} + +func (k Keeper) DenomAuthorityMetadata(ctx context.Context, req *types.QueryDenomAuthorityMetadataRequest) (*types.QueryDenomAuthorityMetadataResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + authorityMetadata, err := k.GetAuthorityMetadata(sdkCtx, req.GetDenom()) + if err != nil { + return nil, err + } + + return &types.QueryDenomAuthorityMetadataResponse{AuthorityMetadata: authorityMetadata}, nil +} + +func (k Keeper) DenomsFromCreator(ctx context.Context, req *types.QueryDenomsFromCreatorRequest) (*types.QueryDenomsFromCreatorResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + denoms := k.GetDenomsFromCreator(sdkCtx, req.GetCreator()) + return &types.QueryDenomsFromCreatorResponse{Denoms: denoms}, nil +} diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go new file mode 100644 index 000000000..0f30be034 --- /dev/null +++ b/x/tokenfactory/keeper/keeper.go @@ -0,0 +1,87 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +type ( + Keeper struct { + storeKey storetypes.StoreKey + + paramSpace paramtypes.Subspace + + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + communityPoolKeeper types.CommunityPoolKeeper + + enabledCapabilities []string + } +) + +// NewKeeper returns a new instance of the x/tokenfactory keeper +func NewKeeper( + storeKey storetypes.StoreKey, + paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + communityPoolKeeper types.CommunityPoolKeeper, + enabledCapabilities []string, +) Keeper { + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + storeKey: storeKey, + paramSpace: paramSpace, + + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + communityPoolKeeper: communityPoolKeeper, + + enabledCapabilities: enabledCapabilities, + } +} + +// Logger returns a logger for the x/tokenfactory module +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// GetDenomPrefixStore returns the substore for a specific denom +func (k Keeper) GetDenomPrefixStore(ctx sdk.Context, denom string) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetDenomPrefixStore(denom)) +} + +// GetCreatorPrefixStore returns the substore for a specific creator address +func (k Keeper) GetCreatorPrefixStore(ctx sdk.Context, creator string) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetCreatorPrefix(creator)) +} + +// GetCreatorsPrefixStore returns the substore that contains a list of creators +func (k Keeper) GetCreatorsPrefixStore(ctx sdk.Context) sdk.KVStore { + store := ctx.KVStore(k.storeKey) + return prefix.NewStore(store, types.GetCreatorsPrefix()) +} + +// CreateModuleAccount creates a module account with minting and burning capabilities +// This account isn't intended to store any coins, +// it purely mints and burns them on behalf of the admin of respective denoms, +// and sends to the relevant address. +func (k Keeper) CreateModuleAccount(ctx sdk.Context) { + moduleAcc := authtypes.NewEmptyModuleAccount(types.ModuleName, authtypes.Minter, authtypes.Burner) + k.accountKeeper.SetModuleAccount(ctx, moduleAcc) +} diff --git a/x/tokenfactory/keeper/keeper_test.go b/x/tokenfactory/keeper/keeper_test.go new file mode 100644 index 000000000..da8589008 --- /dev/null +++ b/x/tokenfactory/keeper/keeper_test.go @@ -0,0 +1,64 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/CosmosTokenFactory/token-factory/app/apptesting" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/keeper" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/testhelpers" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +type KeeperTestSuite struct { + apptesting.KeeperTestHelper + + queryClient types.QueryClient + msgServer types.MsgServer + // defaultDenom is on the suite, as it depends on the creator test address. + defaultDenom string +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.Setup() + // Fund every TestAcc with two denoms, one of which is the denom creation fee + fundAccsAmount := sdk.NewCoins(sdk.NewCoin(types.DefaultParams().DenomCreationFee[0].Denom, types.DefaultParams().DenomCreationFee[0].Amount.MulRaw(100)), sdk.NewCoin(testhelpers.SecondaryDenom, testhelpers.SecondaryAmount)) + for _, acc := range suite.TestAccs { + suite.FundAcc(acc, fundAccsAmount) + } + + suite.queryClient = types.NewQueryClient(suite.QueryHelper) + suite.msgServer = keeper.NewMsgServerImpl(suite.App.TokenFactoryKeeper) +} + +func (suite *KeeperTestSuite) CreateDefaultDenom() { + res, _ := suite.msgServer.CreateDenom(sdk.WrapSDKContext(suite.Ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.defaultDenom = res.GetNewTokenDenom() +} + +func (suite *KeeperTestSuite) TestCreateModuleAccount() { + app := suite.App + + // remove module account + tokenfactoryModuleAccount := app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName)) + app.AccountKeeper.RemoveAccount(suite.Ctx, tokenfactoryModuleAccount) + + // ensure module account was removed + suite.Ctx = app.BaseApp.NewContext(false, tmproto.Header{}) + tokenfactoryModuleAccount = app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName)) + suite.Require().Nil(tokenfactoryModuleAccount) + + // create module account + app.TokenFactoryKeeper.CreateModuleAccount(suite.Ctx) + + // check that the module account is now initialized + tokenfactoryModuleAccount = app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName)) + suite.Require().NotNil(tokenfactoryModuleAccount) +} diff --git a/x/tokenfactory/keeper/msg_server.go b/x/tokenfactory/keeper/msg_server.go new file mode 100644 index 000000000..6a4e09be3 --- /dev/null +++ b/x/tokenfactory/keeper/msg_server.go @@ -0,0 +1,209 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +func (server msgServer) CreateDenom(goCtx context.Context, msg *types.MsgCreateDenom) (*types.MsgCreateDenomResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + denom, err := server.Keeper.CreateDenom(ctx, msg.Sender, msg.Subdenom) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgCreateDenom, + sdk.NewAttribute(types.AttributeCreator, msg.Sender), + sdk.NewAttribute(types.AttributeNewTokenDenom, denom), + ), + }) + + return &types.MsgCreateDenomResponse{ + NewTokenDenom: denom, + }, nil +} + +func (server msgServer) Mint(goCtx context.Context, msg *types.MsgMint) (*types.MsgMintResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // pay some extra gas cost to give a better error here. + _, denomExists := server.bankKeeper.GetDenomMetaData(ctx, msg.Amount.Denom) + if !denomExists { + return nil, types.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Amount.Denom) + } + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + if msg.MintToAddress == "" { + msg.MintToAddress = msg.Sender + } + + err = server.Keeper.mintTo(ctx, msg.Amount, msg.MintToAddress) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgMint, + sdk.NewAttribute(types.AttributeMintToAddress, msg.Sender), + sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), + ), + }) + + return &types.MsgMintResponse{}, nil +} + +func (server msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBurnResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + if msg.BurnFromAddress == "" { + msg.BurnFromAddress = msg.Sender + } else if !types.IsCapabilityEnabled(server.Keeper.enabledCapabilities, types.EnableBurnFrom) { + return nil, types.ErrCapabilityNotEnabled + } + + err = server.Keeper.burnFrom(ctx, msg.Amount, msg.BurnFromAddress) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgBurn, + sdk.NewAttribute(types.AttributeBurnFromAddress, msg.Sender), + sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), + ), + }) + + return &types.MsgBurnResponse{}, nil +} + +func (server msgServer) ForceTransfer(goCtx context.Context, msg *types.MsgForceTransfer) (*types.MsgForceTransferResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if !types.IsCapabilityEnabled(server.Keeper.enabledCapabilities, types.EnableForceTransfer) { + return nil, types.ErrCapabilityNotEnabled + } + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + err = server.Keeper.forceTransfer(ctx, msg.Amount, msg.TransferFromAddress, msg.TransferToAddress) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgForceTransfer, + sdk.NewAttribute(types.AttributeTransferFromAddress, msg.TransferFromAddress), + sdk.NewAttribute(types.AttributeTransferToAddress, msg.TransferToAddress), + sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), + ), + }) + + return &types.MsgForceTransferResponse{}, nil +} + +func (server msgServer) ChangeAdmin(goCtx context.Context, msg *types.MsgChangeAdmin) (*types.MsgChangeAdminResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Denom) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + err = server.Keeper.setAdmin(ctx, msg.Denom, msg.NewAdmin) + if err != nil { + return nil, err + } + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgChangeAdmin, + sdk.NewAttribute(types.AttributeDenom, msg.GetDenom()), + sdk.NewAttribute(types.AttributeNewAdmin, msg.NewAdmin), + ), + }) + + return &types.MsgChangeAdminResponse{}, nil +} + +func (server msgServer) SetDenomMetadata(goCtx context.Context, msg *types.MsgSetDenomMetadata) (*types.MsgSetDenomMetadataResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if !types.IsCapabilityEnabled(server.Keeper.enabledCapabilities, types.EnableSetMetadata) { + return nil, types.ErrCapabilityNotEnabled + } + + // Defense in depth validation of metadata + err := msg.Metadata.Validate() + if err != nil { + return nil, err + } + + authorityMetadata, err := server.Keeper.GetAuthorityMetadata(ctx, msg.Metadata.Base) + if err != nil { + return nil, err + } + + if msg.Sender != authorityMetadata.GetAdmin() { + return nil, types.ErrUnauthorized + } + + server.Keeper.bankKeeper.SetDenomMetaData(ctx, msg.Metadata) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.TypeMsgSetDenomMetadata, + sdk.NewAttribute(types.AttributeDenom, msg.Metadata.Base), + sdk.NewAttribute(types.AttributeDenomMetadata, msg.Metadata.String()), + ), + }) + + return &types.MsgSetDenomMetadataResponse{}, nil +} diff --git a/x/tokenfactory/keeper/msg_server_test.go b/x/tokenfactory/keeper/msg_server_test.go new file mode 100644 index 000000000..14e497177 --- /dev/null +++ b/x/tokenfactory/keeper/msg_server_test.go @@ -0,0 +1,247 @@ +package keeper_test + +import ( + "fmt" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// TestMintDenomMsg tests TypeMsgMint message is emitted on a successful mint +func (suite *KeeperTestSuite) TestMintDenomMsg() { + // Create a denom + suite.CreateDefaultDenom() + + for _, tc := range []struct { + desc string + amount int64 + mintDenom string + admin string + valid bool + expectedMessageEvents int + }{ + { + desc: "denom does not exist", + amount: 10, + mintDenom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/evmos", + admin: suite.TestAccs[0].String(), + valid: false, + }, + { + desc: "success case", + amount: 10, + mintDenom: suite.defaultDenom, + admin: suite.TestAccs[0].String(), + valid: true, + expectedMessageEvents: 1, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + ctx := suite.Ctx.WithEventManager(sdk.NewEventManager()) + suite.Require().Equal(0, len(ctx.EventManager().Events())) + // Test mint message + suite.msgServer.Mint(sdk.WrapSDKContext(ctx), types.NewMsgMint(tc.admin, sdk.NewInt64Coin(tc.mintDenom, 10))) //nolint:errcheck + // Ensure current number and type of event is emitted + suite.AssertEventEmitted(ctx, types.TypeMsgMint, tc.expectedMessageEvents) + }) + } +} + +// TestBurnDenomMsg tests TypeMsgBurn message is emitted on a successful burn +func (suite *KeeperTestSuite) TestBurnDenomMsg() { + // Create a denom. + suite.CreateDefaultDenom() + // mint 10 default token for testAcc[0] + suite.msgServer.Mint(sdk.WrapSDKContext(suite.Ctx), types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 10))) //nolint:errcheck + + for _, tc := range []struct { + desc string + amount int64 + burnDenom string + admin string + valid bool + expectedMessageEvents int + }{ + { + desc: "denom does not exist", + burnDenom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/evmos", + admin: suite.TestAccs[0].String(), + valid: false, + }, + { + desc: "success case", + burnDenom: suite.defaultDenom, + admin: suite.TestAccs[0].String(), + valid: true, + expectedMessageEvents: 1, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + ctx := suite.Ctx.WithEventManager(sdk.NewEventManager()) + suite.Require().Equal(0, len(ctx.EventManager().Events())) + // Test burn message + suite.msgServer.Burn(sdk.WrapSDKContext(ctx), types.NewMsgBurn(tc.admin, sdk.NewInt64Coin(tc.burnDenom, 10))) //nolint:errcheck + // Ensure current number and type of event is emitted + suite.AssertEventEmitted(ctx, types.TypeMsgBurn, tc.expectedMessageEvents) + }) + } +} + +// TestCreateDenomMsg tests TypeMsgCreateDenom message is emitted on a successful denom creation +func (suite *KeeperTestSuite) TestCreateDenomMsg() { + defaultDenomCreationFee := types.Params{DenomCreationFee: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(50000000)))} + for _, tc := range []struct { + desc string + denomCreationFee types.Params + subdenom string + valid bool + expectedMessageEvents int + }{ + { + desc: "subdenom too long", + denomCreationFee: defaultDenomCreationFee, + subdenom: "assadsadsadasdasdsadsadsadsadsadsadsklkadaskkkdasdasedskhanhassyeunganassfnlksdflksafjlkasd", + valid: false, + }, + { + desc: "success case: defaultDenomCreationFee", + denomCreationFee: defaultDenomCreationFee, + subdenom: "evmos", + valid: true, + expectedMessageEvents: 1, + }, + } { + suite.SetupTest() + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + tokenFactoryKeeper := suite.App.TokenFactoryKeeper + ctx := suite.Ctx.WithEventManager(sdk.NewEventManager()) + suite.Require().Equal(0, len(ctx.EventManager().Events())) + // Set denom creation fee in params + tokenFactoryKeeper.SetParams(suite.Ctx, tc.denomCreationFee) + // Test create denom message + suite.msgServer.CreateDenom(sdk.WrapSDKContext(ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), tc.subdenom)) //nolint:errcheck + // Ensure current number and type of event is emitted + suite.AssertEventEmitted(ctx, types.TypeMsgCreateDenom, tc.expectedMessageEvents) + }) + } +} + +// TestChangeAdminDenomMsg tests TypeMsgChangeAdmin message is emitted on a successful admin change +func (suite *KeeperTestSuite) TestChangeAdminDenomMsg() { + for _, tc := range []struct { + desc string + msgChangeAdmin func(denom string) *types.MsgChangeAdmin + expectedChangeAdminPass bool + expectedAdminIndex int + msgMint func(denom string) *types.MsgMint + expectedMintPass bool + expectedMessageEvents int + }{ + { + desc: "non-admins can't change the existing admin", + msgChangeAdmin: func(denom string) *types.MsgChangeAdmin { + return types.NewMsgChangeAdmin(suite.TestAccs[1].String(), denom, suite.TestAccs[2].String()) + }, + expectedChangeAdminPass: false, + expectedAdminIndex: 0, + }, + { + desc: "success change admin", + msgChangeAdmin: func(denom string) *types.MsgChangeAdmin { + return types.NewMsgChangeAdmin(suite.TestAccs[0].String(), denom, suite.TestAccs[1].String()) + }, + expectedAdminIndex: 1, + expectedChangeAdminPass: true, + expectedMessageEvents: 1, + msgMint: func(denom string) *types.MsgMint { + return types.NewMsgMint(suite.TestAccs[1].String(), sdk.NewInt64Coin(denom, 5)) + }, + expectedMintPass: true, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + // setup test + suite.SetupTest() + ctx := suite.Ctx.WithEventManager(sdk.NewEventManager()) + suite.Require().Equal(0, len(ctx.EventManager().Events())) + // Create a denom and mint + res, err := suite.msgServer.CreateDenom(sdk.WrapSDKContext(ctx), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.Require().NoError(err) + testDenom := res.GetNewTokenDenom() + suite.msgServer.Mint(sdk.WrapSDKContext(ctx), types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(testDenom, 10))) //nolint:errcheck + // Test change admin message + suite.msgServer.ChangeAdmin(sdk.WrapSDKContext(ctx), tc.msgChangeAdmin(testDenom)) //nolint:errcheck + // Ensure current number and type of event is emitted + suite.AssertEventEmitted(ctx, types.TypeMsgChangeAdmin, tc.expectedMessageEvents) + }) + } +} + +// TestSetDenomMetaDataMsg tests TypeMsgSetDenomMetadata message is emitted on a successful denom metadata change +func (suite *KeeperTestSuite) TestSetDenomMetaDataMsg() { + // setup test + suite.SetupTest() + suite.CreateDefaultDenom() + + for _, tc := range []struct { + desc string + msgSetDenomMetadata types.MsgSetDenomMetadata + expectedPass bool + expectedMessageEvents int + }{ + { + desc: "successful set denom metadata", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[0].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: suite.defaultDenom, + Exponent: 0, + }, + { + Denom: "uosmo", + Exponent: 6, + }, + }, + Base: suite.defaultDenom, + Display: "uosmo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: true, + expectedMessageEvents: 1, + }, + { + desc: "non existent factory denom name", + msgSetDenomMetadata: *types.NewMsgSetDenomMetadata(suite.TestAccs[0].String(), banktypes.Metadata{ + Description: "yeehaw", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: fmt.Sprintf("factory/%s/litecoin", suite.TestAccs[0].String()), + Exponent: 0, + }, + { + Denom: "uosmo", + Exponent: 6, + }, + }, + Base: fmt.Sprintf("factory/%s/litecoin", suite.TestAccs[0].String()), + Display: "uosmo", + Name: "OSMO", + Symbol: "OSMO", + }), + expectedPass: false, + }, + } { + suite.Run(fmt.Sprintf("Case %s", tc.desc), func() { + ctx := suite.Ctx.WithEventManager(sdk.NewEventManager()) + suite.Require().Equal(0, len(ctx.EventManager().Events())) + // Test set denom metadata message + suite.msgServer.SetDenomMetadata(sdk.WrapSDKContext(ctx), &tc.msgSetDenomMetadata) //nolint:errcheck + // Ensure current number and type of event is emitted + suite.AssertEventEmitted(ctx, types.TypeMsgSetDenomMetadata, tc.expectedMessageEvents) + }) + } +} diff --git a/x/tokenfactory/keeper/params.go b/x/tokenfactory/keeper/params.go new file mode 100644 index 000000000..07b37d8e7 --- /dev/null +++ b/x/tokenfactory/keeper/params.go @@ -0,0 +1,18 @@ +package keeper + +import ( + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GetParams returns the total set params. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the total set of params. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} diff --git a/x/tokenfactory/module.go b/x/tokenfactory/module.go new file mode 100644 index 000000000..936f1bf3f --- /dev/null +++ b/x/tokenfactory/module.go @@ -0,0 +1,229 @@ +/* +The tokenfactory module allows any account to create a new token with +the name `factory/{creator address}/{subdenom}`. + +- Mint and burn user denom to and form any account +- Create a transfer of their denom between any two accounts +- Change the admin. In the future, more admin capabilities may be added. +*/ +package tokenfactory + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + simulation "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/simulation" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/client/cli" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/keeper" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface for the capability module. +type AppModuleBasic struct{} + +func NewAppModuleBasic() AppModuleBasic { + return AppModuleBasic{} +} + +// Name returns the x/tokenfactory module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the x/tokenfactory module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the x/tokenfactory module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) //nolint:errcheck +} + +// GetTxCmd returns the x/tokenfactory module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the x/tokenfactory module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper +} + +func NewAppModule( + keeper keeper.Keeper, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(), + keeper: keeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + } +} + +// Name returns the x/tokenfactory module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the x/tokenfactory module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute returns the x/tokenfactory module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// LegacyQuerierHandler returns the x/tokenfactory module's Querier. +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the x/tokenfactory module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the x/tokenfactory module's genesis initialization. It +// returns no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + cdc.MustUnmarshalJSON(gs, &genState) + + am.keeper.InitGenesis(ctx, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the x/tokenfactory module's exported genesis state as raw +// JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the tokenfactory module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock executes all ABCI EndBlock logic respective to the tokenfactory module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// ___________________________________________________________________________ + +// AppModuleSimulationV2 functions + +// // GenerateGenesisState creates a randomized GenState of the tokenfactory module. +// func (am AppModule) SimulatorGenesisState(simState *module.SimulationState, s *simtypes.SimCtx) { +// tfDefaultGen := types.DefaultGenesis() +// tfDefaultGen.Params.DenomCreationFee = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10000000))) +// tfDefaultGenJson := simState.Cdc.MustMarshalJSON(tfDefaultGen) +// simState.GenState[types.ModuleName] = tfDefaultGenJson +// } + +// // WeightedOperations returns the all the lockup module operations with their respective weights. +// func (am AppModule) Actions() []simtypes.Action { +// return []simtypes.Action{ +// simtypes.NewMsgBasedAction("create token factory token", am.keeper, simulation.RandomMsgCreateDenom), +// simtypes.NewMsgBasedAction("mint token factory token", am.keeper, simulation.RandomMsgMintDenom), +// simtypes.NewMsgBasedAction("burn token factory token", am.keeper, simulation.RandomMsgBurnDenom), +// simtypes.NewMsgBasedAction("change admin token factory token", am.keeper, simulation.RandomMsgChangeAdmin), +// } +// } + +// ____________________________________________________________________________ + +// AppModuleSimulation functions +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// GenerateGenesisState creates a randomized GenState of the bank module. +func (am AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized bank param changes for the simulator. +func (am AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for supply module's types +func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { +} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations(&simState, am.keeper, am.accountKeeper, am.bankKeeper) +} diff --git a/x/tokenfactory/simulation/genesis.go b/x/tokenfactory/simulation/genesis.go new file mode 100644 index 000000000..d839fad40 --- /dev/null +++ b/x/tokenfactory/simulation/genesis.go @@ -0,0 +1,25 @@ +package simulation + +import ( + "math/rand" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" +) + +func RandDenomCreationFeeParam(r *rand.Rand) sdk.Coins { + amount := r.Int63n(10_000_000) + return sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(amount))) +} + +func RandomizedGenState(simstate *module.SimulationState) { + tfGenesis := types.DefaultGenesis() + + _, err := simstate.Cdc.MarshalJSON(tfGenesis) + if err != nil { + panic(err) + } + + simstate.GenState[types.ModuleName] = simstate.Cdc.MustMarshalJSON(tfGenesis) +} diff --git a/x/tokenfactory/simulation/operations.go b/x/tokenfactory/simulation/operations.go new file mode 100644 index 000000000..87e70653b --- /dev/null +++ b/x/tokenfactory/simulation/operations.go @@ -0,0 +1,411 @@ +package simulation + +import ( + "math/rand" + + "github.com/CosmosTokenFactory/token-factory/app/params" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + "github.com/cosmos/cosmos-sdk/baseapp" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation operation weights constants +// +//nolint:gosec +const ( + OpWeightMsgCreateDenom = "op_weight_msg_create_denom" + OpWeightMsgMint = "op_weight_msg_mint" + OpWeightMsgBurn = "op_weight_msg_burn" + OpWeightMsgChangeAdmin = "op_weight_msg_change_admin" + OpWeightMsgSetDenomMetadata = "op_weight_msg_set_denom_metadata" + OpWeightMsgForceTransfer = "op_weight_msg_force_transfer" +) + +type TokenfactoryKeeper interface { + GetParams(ctx sdk.Context) (params types.Params) + GetAuthorityMetadata(ctx sdk.Context, denom string) (types.DenomAuthorityMetadata, error) + GetAllDenomsIterator(ctx sdk.Context) sdk.Iterator + GetDenomsFromCreator(ctx sdk.Context, creator string) []string +} + +type BankKeeper interface { + simulation.BankKeeper + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin +} + +func WeightedOperations( + simstate *module.SimulationState, + tfKeeper TokenfactoryKeeper, + ak types.AccountKeeper, + bk BankKeeper, +) simulation.WeightedOperations { + var ( + weightMsgCreateDenom int + weightMsgMint int + weightMsgBurn int + weightMsgChangeAdmin int + weightMsgSetDenomMetadata int + weightMsgForceTransfer int + ) + + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgCreateDenom, &weightMsgCreateDenom, nil, + func(_ *rand.Rand) { + weightMsgCreateDenom = params.DefaultWeightMsgCreateDenom + }, + ) + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgMint, &weightMsgMint, nil, + func(_ *rand.Rand) { + weightMsgMint = params.DefaultWeightMsgMint + }, + ) + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgBurn, &weightMsgBurn, nil, + func(_ *rand.Rand) { + weightMsgBurn = params.DefaultWeightMsgBurn + }, + ) + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgChangeAdmin, &weightMsgChangeAdmin, nil, + func(_ *rand.Rand) { + weightMsgChangeAdmin = params.DefaultWeightMsgChangeAdmin + }, + ) + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgSetDenomMetadata, &weightMsgSetDenomMetadata, nil, + func(_ *rand.Rand) { + weightMsgSetDenomMetadata = params.DefaultWeightMsgSetDenomMetadata + }, + ) + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgForceTransfer, &weightMsgForceTransfer, nil, + func(_ *rand.Rand) { + weightMsgForceTransfer = params.DefaultWeightMsgForceTransfer + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgCreateDenom, + SimulateMsgCreateDenom( + tfKeeper, + ak, + bk, + ), + ), + simulation.NewWeightedOperation( + weightMsgMint, + SimulateMsgMint( + tfKeeper, + ak, + bk, + DefaultSimulationDenomSelector, + ), + ), + simulation.NewWeightedOperation( + weightMsgBurn, + SimulateMsgBurn( + tfKeeper, + ak, + bk, + DefaultSimulationDenomSelector, + ), + ), + simulation.NewWeightedOperation( + weightMsgChangeAdmin, + SimulateMsgChangeAdmin( + tfKeeper, + ak, + bk, + DefaultSimulationDenomSelector, + ), + ), + simulation.NewWeightedOperation( + weightMsgSetDenomMetadata, + SimulateMsgSetDenomMetadata( + tfKeeper, + ak, + bk, + DefaultSimulationDenomSelector, + ), + ), + } +} + +type DenomSelector = func(*rand.Rand, sdk.Context, TokenfactoryKeeper, string) (string, bool) + +func DefaultSimulationDenomSelector(r *rand.Rand, ctx sdk.Context, tfKeeper TokenfactoryKeeper, creator string) (string, bool) { + denoms := tfKeeper.GetDenomsFromCreator(ctx, creator) + if len(denoms) == 0 { + return "", false + } + randPos := r.Intn(len(denoms)) + + return denoms[randPos], true +} + +func SimulateMsgSetDenomMetadata( + tfKeeper TokenfactoryKeeper, + ak types.AccountKeeper, + bk BankKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgSetDenomMetadata{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.GetAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgSetDenomMetadata{}.Type(), "err authority metadata"), nil, err + } + adminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgSetDenomMetadata{}.Type(), "admin account not found"), nil, nil + } + + metadata := banktypes.Metadata{ + Description: simtypes.RandStringOfLength(r, 10), + DenomUnits: []*banktypes.DenomUnit{{ + Denom: denom, + Exponent: 0, + }}, + Base: denom, + Display: denom, + Name: simtypes.RandStringOfLength(r, 10), + Symbol: simtypes.RandStringOfLength(r, 10), + } + + msg := types.MsgSetDenomMetadata{ + Sender: adminAccount.Address.String(), + Metadata: metadata, + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, adminAccount, ak, bk, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +func SimulateMsgChangeAdmin( + tfKeeper TokenfactoryKeeper, + ak types.AccountKeeper, + bk BankKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.GetAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "err authority metadata"), nil, err + } + curAdminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "admin account not found"), nil, nil + } + + // Rand new admin account + newAdmin, _ := simtypes.RandomAcc(r, accs) + if newAdmin.Address.String() == curAdminAccount.Address.String() { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "new admin cannot be the same as current admin"), nil, nil + } + + // Create msg + msg := types.MsgChangeAdmin{ + Sender: curAdminAccount.Address.String(), + Denom: denom, + NewAdmin: newAdmin.Address.String(), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, curAdminAccount, ak, bk, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +func SimulateMsgBurn( + tfKeeper TokenfactoryKeeper, + ak types.AccountKeeper, + bk BankKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.GetAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "err authority metadata"), nil, err + } + adminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "admin account not found"), nil, nil + } + + // Check if admin account balance = 0 + accountBalance := bk.GetBalance(ctx, adminAccount.Address, denom) + if accountBalance.Amount.LTE(sdk.ZeroInt()) { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "sim account have no balance"), nil, nil + } + + // Rand burn amount + amount, _ := simtypes.RandPositiveInt(r, accountBalance.Amount) + burnAmount := sdk.NewCoin(denom, amount) + + // Create msg + msg := types.MsgBurn{ + Sender: adminAccount.Address.String(), + Amount: burnAmount, + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, adminAccount, ak, bk, sdk.NewCoins(burnAmount)) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +// Simulate msg mint denom +func SimulateMsgMint( + tfKeeper TokenfactoryKeeper, + ak types.AccountKeeper, + bk BankKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgMint{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.GetAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgMint{}.Type(), "err authority metadata"), nil, err + } + adminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgMint{}.Type(), "admin account not found"), nil, nil + } + + // Rand mint amount + mintAmount, _ := simtypes.RandPositiveInt(r, sdk.NewIntFromUint64(100_000_000)) + + // Create msg mint + msg := types.MsgMint{ + Sender: adminAccount.Address.String(), + Amount: sdk.NewCoin(denom, mintAmount), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, adminAccount, ak, bk, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +// Simulate msg create denom +func SimulateMsgCreateDenom(tfKeeper TokenfactoryKeeper, ak types.AccountKeeper, bk BankKeeper) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get sims account + simAccount, _ := simtypes.RandomAcc(r, accs) + + // Check if sims account enough create fee + createFee := tfKeeper.GetParams(ctx).DenomCreationFee + balances := bk.GetAllBalances(ctx, simAccount.Address) + _, hasNeg := balances.SafeSub(createFee) + if hasNeg { + return simtypes.NoOpMsg(types.ModuleName, types.MsgCreateDenom{}.Type(), "Creator not enough creation fee"), nil, nil + } + + // Create msg create denom + msg := types.MsgCreateDenom{ + Sender: simAccount.Address.String(), + Subdenom: simtypes.RandStringOfLength(r, 10), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, bk, createFee) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +// BuildOperationInput helper to build object +func BuildOperationInput( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + msg interface { + sdk.Msg + Type() string + }, + simAccount simtypes.Account, + ak types.AccountKeeper, + bk BankKeeper, + deposit sdk.Coins, +) simulation.OperationInput { + return simulation.OperationInput{ + R: r, + App: app, + TxGen: simappparams.MakeTestEncodingConfig().TxConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: deposit, + } +} diff --git a/x/tokenfactory/simulation/params.go b/x/tokenfactory/simulation/params.go new file mode 100644 index 000000000..001a55c09 --- /dev/null +++ b/x/tokenfactory/simulation/params.go @@ -0,0 +1,23 @@ +package simulation + +import ( + "fmt" + "math/rand" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +func ParamChanges(_ *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{ + simulation.NewSimParamChange( + types.ModuleName, + string(types.KeyDenomCreationFee), + func(r *rand.Rand) string { + amount := RandDenomCreationFeeParam(r) + return fmt.Sprintf("[{\"denom\":\"%v\",\"amount\":\"%v\"}]", amount[0].Denom, amount[0].Amount) + }, + ), + } +} diff --git a/x/tokenfactory/testhelpers/consts.go b/x/tokenfactory/testhelpers/consts.go new file mode 100644 index 000000000..d7804a372 --- /dev/null +++ b/x/tokenfactory/testhelpers/consts.go @@ -0,0 +1,8 @@ +package testhelpers + +import sdk "github.com/cosmos/cosmos-sdk/types" + +var ( + SecondaryDenom = "uion" + SecondaryAmount = sdk.NewInt(100000000) +) diff --git a/x/tokenfactory/testhelpers/suite.go b/x/tokenfactory/testhelpers/suite.go new file mode 100644 index 000000000..7df45ad15 --- /dev/null +++ b/x/tokenfactory/testhelpers/suite.go @@ -0,0 +1,66 @@ +package testhelpers + +import ( + "encoding/json" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + Amino = codec.NewLegacyAmino() + AuthzModuleCdc = codec.NewAminoCodec(Amino) +) + +func init() { + cryptocodec.RegisterCrypto(Amino) + codec.RegisterEvidences(Amino) + sdk.RegisterLegacyAminoCodec(Amino) +} + +func TestMessageAuthzSerialization(t *testing.T, msg sdk.Msg) { + someDate := time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC) + const ( + mockGranter string = "cosmos1abc" + mockGrantee string = "cosmos1xyz" + ) + + var ( + mockMsgGrant authz.MsgGrant + mockMsgRevoke authz.MsgRevoke + mockMsgExec authz.MsgExec + ) + + // Authz: Grant Msg + typeURL := sdk.MsgTypeURL(msg) + later := someDate.Add(time.Hour) + grant, err := authz.NewGrant(authz.NewGenericAuthorization(typeURL), later) + require.NoError(t, err) + + msgGrant := authz.MsgGrant{Granter: mockGranter, Grantee: mockGrantee, Grant: grant} + msgGrantBytes := json.RawMessage(sdk.MustSortJSON(AuthzModuleCdc.MustMarshalJSON(&msgGrant))) + err = AuthzModuleCdc.UnmarshalJSON(msgGrantBytes, &mockMsgGrant) + require.NoError(t, err) + + // Authz: Revoke Msg + msgRevoke := authz.MsgRevoke{Granter: mockGranter, Grantee: mockGrantee, MsgTypeUrl: typeURL} + msgRevokeByte := json.RawMessage(sdk.MustSortJSON(AuthzModuleCdc.MustMarshalJSON(&msgRevoke))) + err = AuthzModuleCdc.UnmarshalJSON(msgRevokeByte, &mockMsgRevoke) + require.NoError(t, err) + + // Authz: Exec Msg + msgAny, err := cdctypes.NewAnyWithValue(msg) + require.NoError(t, err) + msgExec := authz.MsgExec{Grantee: mockGrantee, Msgs: []*cdctypes.Any{msgAny}} + execMsgByte := json.RawMessage(sdk.MustSortJSON(AuthzModuleCdc.MustMarshalJSON(&msgExec))) + err = AuthzModuleCdc.UnmarshalJSON(execMsgByte, &mockMsgExec) + require.NoError(t, err) + require.Equal(t, msgExec.Msgs[0].Value, mockMsgExec.Msgs[0].Value) +} diff --git a/x/tokenfactory/types/authorityMetadata.go b/x/tokenfactory/types/authorityMetadata.go new file mode 100644 index 000000000..b45bffcab --- /dev/null +++ b/x/tokenfactory/types/authorityMetadata.go @@ -0,0 +1,15 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (metadata DenomAuthorityMetadata) Validate() error { + if metadata.Admin != "" { + _, err := sdk.AccAddressFromBech32(metadata.Admin) + if err != nil { + return err + } + } + return nil +} diff --git a/x/tokenfactory/types/authorityMetadata.pb.go b/x/tokenfactory/types/authorityMetadata.pb.go new file mode 100644 index 000000000..d8df78772 --- /dev/null +++ b/x/tokenfactory/types/authorityMetadata.pb.go @@ -0,0 +1,351 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/tokenfactory/v1beta1/authorityMetadata.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// DenomAuthorityMetadata specifies metadata for addresses that have specific +// capabilities over a token factory denom. Right now there is only one Admin +// permission, but is planned to be extended to the future. +type DenomAuthorityMetadata struct { + // Can be empty for no admin, or a valid osmosis address + Admin string `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty" yaml:"admin"` +} + +func (m *DenomAuthorityMetadata) Reset() { *m = DenomAuthorityMetadata{} } +func (m *DenomAuthorityMetadata) String() string { return proto.CompactTextString(m) } +func (*DenomAuthorityMetadata) ProtoMessage() {} +func (*DenomAuthorityMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_99435de88ae175f7, []int{0} +} +func (m *DenomAuthorityMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DenomAuthorityMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DenomAuthorityMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DenomAuthorityMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_DenomAuthorityMetadata.Merge(m, src) +} +func (m *DenomAuthorityMetadata) XXX_Size() int { + return m.Size() +} +func (m *DenomAuthorityMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_DenomAuthorityMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_DenomAuthorityMetadata proto.InternalMessageInfo + +func (m *DenomAuthorityMetadata) GetAdmin() string { + if m != nil { + return m.Admin + } + return "" +} + +func init() { + proto.RegisterType((*DenomAuthorityMetadata)(nil), "osmosis.tokenfactory.v1beta1.DenomAuthorityMetadata") +} + +func init() { + proto.RegisterFile("osmosis/tokenfactory/v1beta1/authorityMetadata.proto", fileDescriptor_99435de88ae175f7) +} + +var fileDescriptor_99435de88ae175f7 = []byte{ + // 240 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xc9, 0x2f, 0xce, 0xcd, + 0x2f, 0xce, 0x2c, 0xd6, 0x2f, 0xc9, 0xcf, 0x4e, 0xcd, 0x4b, 0x4b, 0x4c, 0x2e, 0xc9, 0x2f, 0xaa, + 0xd4, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x2c, 0x2d, 0xc9, 0xc8, 0x2f, 0xca, + 0x2c, 0xa9, 0xf4, 0x4d, 0x2d, 0x49, 0x4c, 0x49, 0x2c, 0x49, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, + 0x17, 0x92, 0x81, 0xea, 0xd2, 0x43, 0xd6, 0xa5, 0x07, 0xd5, 0x25, 0x25, 0x92, 0x9e, 0x9f, 0x9e, + 0x0f, 0x56, 0xa8, 0x0f, 0x62, 0x41, 0xf4, 0x48, 0xc9, 0x25, 0x83, 0x35, 0xe9, 0x27, 0x25, 0x16, + 0xa7, 0xc2, 0x2d, 0x48, 0xce, 0xcf, 0xcc, 0x83, 0xc8, 0x2b, 0xb9, 0x71, 0x89, 0xb9, 0xa4, 0xe6, + 0xe5, 0xe7, 0x3a, 0xa2, 0xdb, 0x29, 0xa4, 0xc6, 0xc5, 0x9a, 0x98, 0x92, 0x9b, 0x99, 0x27, 0xc1, + 0xa8, 0xc0, 0xa8, 0xc1, 0xe9, 0x24, 0xf0, 0xe9, 0x9e, 0x3c, 0x4f, 0x65, 0x62, 0x6e, 0x8e, 0x95, + 0x12, 0x58, 0x58, 0x29, 0x08, 0x22, 0x6d, 0xc5, 0xf2, 0x62, 0x81, 0x3c, 0xa3, 0x53, 0xd4, 0x89, + 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, + 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x39, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, + 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x3b, 0x83, 0x1d, 0x13, 0x02, 0x72, 0xbe, 0x1b, 0xd4, 0xd3, 0x60, + 0xbf, 0xe8, 0xc2, 0x82, 0xa0, 0x02, 0x35, 0x44, 0x4a, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, + 0x4e, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5d, 0xdc, 0xc5, 0x01, 0x36, 0x01, 0x00, 0x00, +} + +func (this *DenomAuthorityMetadata) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*DenomAuthorityMetadata) + if !ok { + that2, ok := that.(DenomAuthorityMetadata) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Admin != that1.Admin { + return false + } + return true +} +func (m *DenomAuthorityMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DenomAuthorityMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DenomAuthorityMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintAuthorityMetadata(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthorityMetadata(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthorityMetadata(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *DenomAuthorityMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovAuthorityMetadata(uint64(l)) + } + return n +} + +func sovAuthorityMetadata(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthorityMetadata(x uint64) (n int) { + return sovAuthorityMetadata(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *DenomAuthorityMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DenomAuthorityMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DenomAuthorityMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthorityMetadata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthorityMetadata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthorityMetadata(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthorityMetadata + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthorityMetadata(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthorityMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthorityMetadata + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthorityMetadata + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthorityMetadata + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthorityMetadata = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthorityMetadata = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthorityMetadata = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/authzcodec/codec.go b/x/tokenfactory/types/authzcodec/codec.go new file mode 100644 index 000000000..366e337a1 --- /dev/null +++ b/x/tokenfactory/types/authzcodec/codec.go @@ -0,0 +1,24 @@ +package authzcodec + +// Note: this file is a copy from authz/codec in 0.46 so we can be compatible with 0.45 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(Amino) +) + +func init() { + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(Amino) + cryptocodec.RegisterCrypto(Amino) + codec.RegisterEvidences(Amino) + + Amino.Seal() +} diff --git a/x/tokenfactory/types/capabilities.go b/x/tokenfactory/types/capabilities.go new file mode 100644 index 000000000..bda91c950 --- /dev/null +++ b/x/tokenfactory/types/capabilities.go @@ -0,0 +1,21 @@ +package types + +const ( + EnableSetMetadata = "enable_metadata" + EnableForceTransfer = "enable_force_transfer" + EnableBurnFrom = "enable_burn_from" +) + +func IsCapabilityEnabled(enabledCapabilities []string, capability string) bool { + if len(enabledCapabilities) == 0 { + return true + } + + for _, v := range enabledCapabilities { + if v == capability { + return true + } + } + + return false +} diff --git a/x/tokenfactory/types/codec.go b/x/tokenfactory/types/codec.go new file mode 100644 index 000000000..8984dd89e --- /dev/null +++ b/x/tokenfactory/types/codec.go @@ -0,0 +1,48 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + // this line is used by starport scaffolding # 1 + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgCreateDenom{}, "osmosis/tokenfactory/create-denom", nil) + cdc.RegisterConcrete(&MsgMint{}, "osmosis/tokenfactory/mint", nil) + cdc.RegisterConcrete(&MsgBurn{}, "osmosis/tokenfactory/burn", nil) + cdc.RegisterConcrete(&MsgForceTransfer{}, "osmosis/tokenfactory/force-transfer", nil) + cdc.RegisterConcrete(&MsgChangeAdmin{}, "osmosis/tokenfactory/change-admin", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgCreateDenom{}, + &MsgMint{}, + &MsgBurn{}, + // &MsgForceTransfer{}, + &MsgChangeAdmin{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) + +func init() { + RegisterCodec(amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + // Note: these 3 are inlines from authz/codec in 0.46 so we can be compatible with 0.45 + sdk.RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + codec.RegisterEvidences(amino) + + amino.Seal() +} diff --git a/x/tokenfactory/types/denoms.go b/x/tokenfactory/types/denoms.go new file mode 100644 index 000000000..7a9f2f9e9 --- /dev/null +++ b/x/tokenfactory/types/denoms.go @@ -0,0 +1,68 @@ +package types + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + ModuleDenomPrefix = "factory" + // See the TokenFactory readme for a derivation of these. + // TL;DR, MaxSubdenomLength + MaxHrpLength = 60 comes from SDK max denom length = 128 + // and the structure of tokenfactory denoms. + MaxSubdenomLength = 44 + MaxHrpLength = 16 + // MaxCreatorLength = 59 + MaxHrpLength + MaxCreatorLength = 59 + MaxHrpLength +) + +// GetTokenDenom constructs a denom string for tokens created by tokenfactory +// based on an input creator address and a subdenom +// The denom constructed is factory/{creator}/{subdenom} +func GetTokenDenom(creator, subdenom string) (string, error) { + if len(subdenom) > MaxSubdenomLength { + return "", ErrSubdenomTooLong + } + if len(creator) > MaxCreatorLength { + return "", ErrCreatorTooLong + } + if strings.Contains(creator, "/") { + return "", ErrInvalidCreator + } + denom := strings.Join([]string{ModuleDenomPrefix, creator, subdenom}, "/") + return denom, sdk.ValidateDenom(denom) +} + +// DeconstructDenom takes a token denom string and verifies that it is a valid +// denom of the tokenfactory module, and is of the form `factory/{creator}/{subdenom}` +// If valid, it returns the creator address and subdenom +func DeconstructDenom(denom string) (creator string, subdenom string, err error) { + err = sdk.ValidateDenom(denom) + if err != nil { + return "", "", err + } + + strParts := strings.Split(denom, "/") + if len(strParts) < 3 { + return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "not enough parts of denom %s", denom) + } + + if strParts[0] != ModuleDenomPrefix { + return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "denom prefix is incorrect. Is: %s. Should be: %s", strParts[0], ModuleDenomPrefix) + } + + creator = strParts[1] + creatorAddr, err := sdk.AccAddressFromBech32(creator) + if err != nil { + return "", "", sdkerrors.Wrapf(ErrInvalidDenom, "Invalid creator address (%s)", err) + } + + // Handle the case where a denom has a slash in its subdenom. For example, + // when we did the split, we'd turn factory/accaddr/atomderivative/sikka into ["factory", "accaddr", "atomderivative", "sikka"] + // So we have to join [2:] with a "/" as the delimiter to get back the correct subdenom which should be "atomderivative/sikka" + subdenom = strings.Join(strParts[2:], "/") + + return creatorAddr.String(), subdenom, nil +} diff --git a/x/tokenfactory/types/denoms_test.go b/x/tokenfactory/types/denoms_test.go new file mode 100644 index 000000000..a4395f59a --- /dev/null +++ b/x/tokenfactory/types/denoms_test.go @@ -0,0 +1,132 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func TestDeconstructDenom(t *testing.T) { + // Note: this seems to be used in osmosis to add some more checks (only 20 or 32 byte addresses), + // which is good, but not required for these tests as they make code less reuable + // appparams.SetAddressPrefixes() + + for _, tc := range []struct { + desc string + denom string + expectedSubdenom string + err error + }{ + { + desc: "empty is invalid", + denom: "", + err: types.ErrInvalidDenom, + }, + { + desc: "normal", + denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + expectedSubdenom: "bitcoin", + }, + { + desc: "multiple slashes in subdenom", + denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin/1", + expectedSubdenom: "bitcoin/1", + }, + { + desc: "no subdenom", + denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/", + expectedSubdenom: "", + }, + { + desc: "incorrect prefix", + denom: "ibc/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + err: types.ErrInvalidDenom, + }, + { + desc: "subdenom of only slashes", + denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/////", + expectedSubdenom: "////", + }, + { + desc: "too long name", + denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/adsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsf", + err: types.ErrInvalidDenom, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + expectedCreator := "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8" + creator, subdenom, err := types.DeconstructDenom(tc.denom) + if tc.err != nil { + require.ErrorContains(t, err, tc.err.Error()) + } else { + require.NoError(t, err) + require.Equal(t, expectedCreator, creator) + require.Equal(t, tc.expectedSubdenom, subdenom) + } + }) + } +} + +func TestGetTokenDenom(t *testing.T) { + // appparams.SetAddressPrefixes() + for _, tc := range []struct { + desc string + creator string + subdenom string + valid bool + }{ + { + desc: "normal", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + subdenom: "bitcoin", + valid: true, + }, + { + desc: "multiple slashes in subdenom", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + subdenom: "bitcoin/1", + valid: true, + }, + { + desc: "no subdenom", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + subdenom: "", + valid: true, + }, + { + desc: "subdenom of only slashes", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + subdenom: "/////", + valid: true, + }, + { + desc: "too long name", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + subdenom: "adsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsfadsf", + valid: false, + }, + { + desc: "subdenom is exactly max length", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + subdenom: "bitcoinfsadfsdfeadfsafwefsefsefsdfsdafasefsf", + valid: true, + }, + { + desc: "creator is exactly max length", + creator: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8jhgjhgkhjklhkjhkjhgjhgjgjghelu", + subdenom: "bitcoin", + valid: true, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + _, err := types.GetTokenDenom(tc.creator, tc.subdenom) + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/tokenfactory/types/errors.go b/x/tokenfactory/types/errors.go new file mode 100644 index 000000000..d5e09de19 --- /dev/null +++ b/x/tokenfactory/types/errors.go @@ -0,0 +1,23 @@ +package types + +// DONTCOVER + +import ( + fmt "fmt" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// x/tokenfactory module sentinel errors +var ( + ErrDenomExists = sdkerrors.Register(ModuleName, 2, "attempting to create a denom that already exists (has bank metadata)") + ErrUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized account") + ErrInvalidDenom = sdkerrors.Register(ModuleName, 4, "invalid denom") + ErrInvalidCreator = sdkerrors.Register(ModuleName, 5, "invalid creator") + ErrInvalidAuthorityMetadata = sdkerrors.Register(ModuleName, 6, "invalid authority metadata") + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 7, "invalid genesis") + ErrSubdenomTooLong = sdkerrors.Register(ModuleName, 8, fmt.Sprintf("subdenom too long, max length is %d bytes", MaxSubdenomLength)) + ErrCreatorTooLong = sdkerrors.Register(ModuleName, 9, fmt.Sprintf("creator too long, max length is %d bytes", MaxCreatorLength)) + ErrDenomDoesNotExist = sdkerrors.Register(ModuleName, 10, "denom does not exist") + ErrCapabilityNotEnabled = sdkerrors.Register(ModuleName, 11, "this capability is not enabled on chain") +) diff --git a/x/tokenfactory/types/events.go b/x/tokenfactory/types/events.go new file mode 100644 index 000000000..602e06fab --- /dev/null +++ b/x/tokenfactory/types/events.go @@ -0,0 +1,18 @@ +package types + +// event types +// +//nolint:gosec +const ( + AttributeAmount = "amount" + AttributeCreator = "creator" + AttributeSubdenom = "subdenom" + AttributeNewTokenDenom = "new_token_denom" + AttributeMintToAddress = "mint_to_address" + AttributeBurnFromAddress = "burn_from_address" + AttributeTransferFromAddress = "transfer_from_address" + AttributeTransferToAddress = "transfer_to_address" + AttributeDenom = "denom" + AttributeNewAdmin = "new_admin" + AttributeDenomMetadata = "denom_metadata" +) diff --git a/x/tokenfactory/types/expected_keepers.go b/x/tokenfactory/types/expected_keepers.go new file mode 100644 index 000000000..5500dab76 --- /dev/null +++ b/x/tokenfactory/types/expected_keepers.go @@ -0,0 +1,38 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type BankKeeper interface { + // Methods imported from bank should be defined here + GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) + SetDenomMetaData(ctx sdk.Context, denomMetaData banktypes.Metadata) + + HasSupply(ctx sdk.Context, denom string) bool + + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + + BlockedAddr(addr sdk.AccAddress) bool +} + +type AccountKeeper interface { + SetModuleAccount(ctx sdk.Context, macc authtypes.ModuleAccountI) + GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI +} + +// CommunityPoolKeeper defines the contract needed to be fulfilled for community pool interactions. +type CommunityPoolKeeper interface { + FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error +} diff --git a/x/tokenfactory/types/genesis.go b/x/tokenfactory/types/genesis.go new file mode 100644 index 000000000..b1ba181fa --- /dev/null +++ b/x/tokenfactory/types/genesis.go @@ -0,0 +1,51 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// this line is used by starport scaffolding # genesis/types/import + +// DefaultIndex is the default capability global index +const DefaultIndex uint64 = 1 + +// DefaultGenesis returns the default Capability genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + FactoryDenoms: []GenesisDenom{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + err := gs.Params.Validate() + if err != nil { + return err + } + + seenDenoms := map[string]bool{} + + for _, denom := range gs.GetFactoryDenoms() { + if seenDenoms[denom.GetDenom()] { + return sdkerrors.Wrapf(ErrInvalidGenesis, "duplicate denom: %s", denom.GetDenom()) + } + seenDenoms[denom.GetDenom()] = true + + _, _, err := DeconstructDenom(denom.GetDenom()) + if err != nil { + return err + } + + if denom.AuthorityMetadata.Admin != "" { + _, err = sdk.AccAddressFromBech32(denom.AuthorityMetadata.Admin) + if err != nil { + return sdkerrors.Wrapf(ErrInvalidAuthorityMetadata, "Invalid admin address (%s)", err) + } + } + } + + return nil +} diff --git a/x/tokenfactory/types/genesis.pb.go b/x/tokenfactory/types/genesis.pb.go new file mode 100644 index 000000000..594a86ea9 --- /dev/null +++ b/x/tokenfactory/types/genesis.pb.go @@ -0,0 +1,649 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/tokenfactory/v1beta1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the tokenfactory module's genesis state. +type GenesisState struct { + // params defines the paramaters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + FactoryDenoms []GenesisDenom `protobuf:"bytes,2,rep,name=factory_denoms,json=factoryDenoms,proto3" json:"factory_denoms" yaml:"factory_denoms"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_5749c3f71850298b, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetFactoryDenoms() []GenesisDenom { + if m != nil { + return m.FactoryDenoms + } + return nil +} + +// GenesisDenom defines a tokenfactory denom that is defined within genesis +// state. The structure contains DenomAuthorityMetadata which defines the +// denom's admin. +type GenesisDenom struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + AuthorityMetadata DenomAuthorityMetadata `protobuf:"bytes,2,opt,name=authority_metadata,json=authorityMetadata,proto3" json:"authority_metadata" yaml:"authority_metadata"` +} + +func (m *GenesisDenom) Reset() { *m = GenesisDenom{} } +func (m *GenesisDenom) String() string { return proto.CompactTextString(m) } +func (*GenesisDenom) ProtoMessage() {} +func (*GenesisDenom) Descriptor() ([]byte, []int) { + return fileDescriptor_5749c3f71850298b, []int{1} +} +func (m *GenesisDenom) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisDenom) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisDenom.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisDenom) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisDenom.Merge(m, src) +} +func (m *GenesisDenom) XXX_Size() int { + return m.Size() +} +func (m *GenesisDenom) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisDenom.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisDenom proto.InternalMessageInfo + +func (m *GenesisDenom) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *GenesisDenom) GetAuthorityMetadata() DenomAuthorityMetadata { + if m != nil { + return m.AuthorityMetadata + } + return DenomAuthorityMetadata{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "osmosis.tokenfactory.v1beta1.GenesisState") + proto.RegisterType((*GenesisDenom)(nil), "osmosis.tokenfactory.v1beta1.GenesisDenom") +} + +func init() { + proto.RegisterFile("osmosis/tokenfactory/v1beta1/genesis.proto", fileDescriptor_5749c3f71850298b) +} + +var fileDescriptor_5749c3f71850298b = []byte{ + // 367 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xca, 0x2f, 0xce, 0xcd, + 0x2f, 0xce, 0x2c, 0xd6, 0x2f, 0xc9, 0xcf, 0x4e, 0xcd, 0x4b, 0x4b, 0x4c, 0x2e, 0xc9, 0x2f, 0xaa, + 0xd4, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, + 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x81, 0xaa, 0xd5, 0x43, 0x56, 0xab, 0x07, 0x55, + 0x2b, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x56, 0xa8, 0x0f, 0x62, 0x41, 0xf4, 0x48, 0x99, 0xe0, + 0x35, 0x3f, 0xb1, 0xb4, 0x24, 0x23, 0xbf, 0x28, 0xb3, 0xa4, 0xd2, 0x37, 0xb5, 0x24, 0x31, 0x25, + 0xb1, 0x24, 0x11, 0xaa, 0x4b, 0x13, 0xaf, 0xae, 0x82, 0xc4, 0xa2, 0xc4, 0x5c, 0xa8, 0xa3, 0x94, + 0x8e, 0x30, 0x72, 0xf1, 0xb8, 0x43, 0x9c, 0x19, 0x5c, 0x92, 0x58, 0x92, 0x2a, 0xe4, 0xc4, 0xc5, + 0x06, 0x51, 0x20, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0xa4, 0xa2, 0x87, 0xcf, 0xd9, 0x7a, 0x01, + 0x60, 0xb5, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x41, 0x75, 0x0a, 0x15, 0x70, 0xf1, 0x41, + 0xd5, 0xc5, 0xa7, 0xa4, 0xe6, 0xe5, 0xe7, 0x16, 0x4b, 0x30, 0x29, 0x30, 0x6b, 0x70, 0x1b, 0x69, + 0xe1, 0x37, 0x0b, 0xea, 0x0e, 0x17, 0x90, 0x16, 0x27, 0x59, 0x90, 0x89, 0x9f, 0xee, 0xc9, 0x8b, + 0x56, 0x26, 0xe6, 0xe6, 0x58, 0x29, 0xa1, 0x9a, 0xa7, 0x14, 0xc4, 0x0b, 0x15, 0x70, 0x81, 0xf0, + 0x8f, 0x22, 0xbc, 0x01, 0x16, 0x11, 0x52, 0xe3, 0x62, 0x05, 0x2b, 0x05, 0xfb, 0x82, 0xd3, 0x49, + 0xe0, 0xd3, 0x3d, 0x79, 0x1e, 0x88, 0x49, 0x60, 0x61, 0xa5, 0x20, 0x88, 0xb4, 0x50, 0x1b, 0x23, + 0x97, 0x10, 0x3c, 0x18, 0xe3, 0x73, 0xa1, 0xe1, 0x28, 0xc1, 0x04, 0xf6, 0xbb, 0x09, 0x7e, 0xf7, + 0x82, 0x6d, 0x72, 0x44, 0x8f, 0x03, 0x27, 0x45, 0xa8, 0xcb, 0x25, 0x21, 0xf6, 0x61, 0x9a, 0xae, + 0x14, 0x24, 0x88, 0x11, 0x73, 0x56, 0x2c, 0x2f, 0x16, 0xc8, 0x33, 0x3a, 0x45, 0x9d, 0x78, 0x24, + 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, + 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x43, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, + 0x72, 0x7e, 0xae, 0xbe, 0x33, 0xd8, 0x59, 0x21, 0x20, 0x37, 0xb9, 0x41, 0x23, 0x17, 0xec, 0x40, + 0x5d, 0x58, 0x54, 0x57, 0xa0, 0xc6, 0x7c, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x38, 0xc6, + 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x39, 0x70, 0x15, 0xb4, 0x02, 0x00, 0x00, +} + +func (this *GenesisDenom) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*GenesisDenom) + if !ok { + that2, ok := that.(GenesisDenom) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Denom != that1.Denom { + return false + } + if !this.AuthorityMetadata.Equal(&that1.AuthorityMetadata) { + return false + } + return true +} +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FactoryDenoms) > 0 { + for iNdEx := len(m.FactoryDenoms) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FactoryDenoms[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *GenesisDenom) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisDenom) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisDenom) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.AuthorityMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.FactoryDenoms) > 0 { + for _, e := range m.FactoryDenoms { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *GenesisDenom) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.AuthorityMetadata.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FactoryDenoms", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FactoryDenoms = append(m.FactoryDenoms, GenesisDenom{}) + if err := m.FactoryDenoms[len(m.FactoryDenoms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisDenom) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisDenom: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisDenom: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuthorityMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AuthorityMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/genesis_test.go b/x/tokenfactory/types/genesis_test.go new file mode 100644 index 000000000..7289c62fc --- /dev/null +++ b/x/tokenfactory/types/genesis_test.go @@ -0,0 +1,139 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" +) + +func TestGenesisState_Validate(t *testing.T) { + for _, tc := range []struct { + desc string + genState *types.GenesisState + valid bool + }{ + { + desc: "default is valid", + genState: types.DefaultGenesis(), + valid: true, + }, + { + desc: "valid genesis state", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8", + }, + }, + }, + }, + valid: true, + }, + { + desc: "different admin from creator", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "cosmos1ft6e5esdtdegnvcr3djd3ftk4kwpcr6jta8eyh", + }, + }, + }, + }, + valid: true, + }, + { + desc: "empty admin", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + }, + }, + valid: true, + }, + { + desc: "no admin", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + }, + }, + }, + valid: true, + }, + { + desc: "invalid admin", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "moose", + }, + }, + }, + }, + valid: false, + }, + { + desc: "multiple denoms", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/litecoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + }, + }, + valid: true, + }, + { + desc: "duplicate denoms", + genState: &types.GenesisState{ + FactoryDenoms: []types.GenesisDenom{ + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + { + Denom: "factory/cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8/bitcoin", + AuthorityMetadata: types.DenomAuthorityMetadata{ + Admin: "", + }, + }, + }, + }, + valid: false, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + err := tc.genState.Validate() + if tc.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/tokenfactory/types/keys.go b/x/tokenfactory/types/keys.go new file mode 100644 index 000000000..fac4a6e39 --- /dev/null +++ b/x/tokenfactory/types/keys.go @@ -0,0 +1,49 @@ +package types + +import ( + "strings" +) + +const ( + // ModuleName defines the module name + ModuleName = "tokenfactory" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey is the message route for slashing + RouterKey = ModuleName + + // QuerierRoute defines the module's query routing key + QuerierRoute = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_tokenfactory" +) + +// KeySeparator is used to combine parts of the keys in the store +const KeySeparator = "|" + +var ( + DenomAuthorityMetadataKey = "authoritymetadata" + DenomsPrefixKey = "denoms" + CreatorPrefixKey = "creator" + AdminPrefixKey = "admin" +) + +// GetDenomPrefixStore returns the store prefix where all the data associated with a specific denom +// is stored +func GetDenomPrefixStore(denom string) []byte { + return []byte(strings.Join([]string{DenomsPrefixKey, denom, ""}, KeySeparator)) +} + +// GetCreatorsPrefix returns the store prefix where the list of the denoms created by a specific +// creator are stored +func GetCreatorPrefix(creator string) []byte { + return []byte(strings.Join([]string{CreatorPrefixKey, creator, ""}, KeySeparator)) +} + +// GetCreatorsPrefix returns the store prefix where a list of all creator addresses are stored +func GetCreatorsPrefix() []byte { + return []byte(strings.Join([]string{CreatorPrefixKey, ""}, KeySeparator)) +} diff --git a/x/tokenfactory/types/msgs.go b/x/tokenfactory/types/msgs.go new file mode 100644 index 000000000..be5e8a716 --- /dev/null +++ b/x/tokenfactory/types/msgs.go @@ -0,0 +1,277 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// constants +const ( + TypeMsgCreateDenom = "create_denom" + TypeMsgMint = "tf_mint" + TypeMsgBurn = "tf_burn" + TypeMsgForceTransfer = "force_transfer" + TypeMsgChangeAdmin = "change_admin" + TypeMsgSetDenomMetadata = "set_denom_metadata" +) + +var _ sdk.Msg = &MsgCreateDenom{} + +// NewMsgCreateDenom creates a msg to create a new denom +func NewMsgCreateDenom(sender, subdenom string) *MsgCreateDenom { + return &MsgCreateDenom{ + Sender: sender, + Subdenom: subdenom, + } +} + +func (m MsgCreateDenom) Route() string { return RouterKey } +func (m MsgCreateDenom) Type() string { return TypeMsgCreateDenom } +func (m MsgCreateDenom) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + _, err = GetTokenDenom(m.Sender, m.Subdenom) + if err != nil { + return sdkerrors.Wrap(ErrInvalidDenom, err.Error()) + } + + return nil +} + +func (m MsgCreateDenom) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgCreateDenom) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgMint{} + +// NewMsgMint creates a message to mint tokens +func NewMsgMint(sender string, amount sdk.Coin) *MsgMint { + return &MsgMint{ + Sender: sender, + Amount: amount, + } +} + +func NewMsgMintTo(sender string, amount sdk.Coin, mintToAddress string) *MsgMint { + return &MsgMint{ + Sender: sender, + Amount: amount, + MintToAddress: mintToAddress, + } +} + +func (m MsgMint) Route() string { return RouterKey } +func (m MsgMint) Type() string { return TypeMsgMint } +func (m MsgMint) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if m.MintToAddress != "" { + _, err = sdk.AccAddressFromBech32(m.MintToAddress) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid mint to address (%s)", err) + } + } + + if !m.Amount.IsValid() || m.Amount.Amount.Equal(sdk.ZeroInt()) { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.Amount.String()) + } + + return nil +} + +func (m MsgMint) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgMint) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgBurn{} + +// NewMsgBurn creates a message to burn tokens +func NewMsgBurn(sender string, amount sdk.Coin) *MsgBurn { + return &MsgBurn{ + Sender: sender, + Amount: amount, + } +} + +// NewMsgBurn creates a message to burn tokens +func NewMsgBurnFrom(sender string, amount sdk.Coin, burnFromAddress string) *MsgBurn { + return &MsgBurn{ + Sender: sender, + Amount: amount, + BurnFromAddress: burnFromAddress, + } +} + +func (m MsgBurn) Route() string { return RouterKey } +func (m MsgBurn) Type() string { return TypeMsgBurn } +func (m MsgBurn) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if !m.Amount.IsValid() || m.Amount.Amount.Equal(sdk.ZeroInt()) { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.Amount.String()) + } + + if m.BurnFromAddress != "" { + _, err = sdk.AccAddressFromBech32(m.BurnFromAddress) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid burn from address (%s)", err) + } + } + + return nil +} + +func (m MsgBurn) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgBurn) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgForceTransfer{} + +// NewMsgForceTransfer creates a transfer funds from one account to another +func NewMsgForceTransfer(sender string, amount sdk.Coin, fromAddr, toAddr string) *MsgForceTransfer { + return &MsgForceTransfer{ + Sender: sender, + Amount: amount, + TransferFromAddress: fromAddr, + TransferToAddress: toAddr, + } +} + +func (m MsgForceTransfer) Route() string { return RouterKey } +func (m MsgForceTransfer) Type() string { return TypeMsgForceTransfer } +func (m MsgForceTransfer) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + _, err = sdk.AccAddressFromBech32(m.TransferFromAddress) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid from address (%s)", err) + } + _, err = sdk.AccAddressFromBech32(m.TransferToAddress) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid to address (%s)", err) + } + + if !m.Amount.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, m.Amount.String()) + } + + return nil +} + +func (m MsgForceTransfer) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgForceTransfer) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgChangeAdmin{} + +// NewMsgChangeAdmin creates a message to burn tokens +func NewMsgChangeAdmin(sender, denom, newAdmin string) *MsgChangeAdmin { + return &MsgChangeAdmin{ + Sender: sender, + Denom: denom, + NewAdmin: newAdmin, + } +} + +func (m MsgChangeAdmin) Route() string { return RouterKey } +func (m MsgChangeAdmin) Type() string { return TypeMsgChangeAdmin } +func (m MsgChangeAdmin) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + _, err = sdk.AccAddressFromBech32(m.NewAdmin) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid address (%s)", err) + } + + _, _, err = DeconstructDenom(m.Denom) + if err != nil { + return err + } + + return nil +} + +func (m MsgChangeAdmin) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgChangeAdmin) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} + +var _ sdk.Msg = &MsgSetDenomMetadata{} + +// NewMsgChangeAdmin creates a message to burn tokens +func NewMsgSetDenomMetadata(sender string, metadata banktypes.Metadata) *MsgSetDenomMetadata { + return &MsgSetDenomMetadata{ + Sender: sender, + Metadata: metadata, + } +} + +func (m MsgSetDenomMetadata) Route() string { return RouterKey } +func (m MsgSetDenomMetadata) Type() string { return TypeMsgSetDenomMetadata } +func (m MsgSetDenomMetadata) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + err = m.Metadata.Validate() + if err != nil { + return err + } + + _, _, err = DeconstructDenom(m.Metadata.Base) + if err != nil { + return err + } + + return nil +} + +func (m MsgSetDenomMetadata) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +func (m MsgSetDenomMetadata) GetSigners() []sdk.AccAddress { + sender, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{sender} +} diff --git a/x/tokenfactory/types/msgs_test.go b/x/tokenfactory/types/msgs_test.go new file mode 100644 index 000000000..d713e1ecf --- /dev/null +++ b/x/tokenfactory/types/msgs_test.go @@ -0,0 +1,451 @@ +package types_test + +import ( + fmt "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/testhelpers" + "github.com/CosmosTokenFactory/token-factory/x/tokenfactory/types" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/tendermint/tendermint/crypto/ed25519" +) + +// // Test authz serialize and de-serializes for tokenfactory msg. +func TestAuthzMsg(t *testing.T) { + t.Skip("TODO: figure out how to register authz interfaces for tests") + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()).String() + coin := sdk.NewCoin("denom", sdk.NewInt(1)) + + testCases := []struct { + name string + msg sdk.Msg + }{ + { + name: "MsgCreateDenom", + msg: &types.MsgCreateDenom{ + Sender: addr1, + Subdenom: "valoper1xyz", + }, + }, + { + name: "MsgBurn", + msg: &types.MsgBurn{ + Sender: addr1, + Amount: coin, + }, + }, + { + name: "MsgMint", + msg: &types.MsgMint{ + Sender: addr1, + Amount: coin, + }, + }, + { + name: "MsgChangeAdmin", + msg: &types.MsgChangeAdmin{ + Sender: addr1, + Denom: "denom", + NewAdmin: "osmo1q8tq5qhrhw6t970egemuuwywhlhpnmdmts6xnu", + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + testhelpers.TestMessageAuthzSerialization(t, tc.msg) + }) + } +} + +// TestMsgCreateDenom tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgCreateDenom(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + + // make a proper createDenom message + createMsg := func(after func(msg types.MsgCreateDenom) types.MsgCreateDenom) types.MsgCreateDenom { + properMsg := *types.NewMsgCreateDenom( + addr1.String(), + "bitcoin", + ) + + return after(properMsg) + } + + // validate createDenom message was created as intended + msg := createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + return msg + }) + require.Equal(t, msg.Route(), types.RouterKey) + require.Equal(t, msg.Type(), "create_denom") + signers := msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg types.MsgCreateDenom + expectPass bool + }{ + { + name: "proper msg", + msg: createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + return msg + }), + expectPass: true, + }, + { + name: "empty sender", + msg: createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + msg.Sender = "" + return msg + }), + expectPass: false, + }, + { + name: "invalid subdenom", + msg: createMsg(func(msg types.MsgCreateDenom) types.MsgCreateDenom { + msg.Subdenom = "thissubdenomismuchtoolongasdkfjaasdfdsafsdlkfnmlksadmflksmdlfmlsakmfdsafasdfasdf" + return msg + }), + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg.ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgMint tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgMint(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + + // make a proper mint message + createMsg := func(after func(msg types.MsgMint) types.MsgMint) types.MsgMint { + properMsg := *types.NewMsgMint( + addr1.String(), + sdk.NewCoin("bitcoin", sdk.NewInt(500000000)), + ) + + return after(properMsg) + } + + // validate mint message was created as intended + msg := createMsg(func(msg types.MsgMint) types.MsgMint { + return msg + }) + require.Equal(t, msg.Route(), types.RouterKey) + require.Equal(t, msg.Type(), "tf_mint") + signers := msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg types.MsgMint + expectPass bool + }{ + { + name: "proper msg", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + return msg + }), + expectPass: true, + }, + { + name: "empty sender", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + msg.Sender = "" + return msg + }), + expectPass: false, + }, + { + name: "zero amount", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + msg.Amount = sdk.NewCoin("bitcoin", sdk.ZeroInt()) + return msg + }), + expectPass: false, + }, + { + name: "negative amount", + msg: createMsg(func(msg types.MsgMint) types.MsgMint { + msg.Amount.Amount = sdk.NewInt(-10000000) + return msg + }), + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg.ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgBurn tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgBurn(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + + // make a proper burn message + baseMsg := types.NewMsgBurn( + addr1.String(), + sdk.NewCoin("bitcoin", sdk.NewInt(500000000)), + ) + + // validate burn message was created as intended + require.Equal(t, baseMsg.Route(), types.RouterKey) + require.Equal(t, baseMsg.Type(), "tf_burn") + signers := baseMsg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg func() *types.MsgBurn + expectPass bool + }{ + { + name: "proper msg", + msg: func() *types.MsgBurn { + msg := baseMsg + return msg + }, + expectPass: true, + }, + { + name: "empty sender", + msg: func() *types.MsgBurn { + msg := baseMsg + msg.Sender = "" + return msg + }, + expectPass: false, + }, + { + name: "zero amount", + msg: func() *types.MsgBurn { + msg := baseMsg + msg.Amount.Amount = sdk.ZeroInt() + return msg + }, + expectPass: false, + }, + { + name: "negative amount", + msg: func() *types.MsgBurn { + msg := baseMsg + msg.Amount.Amount = sdk.NewInt(-10000000) + return msg + }, + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg().ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg().ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgChangeAdmin tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgChangeAdmin(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + pk2 := ed25519.GenPrivKey().PubKey() + addr2 := sdk.AccAddress(pk2.Address()) + tokenFactoryDenom := fmt.Sprintf("factory/%s/bitcoin", addr1.String()) + + // make a proper changeAdmin message + baseMsg := types.NewMsgChangeAdmin( + addr1.String(), + tokenFactoryDenom, + addr2.String(), + ) + + // validate changeAdmin message was created as intended + require.Equal(t, baseMsg.Route(), types.RouterKey) + require.Equal(t, baseMsg.Type(), "change_admin") + signers := baseMsg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg func() *types.MsgChangeAdmin + expectPass bool + }{ + { + name: "proper msg", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + return msg + }, + expectPass: true, + }, + { + name: "empty sender", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + msg.Sender = "" + return msg + }, + expectPass: false, + }, + { + name: "empty newAdmin", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + msg.NewAdmin = "" + return msg + }, + expectPass: false, + }, + { + name: "invalid denom", + msg: func() *types.MsgChangeAdmin { + msg := baseMsg + msg.Denom = "bitcoin" + return msg + }, + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg().ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg().ValidateBasic(), "test: %v", test.name) + } + } +} + +// TestMsgSetDenomMetadata tests if valid/invalid create denom messages are properly validated/invalidated +func TestMsgSetDenomMetadata(t *testing.T) { + // generate a private/public key pair and get the respective address + pk1 := ed25519.GenPrivKey().PubKey() + addr1 := sdk.AccAddress(pk1.Address()) + tokenFactoryDenom := fmt.Sprintf("factory/%s/bitcoin", addr1.String()) + denomMetadata := banktypes.Metadata{ + Description: "nakamoto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: tokenFactoryDenom, + Exponent: 0, + }, + { + Denom: "sats", + Exponent: 6, + }, + }, + Display: "sats", + Base: tokenFactoryDenom, + Name: "bitcoin", + Symbol: "BTC", + } + invalidDenomMetadata := banktypes.Metadata{ + Description: "nakamoto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "bitcoin", + Exponent: 0, + }, + { + Denom: "sats", + Exponent: 6, + }, + }, + Display: "sats", + Base: "bitcoin", + Name: "bitcoin", + Symbol: "BTC", + } + + // make a proper setDenomMetadata message + baseMsg := types.NewMsgSetDenomMetadata( + addr1.String(), + denomMetadata, + ) + + // validate setDenomMetadata message was created as intended + require.Equal(t, baseMsg.Route(), types.RouterKey) + require.Equal(t, baseMsg.Type(), "set_denom_metadata") + signers := baseMsg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), addr1.String()) + + tests := []struct { + name string + msg func() *types.MsgSetDenomMetadata + expectPass bool + }{ + { + name: "proper msg", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + return msg + }, + expectPass: true, + }, + { + name: "empty sender", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + msg.Sender = "" + return msg + }, + expectPass: false, + }, + { + name: "invalid metadata", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + msg.Metadata.Name = "" + return msg + }, + + expectPass: false, + }, + { + name: "invalid base", + msg: func() *types.MsgSetDenomMetadata { + msg := baseMsg + msg.Metadata = invalidDenomMetadata + return msg + }, + expectPass: false, + }, + } + + for _, test := range tests { + if test.expectPass { + require.NoError(t, test.msg().ValidateBasic(), "test: %v", test.name) + } else { + require.Error(t, test.msg().ValidateBasic(), "test: %v", test.name) + } + } +} diff --git a/x/tokenfactory/types/params.go b/x/tokenfactory/types/params.go new file mode 100644 index 000000000..cf481ba84 --- /dev/null +++ b/x/tokenfactory/types/params.go @@ -0,0 +1,70 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +// Parameter store keys. +var ( + KeyDenomCreationFee = []byte("DenomCreationFee") + KeyDenomCreationGasConsume = []byte("DenomCreationGasConsume") +) + +// ParamTable for tokenfactory module. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +func NewParams(denomCreationFee sdk.Coins) Params { + return Params{ + DenomCreationFee: denomCreationFee, + } +} + +// default tokenfactory module parameters. +func DefaultParams() Params { + return Params{ + DenomCreationFee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10_000_000)), + DenomCreationGasConsume: 2_000_000, + } +} + +// validate params. +func (p Params) Validate() error { + err := validateDenomCreationFee(p.DenomCreationFee) + + return err +} + +// Implements params.ParamSet. +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyDenomCreationFee, &p.DenomCreationFee, validateDenomCreationFee), + paramtypes.NewParamSetPair(KeyDenomCreationGasConsume, &p.DenomCreationGasConsume, validateDenomCreationFeeGasConsume), + } +} + +func validateDenomCreationFee(i interface{}) error { + v, ok := i.(sdk.Coins) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.Validate() != nil { + return fmt.Errorf("invalid denom creation fee: %+v", i) + } + + return nil +} + +func validateDenomCreationFeeGasConsume(i interface{}) error { + _, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} diff --git a/x/tokenfactory/types/params.pb.go b/x/tokenfactory/types/params.pb.go new file mode 100644 index 000000000..63cb9f459 --- /dev/null +++ b/x/tokenfactory/types/params.pb.go @@ -0,0 +1,383 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/tokenfactory/v1beta1/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the tokenfactory module. +type Params struct { + DenomCreationFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=denom_creation_fee,json=denomCreationFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"denom_creation_fee" yaml:"denom_creation_fee"` + // if denom_creation_fee is an empty array, then this field is used to add more gas consumption + // to the base cost. + // https://github.com/CosmWasm/token-factory/issues/11 + DenomCreationGasConsume uint64 `protobuf:"varint,2,opt,name=denom_creation_gas_consume,json=denomCreationGasConsume,proto3" json:"denom_creation_gas_consume,omitempty" yaml:"denom_creation_gas_consume"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_cc8299d306f3ff47, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetDenomCreationFee() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.DenomCreationFee + } + return nil +} + +func (m *Params) GetDenomCreationGasConsume() uint64 { + if m != nil { + return m.DenomCreationGasConsume + } + return 0 +} + +func init() { + proto.RegisterType((*Params)(nil), "osmosis.tokenfactory.v1beta1.Params") +} + +func init() { + proto.RegisterFile("osmosis/tokenfactory/v1beta1/params.proto", fileDescriptor_cc8299d306f3ff47) +} + +var fileDescriptor_cc8299d306f3ff47 = []byte{ + // 355 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0x4e, 0xc2, 0x50, + 0x14, 0x86, 0x7b, 0xd1, 0x30, 0xd4, 0xc5, 0x34, 0x26, 0x02, 0x31, 0xb7, 0xd8, 0x09, 0x06, 0xda, + 0xa0, 0x4e, 0x4e, 0x86, 0x26, 0x38, 0x91, 0x18, 0xe2, 0xc4, 0xd2, 0x9c, 0x96, 0x4b, 0x69, 0xb0, + 0x3d, 0xa4, 0xf7, 0x62, 0xec, 0x23, 0xb8, 0x39, 0xf9, 0x10, 0x3e, 0x09, 0x23, 0xa3, 0x53, 0x35, + 0xf0, 0x06, 0x3c, 0x81, 0xe1, 0xf6, 0x62, 0x40, 0x8d, 0x53, 0x7b, 0x72, 0xfe, 0xff, 0xeb, 0x7f, + 0xfa, 0xeb, 0x4d, 0xe4, 0x31, 0xf2, 0x88, 0x3b, 0x02, 0x27, 0x2c, 0x19, 0x41, 0x20, 0x30, 0xcd, + 0x9c, 0xc7, 0xb6, 0xcf, 0x04, 0xb4, 0x9d, 0x29, 0xa4, 0x10, 0x73, 0x7b, 0x9a, 0xa2, 0x40, 0xe3, + 0x4c, 0x49, 0xed, 0x5d, 0xa9, 0xad, 0xa4, 0xb5, 0x93, 0x10, 0x43, 0x94, 0x42, 0x67, 0xf3, 0x56, + 0x78, 0x6a, 0x57, 0xff, 0xe2, 0x61, 0x26, 0xc6, 0x98, 0x46, 0x22, 0xeb, 0x31, 0x01, 0x43, 0x10, + 0xa0, 0x5c, 0xd5, 0x40, 0xda, 0xbc, 0x02, 0x57, 0x0c, 0x6a, 0x45, 0x8b, 0xc9, 0xf1, 0x81, 0xb3, + 0x6f, 0x4e, 0x80, 0x51, 0x52, 0xec, 0xad, 0xe7, 0x92, 0x5e, 0xbe, 0x93, 0xa9, 0x8d, 0x57, 0xa2, + 0x1b, 0x43, 0x96, 0x60, 0xec, 0x05, 0x29, 0x03, 0x11, 0x61, 0xe2, 0x8d, 0x18, 0xab, 0x90, 0xfa, + 0x41, 0xe3, 0xe8, 0xa2, 0x6a, 0x2b, 0xec, 0x06, 0xb4, 0x3d, 0xc2, 0x76, 0x31, 0x4a, 0x3a, 0xbd, + 0x79, 0x6e, 0x6a, 0xeb, 0xdc, 0xac, 0x66, 0x10, 0x3f, 0x5c, 0x5b, 0xbf, 0x11, 0xd6, 0xdb, 0x87, + 0xd9, 0x08, 0x23, 0x31, 0x9e, 0xf9, 0x76, 0x80, 0xb1, 0x0a, 0xa8, 0x1e, 0x2d, 0x3e, 0x9c, 0x38, + 0x22, 0x9b, 0x32, 0x2e, 0x69, 0xbc, 0x7f, 0x2c, 0x01, 0xae, 0xf2, 0x77, 0x19, 0x33, 0x46, 0x7a, + 0xed, 0x07, 0x34, 0x04, 0xee, 0x05, 0x98, 0xf0, 0x59, 0xcc, 0x2a, 0xa5, 0x3a, 0x69, 0x1c, 0x76, + 0x9a, 0xf3, 0xdc, 0x24, 0xeb, 0xdc, 0x3c, 0xff, 0x33, 0xc4, 0x8e, 0xde, 0xea, 0x9f, 0xee, 0x7d, + 0xe0, 0x16, 0xb8, 0x5b, 0x6c, 0x3a, 0x83, 0xf9, 0x92, 0x92, 0xc5, 0x92, 0x92, 0xcf, 0x25, 0x25, + 0x2f, 0x2b, 0xaa, 0x2d, 0x56, 0x54, 0x7b, 0x5f, 0x51, 0x6d, 0x70, 0xb3, 0x93, 0xde, 0x95, 0xb1, + 0xef, 0x37, 0xfd, 0x74, 0x55, 0x3f, 0xb2, 0xac, 0xd6, 0xb6, 0xad, 0xa7, 0xfd, 0xf2, 0xe4, 0x6d, + 0x7e, 0x59, 0xfe, 0xee, 0xcb, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x17, 0xac, 0x28, 0xc6, 0x40, + 0x02, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DenomCreationGasConsume != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.DenomCreationGasConsume)) + i-- + dAtA[i] = 0x10 + } + if len(m.DenomCreationFee) > 0 { + for iNdEx := len(m.DenomCreationFee) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DenomCreationFee[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.DenomCreationFee) > 0 { + for _, e := range m.DenomCreationFee { + l = e.Size() + n += 1 + l + sovParams(uint64(l)) + } + } + if m.DenomCreationGasConsume != 0 { + n += 1 + sovParams(uint64(m.DenomCreationGasConsume)) + } + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomCreationFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DenomCreationFee = append(m.DenomCreationFee, types.Coin{}) + if err := m.DenomCreationFee[len(m.DenomCreationFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DenomCreationGasConsume", wireType) + } + m.DenomCreationGasConsume = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DenomCreationGasConsume |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/query.pb.go b/x/tokenfactory/types/query.pb.go new file mode 100644 index 000000000..1e201985d --- /dev/null +++ b/x/tokenfactory/types/query.pb.go @@ -0,0 +1,1332 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/tokenfactory/v1beta1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6f22013ad0f72e3f, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params defines the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6f22013ad0f72e3f, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// QueryDenomAuthorityMetadataRequest defines the request structure for the +// DenomAuthorityMetadata gRPC query. +type QueryDenomAuthorityMetadataRequest struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` +} + +func (m *QueryDenomAuthorityMetadataRequest) Reset() { *m = QueryDenomAuthorityMetadataRequest{} } +func (m *QueryDenomAuthorityMetadataRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomAuthorityMetadataRequest) ProtoMessage() {} +func (*QueryDenomAuthorityMetadataRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6f22013ad0f72e3f, []int{2} +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomAuthorityMetadataRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomAuthorityMetadataRequest.Merge(m, src) +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomAuthorityMetadataRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomAuthorityMetadataRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomAuthorityMetadataRequest proto.InternalMessageInfo + +func (m *QueryDenomAuthorityMetadataRequest) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +// QueryDenomAuthorityMetadataResponse defines the response structure for the +// DenomAuthorityMetadata gRPC query. +type QueryDenomAuthorityMetadataResponse struct { + AuthorityMetadata DenomAuthorityMetadata `protobuf:"bytes,1,opt,name=authority_metadata,json=authorityMetadata,proto3" json:"authority_metadata" yaml:"authority_metadata"` +} + +func (m *QueryDenomAuthorityMetadataResponse) Reset() { *m = QueryDenomAuthorityMetadataResponse{} } +func (m *QueryDenomAuthorityMetadataResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomAuthorityMetadataResponse) ProtoMessage() {} +func (*QueryDenomAuthorityMetadataResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6f22013ad0f72e3f, []int{3} +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomAuthorityMetadataResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomAuthorityMetadataResponse.Merge(m, src) +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomAuthorityMetadataResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomAuthorityMetadataResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomAuthorityMetadataResponse proto.InternalMessageInfo + +func (m *QueryDenomAuthorityMetadataResponse) GetAuthorityMetadata() DenomAuthorityMetadata { + if m != nil { + return m.AuthorityMetadata + } + return DenomAuthorityMetadata{} +} + +// QueryDenomsFromCreatorRequest defines the request structure for the +// DenomsFromCreator gRPC query. +type QueryDenomsFromCreatorRequest struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty" yaml:"creator"` +} + +func (m *QueryDenomsFromCreatorRequest) Reset() { *m = QueryDenomsFromCreatorRequest{} } +func (m *QueryDenomsFromCreatorRequest) String() string { return proto.CompactTextString(m) } +func (*QueryDenomsFromCreatorRequest) ProtoMessage() {} +func (*QueryDenomsFromCreatorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6f22013ad0f72e3f, []int{4} +} +func (m *QueryDenomsFromCreatorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomsFromCreatorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomsFromCreatorRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomsFromCreatorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomsFromCreatorRequest.Merge(m, src) +} +func (m *QueryDenomsFromCreatorRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomsFromCreatorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomsFromCreatorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomsFromCreatorRequest proto.InternalMessageInfo + +func (m *QueryDenomsFromCreatorRequest) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +// QueryDenomsFromCreatorRequest defines the response structure for the +// DenomsFromCreator gRPC query. +type QueryDenomsFromCreatorResponse struct { + Denoms []string `protobuf:"bytes,1,rep,name=denoms,proto3" json:"denoms,omitempty" yaml:"denoms"` +} + +func (m *QueryDenomsFromCreatorResponse) Reset() { *m = QueryDenomsFromCreatorResponse{} } +func (m *QueryDenomsFromCreatorResponse) String() string { return proto.CompactTextString(m) } +func (*QueryDenomsFromCreatorResponse) ProtoMessage() {} +func (*QueryDenomsFromCreatorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6f22013ad0f72e3f, []int{5} +} +func (m *QueryDenomsFromCreatorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDenomsFromCreatorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDenomsFromCreatorResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryDenomsFromCreatorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDenomsFromCreatorResponse.Merge(m, src) +} +func (m *QueryDenomsFromCreatorResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryDenomsFromCreatorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDenomsFromCreatorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryDenomsFromCreatorResponse proto.InternalMessageInfo + +func (m *QueryDenomsFromCreatorResponse) GetDenoms() []string { + if m != nil { + return m.Denoms + } + return nil +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "osmosis.tokenfactory.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "osmosis.tokenfactory.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryDenomAuthorityMetadataRequest)(nil), "osmosis.tokenfactory.v1beta1.QueryDenomAuthorityMetadataRequest") + proto.RegisterType((*QueryDenomAuthorityMetadataResponse)(nil), "osmosis.tokenfactory.v1beta1.QueryDenomAuthorityMetadataResponse") + proto.RegisterType((*QueryDenomsFromCreatorRequest)(nil), "osmosis.tokenfactory.v1beta1.QueryDenomsFromCreatorRequest") + proto.RegisterType((*QueryDenomsFromCreatorResponse)(nil), "osmosis.tokenfactory.v1beta1.QueryDenomsFromCreatorResponse") +} + +func init() { + proto.RegisterFile("osmosis/tokenfactory/v1beta1/query.proto", fileDescriptor_6f22013ad0f72e3f) +} + +var fileDescriptor_6f22013ad0f72e3f = []byte{ + // 574 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4f, 0x4f, 0x13, 0x41, + 0x14, 0xef, 0x2a, 0xd4, 0x30, 0xfe, 0x89, 0x1d, 0x89, 0xd1, 0x06, 0xb7, 0x3a, 0x12, 0x52, 0x0c, + 0xee, 0x58, 0xe4, 0x24, 0x1a, 0xe9, 0xd6, 0xe0, 0x41, 0x49, 0x74, 0xe3, 0x45, 0x2e, 0xcd, 0xb4, + 0x0c, 0xcb, 0x46, 0x76, 0x67, 0xd9, 0x99, 0x1a, 0x1b, 0xc2, 0xc5, 0x83, 0x67, 0x13, 0x8f, 0x7e, + 0x07, 0x3f, 0x07, 0x47, 0x12, 0x2e, 0x9e, 0x1a, 0xd3, 0x12, 0x3f, 0x40, 0x3f, 0x81, 0xd9, 0x99, + 0x57, 0x04, 0x5b, 0x37, 0x55, 0x4e, 0xdd, 0xcc, 0xfb, 0xbd, 0xdf, 0x9f, 0xf7, 0x5e, 0x8a, 0xca, + 0x42, 0x86, 0x42, 0x06, 0x92, 0x2a, 0xf1, 0x8e, 0x47, 0x9b, 0xac, 0xa9, 0x44, 0xd2, 0xa6, 0xef, + 0x2b, 0x0d, 0xae, 0x58, 0x85, 0xee, 0xb4, 0x78, 0xd2, 0x76, 0xe2, 0x44, 0x28, 0x81, 0x67, 0x00, + 0xe9, 0x9c, 0x44, 0x3a, 0x80, 0x2c, 0x4e, 0xfb, 0xc2, 0x17, 0x1a, 0x48, 0xd3, 0x2f, 0xd3, 0x53, + 0x9c, 0xf1, 0x85, 0xf0, 0xb7, 0x39, 0x65, 0x71, 0x40, 0x59, 0x14, 0x09, 0xc5, 0x54, 0x20, 0x22, + 0x09, 0xd5, 0x7b, 0x4d, 0x4d, 0x49, 0x1b, 0x4c, 0x72, 0x23, 0x75, 0x2c, 0x1c, 0x33, 0x3f, 0x88, + 0x34, 0x18, 0xb0, 0x4b, 0x99, 0x3e, 0x59, 0x4b, 0x6d, 0x89, 0x24, 0x50, 0xed, 0x35, 0xae, 0xd8, + 0x06, 0x53, 0x0c, 0xba, 0xe6, 0x33, 0xbb, 0x62, 0x96, 0xb0, 0x10, 0xcc, 0x90, 0x69, 0x84, 0x5f, + 0xa7, 0x16, 0x5e, 0xe9, 0x47, 0x8f, 0xef, 0xb4, 0xb8, 0x54, 0xe4, 0x2d, 0xba, 0x76, 0xea, 0x55, + 0xc6, 0x22, 0x92, 0x1c, 0xbb, 0x28, 0x6f, 0x9a, 0x6f, 0x58, 0xb7, 0xad, 0xf2, 0xc5, 0xc5, 0x59, + 0x27, 0x6b, 0x38, 0x8e, 0xe9, 0x76, 0x27, 0xf6, 0x3b, 0xa5, 0x9c, 0x07, 0x9d, 0xe4, 0x25, 0x22, + 0x9a, 0xfa, 0x19, 0x8f, 0x44, 0x58, 0xfd, 0x33, 0x00, 0x18, 0xc0, 0x73, 0x68, 0x72, 0x23, 0x05, + 0x68, 0xa1, 0x29, 0xf7, 0x6a, 0xbf, 0x53, 0xba, 0xd4, 0x66, 0xe1, 0xf6, 0x23, 0xa2, 0x9f, 0x89, + 0x67, 0xca, 0xe4, 0x9b, 0x85, 0xee, 0x66, 0xd2, 0x81, 0xf3, 0x4f, 0x16, 0xc2, 0xc7, 0xd3, 0xaa, + 0x87, 0x50, 0x86, 0x18, 0x4b, 0xd9, 0x31, 0x46, 0x53, 0xbb, 0x77, 0xd2, 0x58, 0xfd, 0x4e, 0xe9, + 0xa6, 0xf1, 0x35, 0xcc, 0x4e, 0xbc, 0xc2, 0xd0, 0x82, 0xc8, 0x1a, 0xba, 0xf5, 0xdb, 0xaf, 0x5c, + 0x4d, 0x44, 0x58, 0x4b, 0x38, 0x53, 0x22, 0x19, 0x24, 0x5f, 0x40, 0x17, 0x9a, 0xe6, 0x05, 0xb2, + 0xe3, 0x7e, 0xa7, 0x74, 0xc5, 0x68, 0x40, 0x81, 0x78, 0x03, 0x08, 0x79, 0x81, 0xec, 0xbf, 0xd1, + 0x41, 0xf2, 0x79, 0x94, 0xd7, 0xa3, 0x4a, 0x77, 0x76, 0xbe, 0x3c, 0xe5, 0x16, 0xfa, 0x9d, 0xd2, + 0xe5, 0x13, 0xa3, 0x94, 0xc4, 0x03, 0xc0, 0xe2, 0xd1, 0x04, 0x9a, 0xd4, 0x6c, 0xf8, 0xab, 0x85, + 0xf2, 0x66, 0x7b, 0xf8, 0x41, 0xf6, 0x70, 0x86, 0x8f, 0xa7, 0x58, 0xf9, 0x87, 0x0e, 0x63, 0x92, + 0x2c, 0x7c, 0x3c, 0x3c, 0xfa, 0x72, 0x6e, 0x0e, 0xcf, 0xd2, 0x31, 0x2e, 0x17, 0xff, 0xb4, 0xd0, + 0xf5, 0xd1, 0x4b, 0xc1, 0x2b, 0x63, 0x68, 0x67, 0x5e, 0x5e, 0xb1, 0x7a, 0x06, 0x06, 0x48, 0xf3, + 0x5c, 0xa7, 0xa9, 0xe2, 0xa7, 0xd9, 0x69, 0xcc, 0xd4, 0xe9, 0xae, 0xfe, 0xdd, 0xa3, 0xc3, 0x07, + 0x84, 0x0f, 0x2d, 0x54, 0x18, 0xda, 0x2c, 0x5e, 0x1e, 0xd7, 0xe1, 0x88, 0xf3, 0x2a, 0x3e, 0xfe, + 0xbf, 0x66, 0x48, 0x56, 0xd3, 0xc9, 0x9e, 0xe0, 0xe5, 0x71, 0x92, 0xd5, 0x37, 0x13, 0x11, 0xd6, + 0xe1, 0x52, 0xe9, 0x2e, 0x7c, 0xec, 0xb9, 0xeb, 0xfb, 0x5d, 0xdb, 0x3a, 0xe8, 0xda, 0xd6, 0x8f, + 0xae, 0x6d, 0x7d, 0xee, 0xd9, 0xb9, 0x83, 0x9e, 0x9d, 0xfb, 0xde, 0xb3, 0x73, 0xeb, 0x2b, 0x7e, + 0xa0, 0xb6, 0x5a, 0x0d, 0xa7, 0x29, 0x42, 0x5a, 0xd3, 0x0a, 0x6f, 0x52, 0xfa, 0x55, 0xa0, 0xd7, + 0x5a, 0xf7, 0x07, 0x62, 0x1f, 0x4e, 0x6b, 0xab, 0x76, 0xcc, 0x65, 0x23, 0xaf, 0xff, 0xd5, 0x1e, + 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x27, 0x80, 0x49, 0x9f, 0xe0, 0x05, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params defines a gRPC query method that returns the tokenfactory module's + // parameters. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // DenomAuthorityMetadata defines a gRPC query method for fetching + // DenomAuthorityMetadata for a particular denom. + DenomAuthorityMetadata(ctx context.Context, in *QueryDenomAuthorityMetadataRequest, opts ...grpc.CallOption) (*QueryDenomAuthorityMetadataResponse, error) + // DenomsFromCreator defines a gRPC query method for fetching all + // denominations created by a specific admin/creator. + DenomsFromCreator(ctx context.Context, in *QueryDenomsFromCreatorRequest, opts ...grpc.CallOption) (*QueryDenomsFromCreatorResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomAuthorityMetadata(ctx context.Context, in *QueryDenomAuthorityMetadataRequest, opts ...grpc.CallOption) (*QueryDenomAuthorityMetadataResponse, error) { + out := new(QueryDenomAuthorityMetadataResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Query/DenomAuthorityMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) DenomsFromCreator(ctx context.Context, in *QueryDenomsFromCreatorRequest, opts ...grpc.CallOption) (*QueryDenomsFromCreatorResponse, error) { + out := new(QueryDenomsFromCreatorResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Query/DenomsFromCreator", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params defines a gRPC query method that returns the tokenfactory module's + // parameters. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // DenomAuthorityMetadata defines a gRPC query method for fetching + // DenomAuthorityMetadata for a particular denom. + DenomAuthorityMetadata(context.Context, *QueryDenomAuthorityMetadataRequest) (*QueryDenomAuthorityMetadataResponse, error) + // DenomsFromCreator defines a gRPC query method for fetching all + // denominations created by a specific admin/creator. + DenomsFromCreator(context.Context, *QueryDenomsFromCreatorRequest) (*QueryDenomsFromCreatorResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) DenomAuthorityMetadata(ctx context.Context, req *QueryDenomAuthorityMetadataRequest) (*QueryDenomAuthorityMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomAuthorityMetadata not implemented") +} +func (*UnimplementedQueryServer) DenomsFromCreator(ctx context.Context, req *QueryDenomsFromCreatorRequest) (*QueryDenomsFromCreatorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DenomsFromCreator not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomAuthorityMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomAuthorityMetadataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomAuthorityMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Query/DenomAuthorityMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomAuthorityMetadata(ctx, req.(*QueryDenomAuthorityMetadataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_DenomsFromCreator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryDenomsFromCreatorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).DenomsFromCreator(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Query/DenomsFromCreator", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).DenomsFromCreator(ctx, req.(*QueryDenomsFromCreatorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "osmosis.tokenfactory.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "DenomAuthorityMetadata", + Handler: _Query_DenomAuthorityMetadata_Handler, + }, + { + MethodName: "DenomsFromCreator", + Handler: _Query_DenomsFromCreator_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "osmosis/tokenfactory/v1beta1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryDenomAuthorityMetadataRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomAuthorityMetadataRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomAuthorityMetadataRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomAuthorityMetadataResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomAuthorityMetadataResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomAuthorityMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.AuthorityMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryDenomsFromCreatorRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomsFromCreatorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomsFromCreatorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryDenomsFromCreatorResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDenomsFromCreatorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDenomsFromCreatorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denoms) > 0 { + for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Denoms[iNdEx]) + copy(dAtA[i:], m.Denoms[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denoms[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryDenomAuthorityMetadataRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomAuthorityMetadataResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.AuthorityMetadata.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryDenomsFromCreatorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryDenomsFromCreatorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Denoms) > 0 { + for _, s := range m.Denoms { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomAuthorityMetadataRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomAuthorityMetadataResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomAuthorityMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AuthorityMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AuthorityMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomsFromCreatorRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomsFromCreatorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomsFromCreatorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryDenomsFromCreatorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDenomsFromCreatorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDenomsFromCreatorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tokenfactory/types/query.pb.gw.go b/x/tokenfactory/types/query.pb.gw.go new file mode 100644 index 000000000..0b895e706 --- /dev/null +++ b/x/tokenfactory/types/query.pb.gw.go @@ -0,0 +1,355 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: osmosis/tokenfactory/v1beta1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_DenomAuthorityMetadata_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomAuthorityMetadataRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := client.DenomAuthorityMetadata(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomAuthorityMetadata_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomAuthorityMetadataRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["denom"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "denom") + } + + protoReq.Denom, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "denom", err) + } + + msg, err := server.DenomAuthorityMetadata(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomsFromCreatorRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["creator"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "creator") + } + + protoReq.Creator, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator", err) + } + + msg, err := client.DenomsFromCreator(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_DenomsFromCreator_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryDenomsFromCreatorRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["creator"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "creator") + } + + protoReq.Creator, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator", err) + } + + msg, err := server.DenomsFromCreator(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomAuthorityMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomAuthorityMetadata_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomAuthorityMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomsFromCreator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_DenomsFromCreator_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomsFromCreator_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomAuthorityMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomAuthorityMetadata_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomAuthorityMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_DenomsFromCreator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_DenomsFromCreator_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_DenomsFromCreator_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "tokenfactory", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomAuthorityMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"osmosis", "tokenfactory", "v1beta1", "denoms", "denom", "authority_metadata"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_DenomsFromCreator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"osmosis", "tokenfactory", "v1beta1", "denoms_from_creator", "creator"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_DenomAuthorityMetadata_0 = runtime.ForwardResponseMessage + + forward_Query_DenomsFromCreator_0 = runtime.ForwardResponseMessage +) diff --git a/x/tokenfactory/types/tx.pb.go b/x/tokenfactory/types/tx.pb.go new file mode 100644 index 000000000..6b44d792a --- /dev/null +++ b/x/tokenfactory/types/tx.pb.go @@ -0,0 +1,2829 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/tokenfactory/v1beta1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/x/bank/types" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgCreateDenom defines the message structure for the CreateDenom gRPC service +// method. It allows an account to create a new denom. It requires a sender +// address and a sub denomination. The (sender_address, sub_denomination) tuple +// must be unique and cannot be re-used. +// +// The resulting denom created is defined as +// . The resulting denom's admin is +// originally set to be the creator, but this can be changed later. The token +// denom does not indicate the current admin. +type MsgCreateDenom struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + // subdenom can be up to 44 "alphanumeric" characters long. + Subdenom string `protobuf:"bytes,2,opt,name=subdenom,proto3" json:"subdenom,omitempty" yaml:"subdenom"` +} + +func (m *MsgCreateDenom) Reset() { *m = MsgCreateDenom{} } +func (m *MsgCreateDenom) String() string { return proto.CompactTextString(m) } +func (*MsgCreateDenom) ProtoMessage() {} +func (*MsgCreateDenom) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{0} +} +func (m *MsgCreateDenom) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateDenom) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateDenom.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateDenom) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateDenom.Merge(m, src) +} +func (m *MsgCreateDenom) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateDenom) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateDenom.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateDenom proto.InternalMessageInfo + +func (m *MsgCreateDenom) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgCreateDenom) GetSubdenom() string { + if m != nil { + return m.Subdenom + } + return "" +} + +// MsgCreateDenomResponse is the return value of MsgCreateDenom +// It returns the full string of the newly created denom +type MsgCreateDenomResponse struct { + NewTokenDenom string `protobuf:"bytes,1,opt,name=new_token_denom,json=newTokenDenom,proto3" json:"new_token_denom,omitempty" yaml:"new_token_denom"` +} + +func (m *MsgCreateDenomResponse) Reset() { *m = MsgCreateDenomResponse{} } +func (m *MsgCreateDenomResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCreateDenomResponse) ProtoMessage() {} +func (*MsgCreateDenomResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{1} +} +func (m *MsgCreateDenomResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateDenomResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateDenomResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateDenomResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateDenomResponse.Merge(m, src) +} +func (m *MsgCreateDenomResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateDenomResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateDenomResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateDenomResponse proto.InternalMessageInfo + +func (m *MsgCreateDenomResponse) GetNewTokenDenom() string { + if m != nil { + return m.NewTokenDenom + } + return "" +} + +// MsgMint is the sdk.Msg type for allowing an admin account to mint +// more of a token. For now, we only support minting to the sender account +type MsgMint struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount" yaml:"amount"` + MintToAddress string `protobuf:"bytes,3,opt,name=mintToAddress,proto3" json:"mintToAddress,omitempty" yaml:"mint_to_address"` +} + +func (m *MsgMint) Reset() { *m = MsgMint{} } +func (m *MsgMint) String() string { return proto.CompactTextString(m) } +func (*MsgMint) ProtoMessage() {} +func (*MsgMint) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{2} +} +func (m *MsgMint) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMint.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMint) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMint.Merge(m, src) +} +func (m *MsgMint) XXX_Size() int { + return m.Size() +} +func (m *MsgMint) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMint.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMint proto.InternalMessageInfo + +func (m *MsgMint) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgMint) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func (m *MsgMint) GetMintToAddress() string { + if m != nil { + return m.MintToAddress + } + return "" +} + +type MsgMintResponse struct { +} + +func (m *MsgMintResponse) Reset() { *m = MsgMintResponse{} } +func (m *MsgMintResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMintResponse) ProtoMessage() {} +func (*MsgMintResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{3} +} +func (m *MsgMintResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMintResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMintResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMintResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMintResponse.Merge(m, src) +} +func (m *MsgMintResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMintResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMintResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMintResponse proto.InternalMessageInfo + +// MsgBurn is the sdk.Msg type for allowing an admin account to burn +// a token. For now, we only support burning from the sender account. +type MsgBurn struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount" yaml:"amount"` + BurnFromAddress string `protobuf:"bytes,3,opt,name=burnFromAddress,proto3" json:"burnFromAddress,omitempty" yaml:"burn_from_address"` +} + +func (m *MsgBurn) Reset() { *m = MsgBurn{} } +func (m *MsgBurn) String() string { return proto.CompactTextString(m) } +func (*MsgBurn) ProtoMessage() {} +func (*MsgBurn) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{4} +} +func (m *MsgBurn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurn.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgBurn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurn.Merge(m, src) +} +func (m *MsgBurn) XXX_Size() int { + return m.Size() +} +func (m *MsgBurn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurn proto.InternalMessageInfo + +func (m *MsgBurn) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgBurn) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func (m *MsgBurn) GetBurnFromAddress() string { + if m != nil { + return m.BurnFromAddress + } + return "" +} + +type MsgBurnResponse struct { +} + +func (m *MsgBurnResponse) Reset() { *m = MsgBurnResponse{} } +func (m *MsgBurnResponse) String() string { return proto.CompactTextString(m) } +func (*MsgBurnResponse) ProtoMessage() {} +func (*MsgBurnResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{5} +} +func (m *MsgBurnResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurnResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurnResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgBurnResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurnResponse.Merge(m, src) +} +func (m *MsgBurnResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgBurnResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurnResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurnResponse proto.InternalMessageInfo + +// MsgChangeAdmin is the sdk.Msg type for allowing an admin account to reassign +// adminship of a denom to a new account +type MsgChangeAdmin struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + NewAdmin string `protobuf:"bytes,3,opt,name=new_admin,json=newAdmin,proto3" json:"new_admin,omitempty" yaml:"new_admin"` +} + +func (m *MsgChangeAdmin) Reset() { *m = MsgChangeAdmin{} } +func (m *MsgChangeAdmin) String() string { return proto.CompactTextString(m) } +func (*MsgChangeAdmin) ProtoMessage() {} +func (*MsgChangeAdmin) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{6} +} +func (m *MsgChangeAdmin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChangeAdmin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChangeAdmin.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgChangeAdmin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChangeAdmin.Merge(m, src) +} +func (m *MsgChangeAdmin) XXX_Size() int { + return m.Size() +} +func (m *MsgChangeAdmin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChangeAdmin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgChangeAdmin proto.InternalMessageInfo + +func (m *MsgChangeAdmin) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgChangeAdmin) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *MsgChangeAdmin) GetNewAdmin() string { + if m != nil { + return m.NewAdmin + } + return "" +} + +// MsgChangeAdminResponse defines the response structure for an executed +// MsgChangeAdmin message. +type MsgChangeAdminResponse struct { +} + +func (m *MsgChangeAdminResponse) Reset() { *m = MsgChangeAdminResponse{} } +func (m *MsgChangeAdminResponse) String() string { return proto.CompactTextString(m) } +func (*MsgChangeAdminResponse) ProtoMessage() {} +func (*MsgChangeAdminResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{7} +} +func (m *MsgChangeAdminResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgChangeAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgChangeAdminResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgChangeAdminResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgChangeAdminResponse.Merge(m, src) +} +func (m *MsgChangeAdminResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgChangeAdminResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgChangeAdminResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgChangeAdminResponse proto.InternalMessageInfo + +// MsgSetDenomMetadata is the sdk.Msg type for allowing an admin account to set +// the denom's bank metadata +type MsgSetDenomMetadata struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Metadata types1.Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata" yaml:"metadata"` +} + +func (m *MsgSetDenomMetadata) Reset() { *m = MsgSetDenomMetadata{} } +func (m *MsgSetDenomMetadata) String() string { return proto.CompactTextString(m) } +func (*MsgSetDenomMetadata) ProtoMessage() {} +func (*MsgSetDenomMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{8} +} +func (m *MsgSetDenomMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetDenomMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetDenomMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetDenomMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetDenomMetadata.Merge(m, src) +} +func (m *MsgSetDenomMetadata) XXX_Size() int { + return m.Size() +} +func (m *MsgSetDenomMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetDenomMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetDenomMetadata proto.InternalMessageInfo + +func (m *MsgSetDenomMetadata) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgSetDenomMetadata) GetMetadata() types1.Metadata { + if m != nil { + return m.Metadata + } + return types1.Metadata{} +} + +// MsgSetDenomMetadataResponse defines the response structure for an executed +// MsgSetDenomMetadata message. +type MsgSetDenomMetadataResponse struct { +} + +func (m *MsgSetDenomMetadataResponse) Reset() { *m = MsgSetDenomMetadataResponse{} } +func (m *MsgSetDenomMetadataResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSetDenomMetadataResponse) ProtoMessage() {} +func (*MsgSetDenomMetadataResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{9} +} +func (m *MsgSetDenomMetadataResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetDenomMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetDenomMetadataResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetDenomMetadataResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetDenomMetadataResponse.Merge(m, src) +} +func (m *MsgSetDenomMetadataResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSetDenomMetadataResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetDenomMetadataResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetDenomMetadataResponse proto.InternalMessageInfo + +type MsgForceTransfer struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount" yaml:"amount"` + TransferFromAddress string `protobuf:"bytes,3,opt,name=transferFromAddress,proto3" json:"transferFromAddress,omitempty" yaml:"transfer_from_address"` + TransferToAddress string `protobuf:"bytes,4,opt,name=transferToAddress,proto3" json:"transferToAddress,omitempty" yaml:"transfer_to_address"` +} + +func (m *MsgForceTransfer) Reset() { *m = MsgForceTransfer{} } +func (m *MsgForceTransfer) String() string { return proto.CompactTextString(m) } +func (*MsgForceTransfer) ProtoMessage() {} +func (*MsgForceTransfer) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{10} +} +func (m *MsgForceTransfer) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgForceTransfer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgForceTransfer.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgForceTransfer) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgForceTransfer.Merge(m, src) +} +func (m *MsgForceTransfer) XXX_Size() int { + return m.Size() +} +func (m *MsgForceTransfer) XXX_DiscardUnknown() { + xxx_messageInfo_MsgForceTransfer.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgForceTransfer proto.InternalMessageInfo + +func (m *MsgForceTransfer) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgForceTransfer) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func (m *MsgForceTransfer) GetTransferFromAddress() string { + if m != nil { + return m.TransferFromAddress + } + return "" +} + +func (m *MsgForceTransfer) GetTransferToAddress() string { + if m != nil { + return m.TransferToAddress + } + return "" +} + +type MsgForceTransferResponse struct { +} + +func (m *MsgForceTransferResponse) Reset() { *m = MsgForceTransferResponse{} } +func (m *MsgForceTransferResponse) String() string { return proto.CompactTextString(m) } +func (*MsgForceTransferResponse) ProtoMessage() {} +func (*MsgForceTransferResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_283b6c9a90a846b4, []int{11} +} +func (m *MsgForceTransferResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgForceTransferResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgForceTransferResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgForceTransferResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgForceTransferResponse.Merge(m, src) +} +func (m *MsgForceTransferResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgForceTransferResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgForceTransferResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgForceTransferResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgCreateDenom)(nil), "osmosis.tokenfactory.v1beta1.MsgCreateDenom") + proto.RegisterType((*MsgCreateDenomResponse)(nil), "osmosis.tokenfactory.v1beta1.MsgCreateDenomResponse") + proto.RegisterType((*MsgMint)(nil), "osmosis.tokenfactory.v1beta1.MsgMint") + proto.RegisterType((*MsgMintResponse)(nil), "osmosis.tokenfactory.v1beta1.MsgMintResponse") + proto.RegisterType((*MsgBurn)(nil), "osmosis.tokenfactory.v1beta1.MsgBurn") + proto.RegisterType((*MsgBurnResponse)(nil), "osmosis.tokenfactory.v1beta1.MsgBurnResponse") + proto.RegisterType((*MsgChangeAdmin)(nil), "osmosis.tokenfactory.v1beta1.MsgChangeAdmin") + proto.RegisterType((*MsgChangeAdminResponse)(nil), "osmosis.tokenfactory.v1beta1.MsgChangeAdminResponse") + proto.RegisterType((*MsgSetDenomMetadata)(nil), "osmosis.tokenfactory.v1beta1.MsgSetDenomMetadata") + proto.RegisterType((*MsgSetDenomMetadataResponse)(nil), "osmosis.tokenfactory.v1beta1.MsgSetDenomMetadataResponse") + proto.RegisterType((*MsgForceTransfer)(nil), "osmosis.tokenfactory.v1beta1.MsgForceTransfer") + proto.RegisterType((*MsgForceTransferResponse)(nil), "osmosis.tokenfactory.v1beta1.MsgForceTransferResponse") +} + +func init() { + proto.RegisterFile("osmosis/tokenfactory/v1beta1/tx.proto", fileDescriptor_283b6c9a90a846b4) +} + +var fileDescriptor_283b6c9a90a846b4 = []byte{ + // 742 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x4f, 0x13, 0x41, + 0x14, 0xef, 0xf2, 0x4f, 0x18, 0xac, 0x2d, 0x0b, 0x62, 0x5d, 0x61, 0x97, 0x4c, 0x82, 0xd1, 0x44, + 0xb6, 0x29, 0x1a, 0x13, 0x3d, 0x41, 0x31, 0x8d, 0x07, 0x7b, 0x59, 0x39, 0x11, 0x92, 0x66, 0xdb, + 0x0e, 0x4b, 0x03, 0x3b, 0x83, 0x3b, 0x53, 0x0b, 0x37, 0x3f, 0x82, 0x07, 0xe3, 0x17, 0xf0, 0xe4, + 0xb7, 0xf0, 0x64, 0x38, 0x72, 0xf4, 0xb4, 0x31, 0xf0, 0x0d, 0xf6, 0x13, 0x98, 0x9d, 0x99, 0xfd, + 0x5b, 0x62, 0xdb, 0x13, 0x37, 0xd8, 0xf7, 0xfb, 0xfd, 0xe6, 0xfd, 0xde, 0xbc, 0xf7, 0x3a, 0x60, + 0x93, 0x50, 0x97, 0xd0, 0x1e, 0xad, 0x32, 0x72, 0x82, 0xf0, 0x91, 0xdd, 0x61, 0xc4, 0xbb, 0xa8, + 0x7e, 0xae, 0xb5, 0x11, 0xb3, 0x6b, 0x55, 0x76, 0x6e, 0x9e, 0x79, 0x84, 0x11, 0x75, 0x4d, 0xc2, + 0xcc, 0x34, 0xcc, 0x94, 0x30, 0x6d, 0xc5, 0x21, 0x0e, 0xe1, 0xc0, 0x6a, 0xf8, 0x97, 0xe0, 0x68, + 0x7a, 0x87, 0x93, 0xaa, 0x6d, 0x9b, 0xa2, 0x58, 0xb1, 0x43, 0x7a, 0x78, 0x28, 0x8e, 0x4f, 0xe2, + 0x78, 0xf8, 0x8f, 0x88, 0xc3, 0x53, 0xf0, 0xa0, 0x49, 0x9d, 0x3d, 0x0f, 0xd9, 0x0c, 0xbd, 0x43, + 0x98, 0xb8, 0xea, 0x73, 0x30, 0x47, 0x11, 0xee, 0x22, 0xaf, 0xa2, 0x6c, 0x28, 0xcf, 0x16, 0xea, + 0x4b, 0x81, 0x6f, 0x14, 0x2f, 0x6c, 0xf7, 0xf4, 0x2d, 0x14, 0xdf, 0xa1, 0x25, 0x01, 0x6a, 0x15, + 0xcc, 0xd3, 0x7e, 0xbb, 0x1b, 0xd2, 0x2a, 0x53, 0x1c, 0xbc, 0x1c, 0xf8, 0x46, 0x49, 0x82, 0x65, + 0x04, 0x5a, 0x31, 0x08, 0x1e, 0x82, 0xd5, 0xec, 0x69, 0x16, 0xa2, 0x67, 0x04, 0x53, 0xa4, 0xd6, + 0x41, 0x09, 0xa3, 0x41, 0x8b, 0x3b, 0x6f, 0x09, 0x45, 0x71, 0xbc, 0x16, 0xf8, 0xc6, 0xaa, 0x50, + 0xcc, 0x01, 0xa0, 0x55, 0xc4, 0x68, 0xb0, 0x1f, 0x7e, 0xe0, 0x5a, 0xf0, 0x97, 0x02, 0xee, 0x35, + 0xa9, 0xd3, 0xec, 0x61, 0x36, 0x89, 0x8b, 0xf7, 0x60, 0xce, 0x76, 0x49, 0x1f, 0x33, 0xee, 0x61, + 0x71, 0xfb, 0xb1, 0x29, 0x6a, 0x66, 0x86, 0x35, 0x8d, 0xca, 0x6f, 0xee, 0x91, 0x1e, 0xae, 0x3f, + 0xbc, 0xf4, 0x8d, 0x42, 0xa2, 0x24, 0x68, 0xd0, 0x92, 0x7c, 0x75, 0x07, 0x14, 0xdd, 0x1e, 0x66, + 0xfb, 0x64, 0xb7, 0xdb, 0xf5, 0x10, 0xa5, 0x95, 0xe9, 0xbc, 0x85, 0x30, 0xdc, 0x62, 0xa4, 0x65, + 0x0b, 0x00, 0xb4, 0xb2, 0x04, 0xb8, 0x04, 0x4a, 0xd2, 0x41, 0x54, 0x19, 0xf8, 0x5b, 0xb8, 0xaa, + 0xf7, 0x3d, 0x7c, 0x37, 0xae, 0x1a, 0xa0, 0xd4, 0xee, 0x7b, 0xb8, 0xe1, 0x11, 0x37, 0xeb, 0x6b, + 0x2d, 0xf0, 0x8d, 0x8a, 0xe0, 0x84, 0x80, 0xd6, 0x91, 0x47, 0xdc, 0xc4, 0x59, 0x9e, 0x24, 0xbd, + 0x85, 0x3e, 0x62, 0x6f, 0xdf, 0x15, 0xd1, 0x7e, 0xc7, 0x36, 0x76, 0xd0, 0x6e, 0xd7, 0xed, 0x4d, + 0x64, 0xf1, 0x29, 0x98, 0x4d, 0xf7, 0x5e, 0x39, 0xf0, 0x8d, 0xfb, 0x02, 0x29, 0xfb, 0x43, 0x84, + 0xd5, 0x1a, 0x58, 0x08, 0x5b, 0xc7, 0x0e, 0xf5, 0x65, 0xea, 0x2b, 0x81, 0x6f, 0x94, 0x93, 0xae, + 0xe2, 0x21, 0x68, 0xcd, 0x63, 0x34, 0xe0, 0x59, 0xc0, 0x8a, 0x68, 0xd4, 0x24, 0xaf, 0x38, 0xe5, + 0x6f, 0x0a, 0x58, 0x6e, 0x52, 0xe7, 0x23, 0x62, 0xbc, 0xe9, 0x9a, 0x88, 0xd9, 0x5d, 0x9b, 0xd9, + 0x93, 0xe4, 0x6d, 0x81, 0x79, 0x57, 0xd2, 0xe4, 0xe5, 0xac, 0x27, 0x97, 0x83, 0x4f, 0xe2, 0xcb, + 0x89, 0xb4, 0xeb, 0x8f, 0xe4, 0x05, 0xc9, 0xc9, 0x8a, 0xc8, 0xd0, 0x8a, 0x75, 0xe0, 0x3a, 0x78, + 0x72, 0x4b, 0x56, 0x71, 0xd6, 0x3f, 0xa7, 0x40, 0xb9, 0x49, 0x9d, 0x06, 0xf1, 0x3a, 0x68, 0xdf, + 0xb3, 0x31, 0x3d, 0x42, 0xde, 0xdd, 0x74, 0x93, 0x05, 0x96, 0x99, 0x4c, 0x60, 0xb8, 0xa3, 0x36, + 0x02, 0xdf, 0x58, 0x13, 0xbc, 0x08, 0x94, 0xeb, 0xaa, 0xdb, 0xc8, 0xea, 0x07, 0xb0, 0x14, 0x7d, + 0x4e, 0x66, 0x6f, 0x86, 0x2b, 0xea, 0x81, 0x6f, 0x68, 0x39, 0xc5, 0xf4, 0xfc, 0x0d, 0x13, 0xa1, + 0x06, 0x2a, 0xf9, 0x52, 0x45, 0x75, 0xdc, 0xfe, 0x31, 0x0b, 0xa6, 0x9b, 0xd4, 0x51, 0x3f, 0x81, + 0xc5, 0xf4, 0xce, 0x7c, 0x61, 0xfe, 0x6f, 0x75, 0x9b, 0xd9, 0x9d, 0xa7, 0xbd, 0x9a, 0x04, 0x1d, + 0x6f, 0xc8, 0x43, 0x30, 0xc3, 0x37, 0xdb, 0xe6, 0x48, 0x76, 0x08, 0xd3, 0xb6, 0xc6, 0x82, 0xa5, + 0xd5, 0xf9, 0x86, 0x19, 0xad, 0x1e, 0xc2, 0xc6, 0x50, 0x4f, 0xcf, 0x39, 0x2f, 0x57, 0x6a, 0xc6, + 0xc7, 0x28, 0x57, 0x82, 0x1e, 0xa7, 0x5c, 0xc3, 0x73, 0xaa, 0x7e, 0x51, 0x40, 0x79, 0x68, 0x48, + 0x6b, 0x23, 0xa5, 0xf2, 0x14, 0xed, 0xcd, 0xc4, 0x94, 0x38, 0x85, 0x01, 0x28, 0x66, 0x07, 0xce, + 0x1c, 0xa9, 0x95, 0xc1, 0x6b, 0xaf, 0x27, 0xc3, 0x47, 0x07, 0xd7, 0x0f, 0x2e, 0xaf, 0x75, 0xe5, + 0xea, 0x5a, 0x57, 0xfe, 0x5e, 0xeb, 0xca, 0xd7, 0x1b, 0xbd, 0x70, 0x75, 0xa3, 0x17, 0xfe, 0xdc, + 0xe8, 0x85, 0x83, 0x1d, 0xa7, 0xc7, 0x8e, 0xfb, 0x6d, 0xb3, 0x43, 0xdc, 0xea, 0x1e, 0x17, 0xe7, + 0xbf, 0x9f, 0x0d, 0xf9, 0x24, 0xe1, 0xc7, 0x6c, 0x45, 0x0f, 0x94, 0xf3, 0xec, 0x7b, 0x85, 0x5d, + 0x9c, 0x21, 0xda, 0x9e, 0xe3, 0xef, 0x86, 0x97, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x27, 0x3b, + 0x54, 0x9e, 0xd4, 0x08, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + CreateDenom(ctx context.Context, in *MsgCreateDenom, opts ...grpc.CallOption) (*MsgCreateDenomResponse, error) + Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) + Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) + ChangeAdmin(ctx context.Context, in *MsgChangeAdmin, opts ...grpc.CallOption) (*MsgChangeAdminResponse, error) + SetDenomMetadata(ctx context.Context, in *MsgSetDenomMetadata, opts ...grpc.CallOption) (*MsgSetDenomMetadataResponse, error) + ForceTransfer(ctx context.Context, in *MsgForceTransfer, opts ...grpc.CallOption) (*MsgForceTransferResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) CreateDenom(ctx context.Context, in *MsgCreateDenom, opts ...grpc.CallOption) (*MsgCreateDenomResponse, error) { + out := new(MsgCreateDenomResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Msg/CreateDenom", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) { + out := new(MsgMintResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Msg/Mint", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) { + out := new(MsgBurnResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Msg/Burn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ChangeAdmin(ctx context.Context, in *MsgChangeAdmin, opts ...grpc.CallOption) (*MsgChangeAdminResponse, error) { + out := new(MsgChangeAdminResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SetDenomMetadata(ctx context.Context, in *MsgSetDenomMetadata, opts ...grpc.CallOption) (*MsgSetDenomMetadataResponse, error) { + out := new(MsgSetDenomMetadataResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Msg/SetDenomMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ForceTransfer(ctx context.Context, in *MsgForceTransfer, opts ...grpc.CallOption) (*MsgForceTransferResponse, error) { + out := new(MsgForceTransferResponse) + err := c.cc.Invoke(ctx, "/osmosis.tokenfactory.v1beta1.Msg/ForceTransfer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + CreateDenom(context.Context, *MsgCreateDenom) (*MsgCreateDenomResponse, error) + Mint(context.Context, *MsgMint) (*MsgMintResponse, error) + Burn(context.Context, *MsgBurn) (*MsgBurnResponse, error) + ChangeAdmin(context.Context, *MsgChangeAdmin) (*MsgChangeAdminResponse, error) + SetDenomMetadata(context.Context, *MsgSetDenomMetadata) (*MsgSetDenomMetadataResponse, error) + ForceTransfer(context.Context, *MsgForceTransfer) (*MsgForceTransferResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) CreateDenom(ctx context.Context, req *MsgCreateDenom) (*MsgCreateDenomResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateDenom not implemented") +} +func (*UnimplementedMsgServer) Mint(ctx context.Context, req *MsgMint) (*MsgMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mint not implemented") +} +func (*UnimplementedMsgServer) Burn(ctx context.Context, req *MsgBurn) (*MsgBurnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Burn not implemented") +} +func (*UnimplementedMsgServer) ChangeAdmin(ctx context.Context, req *MsgChangeAdmin) (*MsgChangeAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ChangeAdmin not implemented") +} +func (*UnimplementedMsgServer) SetDenomMetadata(ctx context.Context, req *MsgSetDenomMetadata) (*MsgSetDenomMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetDenomMetadata not implemented") +} +func (*UnimplementedMsgServer) ForceTransfer(ctx context.Context, req *MsgForceTransfer) (*MsgForceTransferResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ForceTransfer not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_CreateDenom_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgCreateDenom) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).CreateDenom(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Msg/CreateDenom", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).CreateDenom(ctx, req.(*MsgCreateDenom)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Mint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMint) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Mint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Msg/Mint", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Mint(ctx, req.(*MsgMint)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Burn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgBurn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Burn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Msg/Burn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Burn(ctx, req.(*MsgBurn)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ChangeAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgChangeAdmin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ChangeAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Msg/ChangeAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ChangeAdmin(ctx, req.(*MsgChangeAdmin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SetDenomMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSetDenomMetadata) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SetDenomMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Msg/SetDenomMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SetDenomMetadata(ctx, req.(*MsgSetDenomMetadata)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ForceTransfer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgForceTransfer) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ForceTransfer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.tokenfactory.v1beta1.Msg/ForceTransfer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ForceTransfer(ctx, req.(*MsgForceTransfer)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "osmosis.tokenfactory.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateDenom", + Handler: _Msg_CreateDenom_Handler, + }, + { + MethodName: "Mint", + Handler: _Msg_Mint_Handler, + }, + { + MethodName: "Burn", + Handler: _Msg_Burn_Handler, + }, + { + MethodName: "ChangeAdmin", + Handler: _Msg_ChangeAdmin_Handler, + }, + { + MethodName: "SetDenomMetadata", + Handler: _Msg_SetDenomMetadata_Handler, + }, + { + MethodName: "ForceTransfer", + Handler: _Msg_ForceTransfer_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "osmosis/tokenfactory/v1beta1/tx.proto", +} + +func (m *MsgCreateDenom) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateDenom) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateDenom) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Subdenom) > 0 { + i -= len(m.Subdenom) + copy(dAtA[i:], m.Subdenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Subdenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgCreateDenomResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateDenomResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateDenomResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewTokenDenom) > 0 { + i -= len(m.NewTokenDenom) + copy(dAtA[i:], m.NewTokenDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewTokenDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMint) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMint) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMint) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.MintToAddress) > 0 { + i -= len(m.MintToAddress) + copy(dAtA[i:], m.MintToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.MintToAddress))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMintResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMintResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMintResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgBurn) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgBurn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BurnFromAddress) > 0 { + i -= len(m.BurnFromAddress) + copy(dAtA[i:], m.BurnFromAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.BurnFromAddress))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgBurnResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgBurnResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurnResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgChangeAdmin) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgChangeAdmin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChangeAdmin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewAdmin) > 0 { + i -= len(m.NewAdmin) + copy(dAtA[i:], m.NewAdmin) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewAdmin))) + i-- + dAtA[i] = 0x1a + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgChangeAdminResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgChangeAdminResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgChangeAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSetDenomMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetDenomMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetDenomMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSetDenomMetadataResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetDenomMetadataResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetDenomMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgForceTransfer) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgForceTransfer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgForceTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TransferToAddress) > 0 { + i -= len(m.TransferToAddress) + copy(dAtA[i:], m.TransferToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.TransferToAddress))) + i-- + dAtA[i] = 0x22 + } + if len(m.TransferFromAddress) > 0 { + i -= len(m.TransferFromAddress) + copy(dAtA[i:], m.TransferFromAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.TransferFromAddress))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgForceTransferResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgForceTransferResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgForceTransferResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgCreateDenom) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Subdenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgCreateDenomResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.NewTokenDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMint) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.MintToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMintResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgBurn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.BurnFromAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgBurnResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChangeAdmin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.NewAdmin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgChangeAdminResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSetDenomMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgSetDenomMetadataResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgForceTransfer) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.TransferFromAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.TransferToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgForceTransferResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgCreateDenom) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateDenom: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateDenom: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Subdenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Subdenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgCreateDenomResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateDenomResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateDenomResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewTokenDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewTokenDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMint) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMint: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMint: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MintToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MintToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMintResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMintResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMintResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBurn) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgBurn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBurn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BurnFromAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BurnFromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBurnResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgBurnResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBurnResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgChangeAdmin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgChangeAdmin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChangeAdmin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewAdmin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewAdmin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgChangeAdminResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgChangeAdminResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgChangeAdminResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetDenomMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetDenomMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetDenomMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetDenomMetadataResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetDenomMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetDenomMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgForceTransfer) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgForceTransfer: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgForceTransfer: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TransferFromAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TransferFromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TransferToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TransferToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgForceTransferResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgForceTransferResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgForceTransferResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)