Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: ADR-009: Supply module #782

Merged
merged 37 commits into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ada2f1b
started coingecko module
leobragaz Mar 9, 2022
4387c0f
finished coingecko module to get circulating-supply directly from node
leobragaz Mar 10, 2022
3c111a7
Merge branch 'master' of github.com:desmos-labs/desmos into leonardo/…
leobragaz Mar 14, 2022
3d84a52
added total-supply API grpc and rest endpoint
leobragaz Mar 16, 2022
aa20b9d
added test suite for supply module
leobragaz Mar 17, 2022
4461065
added x/supply tests
leobragaz Mar 18, 2022
5817252
Merge branch 'master' of github.com:desmos-labs/desmos into leonardo/…
leobragaz Mar 18, 2022
e996254
fixed imports
leobragaz Mar 18, 2022
6750391
First draft of ADR-009
leobragaz Mar 21, 2022
7a5b364
Applied suggestions
leobragaz Mar 21, 2022
4905532
Second review
leobragaz Mar 21, 2022
b7b9e8b
Merge branch 'leonardo/supply-module-adr' of github.com:desmos-labs/d…
leobragaz Mar 22, 2022
c3277cd
finished to implement supply module and tests
leobragaz Mar 22, 2022
a3da1b8
- renamed parameters
leobragaz Mar 23, 2022
bdbcb12
Merge branch 'master' of github.com:desmos-labs/desmos into leonardo/…
leobragaz Mar 23, 2022
8dff037
removed a function
leobragaz Mar 23, 2022
aa292e0
removed legacy querier
leobragaz Mar 24, 2022
b8c9dca
fixed tests errors
leobragaz Mar 24, 2022
d93a882
reorganized module functions
leobragaz Mar 24, 2022
30106f5
added tests
leobragaz Mar 25, 2022
7d6735b
Merge branch 'master' of github.com:desmos-labs/desmos into leonardo/…
leobragaz Mar 25, 2022
311e70c
added cli query to module
leobragaz Mar 28, 2022
3706511
switched from divider to divider_exponent as a query optional parameter
leobragaz Mar 29, 2022
ae7c345
renamed divider to divider_exponent in proto files
leobragaz Mar 29, 2022
22d52df
switched from custom response types to protobuf string type
leobragaz Apr 5, 2022
79278ff
fixing tests and lint errors
leobragaz Apr 5, 2022
0aa7c27
readded rest APIs
leobragaz Apr 6, 2022
fd16690
reformatted code
leobragaz Apr 6, 2022
30dd8da
edited rest queries
leobragaz Apr 6, 2022
deb9b16
revert grpc queries responses
leobragaz Apr 6, 2022
0093c06
moved divider exponent in a rest requests to make it optional
leobragaz Apr 6, 2022
983b0c0
revert to required divider exponent
leobragaz Apr 6, 2022
90f8ec4
fixed rest queries response
leobragaz Apr 6, 2022
5af8839
improved the REST queries to use Protobuf instead of Amino
RiccardoM Apr 8, 2022
3ec4b0c
chore: updated ADR
RiccardoM Apr 8, 2022
ea2101d
chore: added changeset entry
RiccardoM Apr 8, 2022
df47a9f
Merge branch 'master' into leonardo/coingecko-APIs
mergify[bot] Apr 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ import (
subspaceskeeper "github.com/desmos-labs/desmos/v3/x/subspaces/keeper"
subspacestypes "github.com/desmos-labs/desmos/v3/x/subspaces/types"

"github.com/desmos-labs/desmos/v3/x/supply"
supplykeeper "github.com/desmos-labs/desmos/v3/x/supply/keeper"
supplytypes "github.com/desmos-labs/desmos/v3/x/supply/types"

authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper"
Expand Down Expand Up @@ -222,6 +226,7 @@ var (
profiles.AppModuleBasic{},
relationships.AppModuleBasic{},
subspaces.AppModuleBasic{},
supply.AppModuleBasic{},
)

// Module account permissions
Expand Down Expand Up @@ -284,6 +289,7 @@ type DesmosApp struct {
SubspacesKeeper subspaceskeeper.Keeper
ProfileKeeper profileskeeper.Keeper
RelationshipsKeeper relationshipskeeper.Keeper
SupplyKeeper supplykeeper.Keeper

// Module Manager
mm *module.Manager
Expand Down Expand Up @@ -330,7 +336,7 @@ func NewDesmosApp(
authzkeeper.StoreKey, wasm.StoreKey,

// Custom modules
profilestypes.StoreKey, relationshipstypes.StoreKey, subspacestypes.StoreKey,
profilestypes.StoreKey, relationshipstypes.StoreKey, subspacestypes.StoreKey, supplytypes.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
Expand Down Expand Up @@ -455,6 +461,8 @@ func NewDesmosApp(
subspacestypes.NewMultiSubspacesHooks(app.RelationshipsKeeper.Hooks()),
)

app.SupplyKeeper = supplykeeper.NewKeeper(app.appCodec, app.AccountKeeper, app.BankKeeper, app.DistrKeeper)

// Create static IBC router, add transfer route, then set and seal it
ibcRouter := porttypes.NewRouter()
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule)
Expand Down Expand Up @@ -554,6 +562,7 @@ func NewDesmosApp(
subspaces.NewAppModule(appCodec, app.SubspacesKeeper, app.AccountKeeper, app.BankKeeper),
profilesModule,
relationships.NewAppModule(appCodec, app.RelationshipsKeeper, app.SubspacesKeeper, profilesv4.NewKeeper(keys[profilestypes.StoreKey], appCodec), app.AccountKeeper, app.BankKeeper),
supply.NewAppModule(appCodec, app.SupplyKeeper),
)

// During begin block slashing happens after distr.BeginBlocker so that
Expand Down Expand Up @@ -585,6 +594,7 @@ func NewDesmosApp(
subspacestypes.ModuleName,
relationshipstypes.ModuleName,
profilestypes.ModuleName,
supplytypes.ModuleName,
)
app.mm.SetOrderEndBlockers(
crisistypes.ModuleName,
Expand All @@ -610,6 +620,7 @@ func NewDesmosApp(
subspacestypes.ModuleName,
relationshipstypes.ModuleName,
profilestypes.ModuleName,
supplytypes.ModuleName,
)

// NOTE: The genutils module must occur after staking so that pools are
Expand Down Expand Up @@ -642,6 +653,7 @@ func NewDesmosApp(
subspacestypes.ModuleName,
profilestypes.ModuleName,
relationshipstypes.ModuleName,
supplytypes.ModuleName,

crisistypes.ModuleName,
)
Expand Down Expand Up @@ -673,6 +685,7 @@ func NewDesmosApp(
subspacestypes.ModuleName,
relationshipstypes.ModuleName,
profilestypes.ModuleName,
supplytypes.ModuleName,

crisistypes.ModuleName,
)
Expand Down Expand Up @@ -707,6 +720,7 @@ func NewDesmosApp(
wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper),

// Custom modules
supply.NewAppModule(appCodec, app.SupplyKeeper),
subspaces.NewAppModule(appCodec, app.SubspacesKeeper, app.AccountKeeper, app.BankKeeper),
profilesModule,
relationships.NewAppModule(appCodec, app.RelationshipsKeeper, app.SubspacesKeeper, profilesv4.NewKeeper(keys[profilestypes.StoreKey], appCodec), app.AccountKeeper, app.BankKeeper),
Expand Down
5 changes: 3 additions & 2 deletions docs/architecture/adr-009-supply-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## Status

DRAFTED
ACCEPTED

## Abstract

Expand All @@ -24,7 +24,8 @@ The APIs will be exposed in a new module called `x/supply` that will have the pu

### Queries

All the following APIs will have a custom param named `multiplier` that allows to set the multiplier to be used when returning the values. A `multiplier` of `0` will identify the whole token amount, while a multiplier of `1.000.000` will make the result display the values in millionth of units.
All the following APIs will have a custom param named `divider` that allows to set the divider to be used when
returning the values. A `divider` of `0` will identify the whole token amount, while a divider of `1.000.000` will make the result display the values in millionth of units.

#### Total Supply

Expand Down
73 changes: 73 additions & 0 deletions proto/desmos/supply/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
syntax = "proto3";
package desmos.supply.v1;

import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/desmos-labs/desmos/v3/x/supply/types";


// Query defines the gRPC querier service.
service Query {

// TotalSupply queries the total supply of the given denom, converted with the given divider
leobragaz marked this conversation as resolved.
Show resolved Hide resolved
rpc TotalSupply(QueryTotalSupplyRequest)
returns (QueryTotalSupplyResponse) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning a QueryTotalSupplyResponse, is there any way we can simply return a string here instead? So the REST response instead of looking like this

{
  "total_supply": "<amount>"
}

Can simply look like this:

"<amount>"

Maybe something like StringValue from wrappers.proto can work like this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, but that makes the Protobuf linter angry...any way to skip to kind of checks on query returns types? @RiccardoM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schermata 2022-04-05 alle 17 20 38

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result isn't what expected btw. Should we roll-back to the previous one?

Copy link
Contributor

@RiccardoM RiccardoM Apr 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering CoinMarketCap requires the supply value to be returned simply as a value, we need a way to have this as well. From their docs we can read:

API endpoint that displays ONLY 'Total Supply' as a numerical value (e.g. http://chainz.cryptoid.info/grs/api.dws?q=totalcoins)

Probably the best way would be to register a custom REST endpoint. This can be done using the RegisterRESTRoutes module method and registering a custom endpoint there.

Once that's done, we can simply revert to the previous answers for the gRPC endpoints

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both done 👍

option (google.api.http).get = "/desmos/supply/v1/total-supply/{denom}";
}

// CirculatingSupply queries the amount of tokens circulating in the market of the given
leobragaz marked this conversation as resolved.
Show resolved Hide resolved
rpc CirculatingSupply(QueryCirculatingSupplyRequest)
returns (QueryCirculatingSupplyResponse) {
option (google.api.http).get = "/desmos/supply/v1/circulating-supply/{denom}";
}
}

// QueryTotalSupplyRequest is the request type for Query/TotalSupply RPC method
message QueryTotalSupplyRequest {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// coin denom to query the circulating supply for
string denom = 1;

// divider is a factor used to convert the supply amount to the desired representation
uint64 divider = 2;
}

// QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC method
message QueryTotalSupplyResponse {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string total_supply = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}

// QueryCirculatingSupplyRequest is the request type for the Query/CirculatingSupply RPC method
message QueryCirculatingSupplyRequest {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// coin denom to query the circulating supply for
string denom = 1;

// divider is a factor used to convert the supply amount to the desired representation
uint64 divider = 2;
leobragaz marked this conversation as resolved.
Show resolved Hide resolved
}

// QueryCirculatingSupplyRequest is the response type for the Query/CirculatingSupply RPC method
message QueryCirculatingSupplyResponse {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string circulating_supply = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}
174 changes: 174 additions & 0 deletions x/supply/client/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package cli_test

import (
"fmt"
"testing"

clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
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"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/desmos-labs/desmos/v3/testutil"
"github.com/desmos-labs/desmos/v3/x/supply/client/cli"
"github.com/desmos-labs/desmos/v3/x/supply/types"
"github.com/stretchr/testify/suite"
tmcli "github.com/tendermint/tendermint/libs/cli"
)

type IntegrationTestSuite struct {
suite.Suite

cfg network.Config
network *network.Network
}

func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")

cfg := testutil.DefaultConfig()
genesisState := cfg.GenesisState
cfg.NumValidators = 2

var authData authtypes.GenesisState
s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[authtypes.ModuleName], &authData))

var bankData banktypes.GenesisState
s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[banktypes.ModuleName], &bankData))

