Skip to content

Commit

Permalink
tests: token factory
Browse files Browse the repository at this point in the history
  • Loading branch information
emidev98 committed Aug 28, 2023
1 parent b826d41 commit 1af15e5
Show file tree
Hide file tree
Showing 6 changed files with 664 additions and 2 deletions.
14 changes: 14 additions & 0 deletions app/app_testing/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/terra-money/core/v2/app"
terra_app "github.com/terra-money/core/v2/app"
appparams "github.com/terra-money/core/v2/app/params"
terrraParams "github.com/terra-money/core/v2/app/params"
"github.com/terra-money/core/v2/app/wasmconfig"
tokenfactorytypes "github.com/terra-money/core/v2/x/tokenfactory/types"
Expand All @@ -42,6 +43,7 @@ type AppTestSuite struct {

// Setup sets up basic environment for suite (App, Ctx, and test accounts)
func (s *AppTestSuite) Setup() {
appparams.RegisterAddressesConfig()
baseTestAccts := CreateRandomAccounts(3)
encCfg := terra_app.MakeEncodingConfig()

Expand Down Expand Up @@ -72,6 +74,18 @@ func (s *AppTestSuite) Setup() {
s.App.DistrKeeper.SetFeePool(s.Ctx, distrtypes.InitialFeePool())
}

func (s *AppTestSuite) AssertEventEmitted(ctx sdk.Context, eventTypeExpected string, numEventsExpected int) {
allEvents := ctx.EventManager().Events()
// filter out other events
actualEvents := make([]sdk.Event, 0)
for _, event := range allEvents {
if event.Type == eventTypeExpected {
actualEvents = append(actualEvents, event)
}
}
s.Require().Equal(numEventsExpected, len(actualEvents))
}

// CreateRandomAccounts is a function return a list of randomly generated AccAddresses
func CreateRandomAccounts(numAccts int) []sdk.AccAddress {
testAddrs := make([]sdk.AccAddress, numAccts)
Expand Down
66 changes: 66 additions & 0 deletions x/tokenfactory/client/cli/query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package cli_test

import (
gocontext "context"
"testing"

"cosmossdk.io/math"
"github.com/stretchr/testify/suite"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/terra-money/core/v2/app/app_testing"
"github.com/terra-money/core/v2/app/config"
"github.com/terra-money/core/v2/x/tokenfactory/types"
)

type QueryTestSuite struct {
app_testing.AppTestSuite
}

func (s *QueryTestSuite) TestQueriesNeverAlterState() {
s.Setup()

// fund acc
fundAccsAmount := sdk.NewCoins(sdk.NewCoin(config.BondDenom, math.NewInt(1_000_000_000)))
s.FundAcc(s.TestAccs[0], fundAccsAmount)
// create new token
_, err := s.App.TokenFactoryKeeper.CreateDenom(s.Ctx, s.TestAccs[0].String(), "tokenfactory")
s.Require().NoError(err)

testCases := []struct {
name string
query string
input interface{}
output interface{}
}{
{
"Query denom authority metadata",
"/osmosis.tokenfactory.v1beta1.Query/DenomAuthorityMetadata",
&types.QueryDenomAuthorityMetadataRequest{Denom: "tokenfactory"},
&types.QueryDenomAuthorityMetadataResponse{},
},
{
"Query denoms by creator",
"/osmosis.tokenfactory.v1beta1.Query/DenomsFromCreator",
&types.QueryDenomsFromCreatorRequest{Creator: s.TestAccs[0].String()},
&types.QueryDenomsFromCreatorResponse{},
},
{
"Query params",
"/osmosis.tokenfactory.v1beta1.Query/Params",
&types.QueryParamsRequest{},
&types.QueryParamsResponse{},
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
err := s.QueryHelper.Invoke(gocontext.Background(), tc.query, tc.input, tc.output)
s.Require().NoError(err)
})
}
}

func TestQueryTestSuite(t *testing.T) {
suite.Run(t, new(QueryTestSuite))
}
2 changes: 0 additions & 2 deletions x/tokenfactory/keeper/before_send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,6 @@ func (s *KeeperTestSuite) TestBeforeSendHook() {
// mint enough coins to the creator
_, err = s.msgServer.Mint(sdk.WrapSDKContext(s.Ctx), types.NewMsgMint(s.TestAccs[0].String(), sdk.NewInt64Coin(denom, 1000000000)))
s.Require().NoError(err)
// mint some non token factory denom coins for testing
s.FundAcc(sdk.AccAddress(s.TestAccs[0].String()), sdk.Coins{sdk.NewInt64Coin("foo", 100000000000)})

// set beforesend hook to the new denom
_, err = s.msgServer.SetBeforeSendHook(sdk.WrapSDKContext(s.Ctx), types.NewMsgSetBeforeSendHook(s.TestAccs[0].String(), denom, cosmwasmAddress.String()))
Expand Down
242 changes: 242 additions & 0 deletions x/tokenfactory/keeper/createdenom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package keeper_test

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

"github.com/terra-money/core/v2/app/config"
"github.com/terra-money/core/v2/x/tokenfactory/types"
)

func (s *KeeperTestSuite) TestMsgCreateDenom() {
var (
tokenFactoryKeeper = s.App.TokenFactoryKeeper
bankKeeper = s.App.BankKeeper
denomCreationFee = sdk.NewCoins(sdk.NewCoin("uluna", sdk.NewInt(1000000)))
)

// Set the denom creation fee. It is currently turned off in favor
// of gas charge by default.
params := s.App.TokenFactoryKeeper.GetParams(s.Ctx)
params.DenomCreationFee = denomCreationFee
s.App.TokenFactoryKeeper.SetParams(s.Ctx, params)

// Fund denom creation fee for every execution of MsgCreateDenom.
s.FundAcc(s.TestAccs[0], denomCreationFee)
s.FundAcc(s.TestAccs[0], denomCreationFee)
s.FundAcc(s.TestAccs[1], denomCreationFee)

// Get balance of acc 0 before creating a denom
preCreateBalance := bankKeeper.GetBalance(s.Ctx, s.TestAccs[0], denomCreationFee[0].Denom)

// Creating a denom should work
res, err := s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[0].String(), "bitcoin"))
s.Require().NoError(err)
s.Require().NotEmpty(res.GetNewTokenDenom())

// Make sure that the admin is set correctly
queryRes, err := s.queryClient.DenomAuthorityMetadata(s.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{
Denom: res.GetNewTokenDenom(),
})
s.Require().NoError(err)
s.Require().Equal(s.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin)

// Make sure that creation fee was deducted
postCreateBalance := bankKeeper.GetBalance(s.Ctx, s.TestAccs[0], tokenFactoryKeeper.GetParams(s.Ctx).DenomCreationFee[0].Denom)
s.Require().True(preCreateBalance.Sub(postCreateBalance).IsEqual(denomCreationFee[0]))

// Make sure that a second version of the same denom can't be recreated
_, err = s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[0].String(), "bitcoin"))
s.Require().Error(err)

