Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ test:
COV_ROOT="/tmp/tokenfactory-coverage"
COV_UNIT_E2E="${COV_ROOT}/unit-e2e"
COV_SIMULATION="${COV_ROOT}/simulation"
COV_PKG="github.com/strangelove-ventures/tokenfactory/..."
COV_PKG="github.com/fetchai/tokenfactory/..."
COV_SIM_CMD=${COV_SIMULATION}/simulation.test
COV_SIM_COMMON=-Enabled=True -NumBlocks=100 -Commit=true -Period=5 -Verbose=false -test.v -test.gocoverdir=${COV_SIMULATION}

Expand Down
1 change: 0 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,6 @@ func NewApp(
app.BankKeeper,
app.DistrKeeper,
tokenFactoryCapabilities,
tokenfactorykeeper.DefaultIsSudoAdminFunc,
govModAddress,
)
wasmOpts = append(wasmOpts, bindings.RegisterCustomPlugins(app.BankKeeper, &app.TokenFactoryKeeper)...)
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ require (
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect
github.com/cosmos/ibc-go/v10 v10.3.0 // indirect
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -835,12 +835,10 @@ github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fr
github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0=
github.com/cosmos/iavl v1.2.4 h1:IHUrG8dkyueKEY72y92jajrizbkZKPZbMmG14QzsEkw=
github.com/cosmos/iavl v1.2.4/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw=
github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE=
github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco=
github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI=
github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E=
github.com/cosmos/ibc-go/v10 v10.3.0 h1:w5DkHih8qn15deAeFoTk778WJU+xC1krJ5kDnicfUBc=
github.com/cosmos/ibc-go/v10 v10.3.0/go.mod h1:CthaR7n4d23PJJ7wZHegmNgbVcLXCQql7EwHrAXnMtw=
github.com/cosmos/ibc-go/v10 v8.2.0 h1:7oCzyy1sZCcgpeQLnHxC56brsSz3KWwQGKXalXwXFzE=
github.com/cosmos/ibc-go/v10 v8.2.0/go.mod h1:wj3qx75iC/XNnsMqbPDCIGs0G6Y3E/lo3bdqCyoCy+8=
github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU=
github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0=
github.com/cosmos/ledger-cosmos-go v0.14.0 h1:WfCHricT3rPbkPSVKRH+L4fQGKYHuGOK9Edpel8TYpE=
Expand Down
7 changes: 7 additions & 0 deletions proto/osmosis/tokenfactory/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package osmosis.tokenfactory.v1beta1;
import "gogoproto/gogo.proto";
import "osmosis/tokenfactory/v1beta1/authorityMetadata.proto";
import "osmosis/tokenfactory/v1beta1/params.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/strangelove-ventures/tokenfactory/x/tokenfactory/types";

Expand All @@ -16,6 +17,12 @@ message GenesisState {
(gogoproto.moretags) = "yaml:\"factory_denoms\"",
(gogoproto.nullable) = false
];

repeated string sudo_admins = 3 [
(cosmos_proto.scalar) = "cosmos.AddressString",
(gogoproto.moretags) = "yaml:\"sudo_admins\"",
(gogoproto.nullable) = false
];
}

// GenesisDenom defines a tokenfactory denom that is defined within genesis
Expand Down
12 changes: 11 additions & 1 deletion x/tokenfactory/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {
panic(err)
}
}

sa := SudoAdmins{Keeper: k}
for _, genAdmin := range genState.GetSudoAdmins() {
if err := sa.AddSudoAdmin(ctx, genAdmin); err != nil {
panic(err)
}
}
}

// ExportGenesis returns the tokenfactory module's exported genesis.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
genDenoms := []types.GenesisDenom{}
var genDenoms []types.GenesisDenom
iterator := k.GetAllDenomsIterator(ctx)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
Expand All @@ -51,8 +58,11 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
})
}

sa := SudoAdmins{Keeper: k}

return &types.GenesisState{
FactoryDenoms: genDenoms,
Params: k.GetParams(ctx),
SudoAdmins: sa.GetAllSudoAdmins(ctx),
}
}
20 changes: 20 additions & 0 deletions x/tokenfactory/keeper/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper_test

import (
"github.com/strangelove-ventures/tokenfactory/x/tokenfactory/keeper"
"github.com/strangelove-ventures/tokenfactory/x/tokenfactory/types"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -29,6 +30,10 @@ func (suite *KeeperTestSuite) TestGenesis() {
},
},
},
SudoAdmins: []string{
"cosmos1t7egva48prqmzl59x5ngv4zx0dtrwewcdqdjr8",
"cosmos15czt5nhlnvayqq37xun9s9yus0d6y26dx74r5p",
},
}

suite.SetupTestForInitGenesis()
Expand All @@ -51,3 +56,18 @@ func (suite *KeeperTestSuite) TestGenesis() {
suite.Require().NotNil(exportedGenesis)
suite.Require().Equal(genesisState, *exportedGenesis)
}