var stakingData stakingtypes.GenesisState
s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[stakingtypes.ModuleName], &stakingData))

s.cfg = cfg
s.network = network.New(s.T(), cfg)
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
}

func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}

func (s *IntegrationTestSuite) TestCmdQueryTotalSupply() {
val := s.network.Validators[0]

testCases := []struct {
name string
args []string
shouldErr bool
expectedOutput types.QueryTotalSupplyResponse
}{
{
name: "invalid denom returns error",
args: []string{
"",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
shouldErr: true,
},
{
name: "total supply returned correctly without divider conversion applied",
args: []string{
"stake",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
shouldErr: false,
expectedOutput: types.QueryTotalSupplyResponse{TotalSupply: sdk.NewInt(1000000020)},
},
{
name: " total supply returned correctly with divider conversion applied",
leobragaz marked this conversation as resolved.
Show resolved Hide resolved
args: []string{
"stake",
"100",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
shouldErr: false,
expectedOutput: types.QueryTotalSupplyResponse{TotalSupply: sdk.NewInt(10000000)},
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.GetCmdQueryTotalSupply()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)

if tc.shouldErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)

var response types.QueryTotalSupplyResponse
s.Require().NoError(clientCtx.JSONCodec.UnmarshalJSON(out.Bytes(), &response), out.String())
s.Require().Equal(tc.expectedOutput.TotalSupply, response.TotalSupply)
}
})
}
}

func (s *IntegrationTestSuite) TestCmdQueryCirculatingSupply() {
val := s.network.Validators[0]

testCases := []struct {
name string
args []string
shouldErr bool
expectedOutput types.QueryCirculatingSupplyResponse
}{
{
name: "invalid denom returns error",
args: []string{
"",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
shouldErr: true,
},
{
name: "circulating supply returned correctly without divider conversion applied",
args: []string{
"stake",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
shouldErr: false,
expectedOutput: types.QueryCirculatingSupplyResponse{CirculatingSupply: sdk.NewInt(1000000020)},
},
{
name: " circulating supply returned correctly with divider conversion applied",
args: []string{
"stake",
"100",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
shouldErr: false,
expectedOutput: types.QueryCirculatingSupplyResponse{CirculatingSupply: sdk.NewInt(10000000)},
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.GetCmdQueryCirculatingSupply()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)

if tc.shouldErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)

var response types.QueryCirculatingSupplyResponse
s.Require().NoError(clientCtx.JSONCodec.UnmarshalJSON(out.Bytes(), &response), out.String())
s.Require().Equal(tc.expectedOutput.CirculatingSupply, response.CirculatingSupply)
}
})
}
}
Loading