// Creating a second denom should work
res, err = s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[0].String(), "litecoin"))
s.Require().NoError(err)
s.Require().NotEmpty(res.GetNewTokenDenom())

// Try querying all the denoms created by s.TestAccs[0]
queryRes2, err := s.queryClient.DenomsFromCreator(s.Ctx.Context(), &types.QueryDenomsFromCreatorRequest{
Creator: s.TestAccs[0].String(),
})
s.Require().NoError(err)
s.Require().Len(queryRes2.Denoms, 2)

// Make sure that a second account can create a denom with the same subdenom
res, err = s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[1].String(), "bitcoin"))
s.Require().NoError(err)
s.Require().NotEmpty(res.GetNewTokenDenom())

// Make sure that an address with a "/" in it can't create denoms
_, err = s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom("w.eth/creator", "bitcoin"))
s.Require().Error(err)
}

func (s *KeeperTestSuite) TestCreateDenom() {
var (
defaultDenomCreationFee = types.Params{DenomCreationFee: sdk.NewCoins(sdk.NewCoin(config.BondDenom, sdk.NewInt(50000000)))}
nilCreationFee = types.Params{DenomCreationFee: nil}
largeCreationFee = types.Params{DenomCreationFee: sdk.NewCoins(sdk.NewCoin(config.BondDenom, 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 := s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[0].String(), "bitcoin"))
s.Require().NoError(err)
},
subdenom: "bitcoin",
valid: false,
},
{
desc: "success case: defaultDenomCreationFee",
denomCreationFee: defaultDenomCreationFee,
subdenom: "evmos",
valid: true,
},
{
desc: "success case: nilCreationFee",
denomCreationFee: nilCreationFee,
subdenom: "ucoin",
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,
},
} {
s.SetupTest()
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
if tc.setup != nil {
tc.setup()
}
tokenFactoryKeeper := s.App.TokenFactoryKeeper
bankKeeper := s.App.BankKeeper
// Set denom creation fee in params
s.FundAcc(s.TestAccs[0], defaultDenomCreationFee.DenomCreationFee)
tokenFactoryKeeper.SetParams(s.Ctx, tc.denomCreationFee)
denomCreationFee := tokenFactoryKeeper.GetParams(s.Ctx).DenomCreationFee
s.Require().Equal(tc.denomCreationFee.DenomCreationFee, denomCreationFee)

// note balance, create a tokenfactory denom, then note balance again
preCreateBalance := bankKeeper.GetAllBalances(s.Ctx, s.TestAccs[0])
res, err := s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[0].String(), tc.subdenom))
postCreateBalance := bankKeeper.GetAllBalances(s.Ctx, s.TestAccs[0])
if tc.valid {
s.Require().NoError(err)
s.Require().True(preCreateBalance.Sub(postCreateBalance[0]).IsEqual(denomCreationFee))

// Make sure that the admin is set correctly
queryRes, err := s.queryClient.DenomAuthorityMetadata(s.Ctx.Context(), &types.QueryDenomAuthorityMetadataRequest{
Denom: res.GetNewTokenDenom(),
})

s.Require().NoError(err)
s.Require().Equal(s.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin)

// Make sure that the denom metadata is initialized correctly
metadata, found := bankKeeper.GetDenomMetaData(s.Ctx, res.GetNewTokenDenom())
s.Require().True(found)
s.Require().Equal(banktypes.Metadata{
DenomUnits: []*banktypes.DenomUnit{{
Denom: res.GetNewTokenDenom(),
Exponent: 0,
}},
Base: res.GetNewTokenDenom(),
}, metadata)
} else {
s.Require().Error(err)
// Ensure we don't charge if we expect an error
s.Require().True(preCreateBalance.IsEqual(postCreateBalance))
}
})
}
}

