Skip to content

Commit

Permalink
Merge pull request #125 from iov-one/burner-module
Browse files Browse the repository at this point in the history
Adds a burner module
  • Loading branch information
merge-when-green[bot] authored Oct 29, 2021
2 parents 640e034 + 33b4c91 commit b6f8d9a
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 7 deletions.
18 changes: 14 additions & 4 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ import (
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

"github.com/iov-one/starnamed/x/burner"
burnertypes "github.com/iov-one/starnamed/x/burner/types"
"github.com/iov-one/starnamed/x/configuration"
"github.com/iov-one/starnamed/x/offchain"
"github.com/iov-one/starnamed/x/starname"
Expand Down Expand Up @@ -208,11 +210,17 @@ var (
govtypes.ModuleName: {authtypes.Burner},
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
wasm.ModuleName: {authtypes.Burner},
burnertypes.ModuleName: {authtypes.Burner},
}

//NOTE: this was included from wasmd repo but the allowedReceivingModAcc variable was not used,
/*allowedReceivingModAcc = map[string]bool{
//distrtypes.ModuleName: true,
}*/

// module accounts that are allowed to receive tokens
allowedReceivingModAcc = map[string]bool{
distrtypes.ModuleName: true,
allowedReceivingModules = map[string]bool{
burnertypes.ModuleName: true,
}
)

Expand Down Expand Up @@ -481,6 +489,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
transferModule,
configuration.NewAppModule(app.configKeeper),
starname.NewAppModule(app.starnameKeeper),
burner.NewAppModule(app.bankKeeper, app.accountKeeper),
)

// During begin block slashing happens after distr.BeginBlocker so that
Expand All @@ -491,7 +500,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
upgradetypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName,
evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName,
)
app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName, starname.ModuleName)
app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName, burnertypes.ModuleName, starname.ModuleName)

// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
Expand Down Expand Up @@ -611,7 +620,8 @@ func (app *WasmApp) LoadHeight(height int64) error {
func (app *WasmApp) ModuleAccountAddrs() map[string]bool {
modAccAddrs := make(map[string]bool)
for acc := range maccPerms {
modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true
moduleCanReceive, modulePresentInArray := allowedReceivingModules[acc]
modAccAddrs[authtypes.NewModuleAddress(acc).String()] = !(modulePresentInArray && moduleCanReceive)
}

return modAccAddrs
Expand Down
11 changes: 9 additions & 2 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import (
"os"
"testing"

"github.com/iov-one/starnamed/x/wasm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
db "github.com/tendermint/tm-db"

"github.com/iov-one/starnamed/x/wasm"
)

var emptyWasmOpts []wasm.Option = nil
Expand Down Expand Up @@ -45,7 +46,13 @@ func TestBlockedAddrs(t *testing.T) {

for acc := range maccPerms {
t.Run(acc, func(t *testing.T) {
require.True(t, gapp.bankKeeper.BlockedAddr(gapp.accountKeeper.GetModuleAddress(acc)),
var expected bool
if allowedReceivingModules[acc] {
expected = false
} else {
expected = true
}
require.Equal(t, expected, gapp.bankKeeper.BlockedAddr(gapp.accountKeeper.GetModuleAddress(acc)),
"ensure that blocked addresses are properly set in bank keeper",
)
})
Expand Down
1 change: 1 addition & 0 deletions scripts/integration/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ FEE=${DENOM_FEE:-tiov}
CHAIN_ID=${CHAIN:-testing}
MONIKER=${MONIKER:-node001}

rm -f "$HOME"/.${BINARY}/config/genesis.json
${BINARY} init --chain-id "$CHAIN_ID" "$MONIKER" 2>&1 | jq .chain_id
sed --in-place 's/timeout_commit = "5s"/timeout_commit = "1s"/' "$HOME"/.${BINARY}/config/config.toml
sed --in-place 's/enable = false/enable = true/' "$HOME"/.${BINARY}/config/app.toml # enable api
Expand Down
21 changes: 20 additions & 1 deletion scripts/integration/test/CLI.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Base64 } from "js-base64";
import { gasPrices, cli, denomFee, denomStake, getBalance, memo, msig1, msig1SignTx, signAndBroadcastTx, signer, w1, w2, writeTmpJson, makeTx } from "./common";
import { burner, cli, denomFee, denomStake, gasPrices, getBalance, memo, msig1, msig1SignTx, signAndBroadcastTx, signer, w1, w2, writeTmpJson, makeTx } from "./common";
import compareObjects from "./compareObjects";
import forge from "node-forge";

Expand Down Expand Up @@ -602,11 +602,30 @@ describe( "Tests the CLI.", () => {
expect( resolved1.account.metadata_uri ).toEqual( undefined );
} );


it( `Should throw an error while querying the yield for less than 100k blocks`, async () => {
try {
cli(["query", "starname", "yield"]);
} catch (e) {
expect(e.message).toContain("not enough data")
}
} );


it( `Should burn tokens.`, async () => {
const signer = w1;
const amount = 1e6;
const supply0 = { balances: cli( [ "query", "bank", "total" ] ).supply };
const balance0 = cli( [ "query", "bank", "balances", signer ] );
const burned = cli( [ "tx", "send", signer, burner, `${amount}${denomFee}`, "--yes", "--broadcast-mode", "block", "--gas-prices", gasPrices, "--memo", memo() ] );
const supply = { balances: cli( [ "query", "bank", "total" ] ).supply };
const balance = cli( [ "query", "bank", "balances", signer ] );
const blackhole = cli( [ "query", "bank", "balances", burner ] );

expect( burned.txhash ).toBeDefined();
if ( !burned.logs ) throw new Error( registered.raw_log );
expect( +getBalance( supply ) ).toEqual( +getBalance( supply0 ) - amount );
expect( +getBalance( balance ) ).toBeLessThan( +getBalance( balance0 ) - amount); // less than to account for fees
expect( +getBalance( blackhole ) ).toBe( 0 );
} );
} );
1 change: 1 addition & 0 deletions scripts/integration/test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const w1 = "star19jj4wc3lxd54hkzl42m7ze73rzy3dd3wry2f3q"; // w1
export const w2 = "star1l4mvu36chkj9lczjhy9anshptdfm497fune6la"; // w2
export const w3 = "star1aj9qqrftdqussgpnq6lqj08gwy6ysppf53c8e9"; // w3
export const msig1 = "star1d3lhm5vtta78cm7c7ytzqh7z5pcgktmautntqv"; // msig1
export const burner = "star1v7uw4xhrcv0vk7qp8jf9lu3hm5d8uu5ywlkzeg"; // burner

const dirSdk = process.env.COSMOS_SDK_DIR || String( spawnSync( "go", [ "list", "-f", `"{{ .Dir }}"`, "-m", "github.com/cosmos/cosmos-sdk" ] ).stdout ).trim().slice( 1, -1 );

Expand Down
21 changes: 21 additions & 0 deletions x/burner/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package burner

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/iov-one/starnamed/x/burner/types"
)

//TODO: we could add a test for this function

//EndBlocker burns all the coins owned by the burner module
func EndBlocker(ctx sdk.Context, supplyKeeper types.SupplyKeeper, accountKeeper types.AccountKeeper) {
moduleAcc := accountKeeper.GetModuleAccount(ctx, types.ModuleName)
if balance := supplyKeeper.GetAllBalances(ctx, moduleAcc.GetAddress()); !balance.IsZero() {
if err := supplyKeeper.BurnCoins(ctx, types.ModuleName, balance); err != nil {
panic(fmt.Sprintf("Error while burning tokens of the burner module account: %s", err.Error()))
}
}
}
3 changes: 3 additions & 0 deletions x/burner/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package burner contains the burner module, that burns all tokens sent
// to its address (star1v7uw4xhrcv0vk7qp8jf9lu3hm5d8uu5ywlkzeg)
package burner
133 changes: 133 additions & 0 deletions x/burner/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package burner

import (
"encoding/json"
"fmt"

"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"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"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"

"github.com/iov-one/starnamed/x/burner/types"
)

var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
)