func (suite *KeeperTestSuite) TestGenesisStoresSudoAdmins() {
genesisState := types.GenesisState{
SudoAdmins: []string{
suite.TestAccs[0].String(),
suite.TestAccs[1].String(),
},
}

sa := keeper.SudoAdmins{Keeper: suite.App.TokenFactoryKeeper}
suite.App.TokenFactoryKeeper.InitGenesis(suite.Ctx, genesisState)

suite.Require().True(sa.IsSudoAdmin(suite.Ctx, suite.TestAccs[0].String()))
suite.Require().True(sa.IsSudoAdmin(suite.Ctx, suite.TestAccs[1].String()))
}
17 changes: 2 additions & 15 deletions x/tokenfactory/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package keeper

import (
"context"
"fmt"

"github.com/strangelove-ventures/tokenfactory/x/tokenfactory/types"
Expand All @@ -16,9 +15,6 @@ import (
)

type (
// IsAdmin is a function signature that checks if an address is an admin.
IsSudoAdmin func(ctx context.Context, addr string) bool

Keeper struct {
cdc codec.BinaryCodec
storeKey store.StoreKey
Expand All @@ -33,8 +29,6 @@ type (
// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string

IsSudoAdminFunc IsSudoAdmin
}
)

Expand All @@ -47,16 +41,14 @@ func NewKeeper(
bankKeeper types.BankKeeper,
communityPoolKeeper types.CommunityPoolKeeper,
enabledCapabilities []string,
// use DefaultIsSudoAdminFunc if you don't have a custom one
isSudoAdminFunc IsSudoAdmin,
authority string,
) Keeper {
permAddrs := make(map[string]authtypes.PermissionsForAddress)
for name, perms := range maccPerms {
permAddrs[name] = authtypes.NewPermissionsForAddress(name, perms)
}

return Keeper{
k := Keeper{
cdc: cdc,
storeKey: storeKey,
permAddrs: permAddrs,
Expand All @@ -68,14 +60,9 @@ func NewKeeper(
authority: authority,

enabledCapabilities: enabledCapabilities,

IsSudoAdminFunc: isSudoAdminFunc,
}
}

// DefaultIsSudoAdminFunc returns false for all addresses.
func DefaultIsSudoAdminFunc(_ context.Context, _ string) bool {
return false
return k
}

// GetAuthority returns the x/mint module's authority.
Expand Down
4 changes: 4 additions & 0 deletions x/tokenfactory/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

// NativeDenom is denomination which is *NOT* related to tokenfactory
const NativeDenom = "any_non_tokenfactory_denom"

type KeeperTestSuite struct {
apptesting.KeeperTestHelper

Expand All @@ -40,6 +43,7 @@ func (suite *KeeperTestSuite) SetupTest() {
suite.queryClient = types.NewQueryClient(suite.QueryHelper)
suite.bankQueryClient = banktypes.NewQueryClient(suite.QueryHelper)
suite.msgServer = keeper.NewMsgServerImpl(suite.App.TokenFactoryKeeper)

}

func (suite *KeeperTestSuite) CreateDefaultDenom() {
Expand Down
6 changes: 4 additions & 2 deletions x/tokenfactory/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ func (server msgServer) Mint(goCtx context.Context, msg *types.MsgMint) (*types.
ctx := sdk.UnwrapSDKContext(goCtx)

sudoEnabled := types.IsCapabilityEnabled(server.Keeper.enabledCapabilities, types.EnableSudoMint)
senderIsSudoAble := server.IsSudoAdminFunc(goCtx, msg.Sender)
sa := SudoAdmins{Keeper: server.Keeper}
senderIsSudoAble := sa.IsSudoAdmin(goCtx, msg.Sender)
isSudo := sudoEnabled && senderIsSudoAble

if !isSudo {
Expand Down Expand Up @@ -116,7 +117,8 @@ func (server msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.
}

sudoEnabled := types.IsCapabilityEnabled(server.Keeper.enabledCapabilities, types.EnableSudoMint)
senderIsSudoAble := server.Keeper.IsSudoAdminFunc(goCtx, msg.Sender)
sa := SudoAdmins{Keeper: server.Keeper}
senderIsSudoAble := sa.IsSudoAdmin(goCtx, msg.Sender)
isSudo := sudoEnabled && senderIsSudoAble

if !isSudo {
Expand Down
33 changes: 19 additions & 14 deletions x/tokenfactory/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package keeper_test

import (
"context"
"fmt"

"github.com/strangelove-ventures/tokenfactory/x/tokenfactory/keeper"
"github.com/strangelove-ventures/tokenfactory/x/tokenfactory/types"

sdkmath "cosmossdk.io/math"
Expand All @@ -21,53 +21,58 @@ func (suite *KeeperTestSuite) TestMintDenomMsg() {
desc string
amount int64
mintDenom string
admin string
sender string
sudoer string
expectedMessageEvents int // the valid case should emit >= 1
}{
{
desc: "denom does not exist",
amount: 10,
mintDenom: "factory/osmo1t7egva48prqmzl59x5ngv4zx0dtrwewc9m7z44/evmos",
admin: suite.TestAccs[0].String(),
sender: suite.TestAccs[0].String(),
},
{
desc: "success case tokenfactory",
amount: 10,
mintDenom: suite.defaultDenom,
admin: suite.TestAccs[0].String(),
sender: suite.TestAccs[0].String(),
expectedMessageEvents: 1,
},
// Sudo Mints
{
desc: "successful sudo mint executed by an allowed sudoer",
amount: 10,
mintDenom: "unique",
admin: suite.TestAccs[0].String(),
sender: suite.TestAccs[0].String(),
sudoer: suite.TestAccs[0].String(), // this user can sudo mint
expectedMessageEvents: 1,
},
{
desc: "invalid sudo mint from a non admin",
amount: 10,
mintDenom: "unique",
admin: suite.TestAccs[0].String(),
sudoer: "nope",
desc: "invalid sudo mint from a non admin",
amount: 10,
mintDenom: "unique",
sender: suite.TestAccs[0].String(),
sudoer: suite.TestAccs[1].String(),
expectedMessageEvents: 0,
},
} {
suite.Run(fmt.Sprintf("Case %s", tc.desc), func() {
ctx := suite.Ctx.WithEventManager(sdk.NewEventManager())
suite.Require().Equal(0, len(ctx.EventManager().Events()))

// Override the default IsSudoAdminFunc for testing
suite.App.TokenFactoryKeeper.IsSudoAdminFunc = func(_ context.Context, addr string) bool {
return tc.sudoer == addr
sa := keeper.SudoAdmins{Keeper: suite.App.TokenFactoryKeeper}
if tc.sudoer != "" {
suite.NoError(sa.AddSudoAdmin(suite.Ctx, tc.sudoer))

defer func() {
suite.NoError(sa.RemoveSudoAdmin(suite.Ctx, tc.sudoer))
}()
}

suite.OverrideMsgServer(suite.App.TokenFactoryKeeper)

// Test mint message
suite.msgServer.Mint(ctx, types.NewMsgMint(tc.admin, sdk.NewInt64Coin(tc.mintDenom, tc.amount))) //nolint:errcheck
suite.msgServer.Mint(ctx, types.NewMsgMint(tc.sender, sdk.NewInt64Coin(tc.mintDenom, tc.amount))) //nolint:errcheck

// Ensure current number and type of event is emitted
suite.AssertEventEmitted(ctx, types.TypeMsgMint, tc.expectedMessageEvents)
Expand Down
80 changes: 80 additions & 0 deletions x/tokenfactory/keeper/sudo_admins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package keeper

import (
"context"

"cosmossdk.io/store/prefix"
store "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/strangelove-ventures/tokenfactory/x/tokenfactory/types"
)

type SudoAdmins struct {
Keeper
}

// GetSudoAdminsStore returns the substore for sudoers
func (k SudoAdmins) GetSudoAdminsStore(ctx sdk.Context) store.KVStore {
store := ctx.KVStore(k.storeKey)
return prefix.NewStore(store, types.GetSudoAdminsPrefix())
}

func (k SudoAdmins) AddSudoAdmin(ctx context.Context, admin string) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := k.GetSudoAdminsStore(sdkCtx)

addr, err := sdk.AccAddressFromBech32(admin)
if err != nil {
return err
}

// key = canonical address bytes
// value = dummy marker
store.Set(addr.Bytes(), []byte{1})

return nil
}

func (k SudoAdmins) RemoveSudoAdmin(ctx context.Context, admin string) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := k.GetSudoAdminsStore(sdkCtx)

addr, err := sdk.AccAddressFromBech32(admin)
if err != nil {
return err
}

store.Delete(addr.Bytes())
return nil
}

func (k SudoAdmins) IsSudoAdmin(ctx context.Context, admin string) bool {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := k.GetSudoAdminsStore(sdkCtx)

addr, err := sdk.AccAddressFromBech32(admin)
if err != nil {
return false
}

return store.Has(addr.Bytes())
}

func (k SudoAdmins) GetAllSudoAdmins(ctx context.Context) []string {
sdkCtx := sdk.UnwrapSDKContext(ctx)
store := k.GetSudoAdminsStore(sdkCtx)
iterator := store.Iterator(nil, nil)
defer iterator.Close()

prefix := sdk.GetConfig().GetBech32AccountAddrPrefix()
var admins []string
for ; iterator.Valid(); iterator.Next() {
admin, err := sdk.Bech32ifyAddressBytes(prefix, iterator.Key())
if err != nil {
panic(err)
}
admins = append(admins, admin)
}

return admins
}
Loading