func (s *KeeperTestSuite) TestGasConsume() {
// It's hard to estimate exactly how much gas will be consumed when creating a
// denom, because besides consuming the gas specified by the params, the keeper
// also does a bunch of other things that consume gas.
//
// Rather, we test whether the gas consumed is within a range. Specifically,
// the range [gasConsume, gasConsume + offset]. If the actual gas consumption
// falls within the range for all test cases, we consider the test passed.
//
// In experience, the total amount of gas consumed should consume be ~30k more
// than the set amount.
const offset = 50000

for _, tc := range []struct {
desc string
gasConsume uint64
}{
{
desc: "gas consume zero",
gasConsume: 0,
},
{
desc: "gas consume 1,000,000",
gasConsume: 1_000_000,
},
{
desc: "gas consume 10,000,000",
gasConsume: 10_000_000,
},
{
desc: "gas consume 25,000,000",
gasConsume: 25_000_000,
},
{
desc: "gas consume 50,000,000",
gasConsume: 50_000_000,
},
{
desc: "gas consume 200,000,000",
gasConsume: 200_000_000,
},
} {
s.SetupTest()
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
// set params with the gas consume amount
s.App.TokenFactoryKeeper.SetParams(s.Ctx, types.NewParams(nil, tc.gasConsume))

// amount of gas consumed prior to the denom creation
gasConsumedBefore := s.Ctx.GasMeter().GasConsumed()

// create a denom
_, err := s.msgServer.CreateDenom(sdk.WrapSDKContext(s.Ctx), types.NewMsgCreateDenom(s.TestAccs[0].String(), "larry"))
s.Require().NoError(err)

// amount of gas consumed after the denom creation
gasConsumedAfter := s.Ctx.GasMeter().GasConsumed()

// the amount of gas consumed must be within the range
gasConsumed := gasConsumedAfter - gasConsumedBefore
s.Require().Greater(gasConsumed, tc.gasConsume)
s.Require().Less(gasConsumed, tc.gasConsume+offset)
})
}
}
Loading

0 comments on commit 1af15e5

Please sign in to comment.