// AppModuleBasic defines the basic application module used by the burner module.
type AppModuleBasic struct {
cdc codec.Marshaler
}

// RegisterLegacyAminoCodec registers the amino codec.
func (b AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {
}

// RegisterGRPCGatewayRoutes registers the query handler client.
func (b AppModuleBasic) RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux) {
}

// Name returns the burner module's name.
func (AppModuleBasic) Name() string { return types.ModuleName }

// DefaultGenesis returns default genesis state as raw bytes for the burner module.
func (AppModuleBasic) DefaultGenesis(codec.JSONMarshaler) json.RawMessage {
return nil
}

// ValidateGenesis performs genesis state validation for the burner module.
func (b AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ client.TxEncodingConfig, genesisData json.RawMessage) error {
if len(genesisData) > 0 {
return fmt.Errorf("invalid genesis data for module burner: should be empty")
}
return nil
}

// RegisterRESTRoutes registers the REST routes for this module.
func (AppModuleBasic) RegisterRESTRoutes(client.Context, *mux.Router) {
}

// GetQueryCmd returns no root query command for this module.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return nil
}

// GetTxCmd returns the root tx command for this module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
}

// RegisterInterfaces implements InterfaceModule
func (b AppModuleBasic) RegisterInterfaces(cdctypes.InterfaceRegistry) {
}

// AppModule implements an application module for the burner module.
type AppModule struct {
AppModuleBasic
supplyKeeper types.SupplyKeeper
accountKeeper types.AccountKeeper
}

// NewAppModule creates a new AppModule object.
func NewAppModule(supplyKeeper types.SupplyKeeper, accountKeeper types.AccountKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
supplyKeeper: supplyKeeper,
accountKeeper: accountKeeper,
}
}

// Name returns the burner module's name.
func (am AppModule) Name() string { return am.AppModuleBasic.Name() }

// RegisterServices allows a module to register services
func (am AppModule) RegisterServices(module.Configurator) {
}

// LegacyQuerierHandler provides an sdk.Querier object that uses the legacy amino codec.
func (AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "%s", path[0])
}
}

// RegisterInvariants registers the burner module invariants.
func (AppModule) RegisterInvariants(sdk.InvariantRegistry) {}

// Route returns the message routing key for the burner module.
func (am AppModule) Route() sdk.Route {
return sdk.NewRoute(types.ModuleName, func(sdk.Context, sdk.Msg) (*sdk.Result, error) {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "unknown request")
})
}

// QuerierRoute returns the burner module's querier route name.
func (AppModule) QuerierRoute() string { return types.ModuleName }

// BeginBlock returns the begin blocker for the burner module.
func (AppModule) BeginBlock(sdk.Context, abci.RequestBeginBlock) {}

// EndBlock returns the end blocker for the burner module. It returns no validator updates.
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
EndBlocker(ctx, am.supplyKeeper, am.accountKeeper)
return []abci.ValidatorUpdate{}
}

// InitGenesis performs genesis initialization for the burner module. It returns no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}

// ExportGenesis returns the exported genesis state as raw bytes for the burner module.
func (am AppModule) ExportGenesis(sdk.Context, codec.JSONMarshaler) json.RawMessage {
return am.DefaultGenesis(nil)
}
16 changes: 16 additions & 0 deletions x/burner/types/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

type SupplyKeeper interface {
GetAllBalances(sdk.Context, sdk.AccAddress) sdk.Coins
BurnCoins(sdk.Context, string, sdk.Coins) error
}

type AccountKeeper interface {
GetModuleAddress(string) sdk.AccAddress
GetModuleAccount(sdk.Context, string) types.ModuleAccountI
}
8 changes: 8 additions & 0 deletions x/burner/types/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package types

// Module names
const (
// ModuleName is the name of the module
// the corresponding bech32 address is star1v7uw4xhrcv0vk7qp8jf9lu3hm5d8uu5ywlkzeg
ModuleName = "burner"
)

0 comments on commit b6f8d9a

Please sign in to comment.