Skip to content

Commit

Permalink
Merge branch 'main' into 1749-support-setting-a-NAV-attribute-on-meta…
Browse files Browse the repository at this point in the history
…data-scopes
  • Loading branch information
iramiller authored Jan 26, 2024
2 parents 38ce700 + c843436 commit ae5647e
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

* Remove deleted marker send deny entries [#1666](https://github.com/provenance-io/provenance/issues/1666).
* Update protos, naming, and documentation to use mills [#1813](https://github.com/provenance-io/provenance/issues/1813).
* Update marker transfer to work with groups [#1818](https://github.com/provenance-io/provenance/issues/1818).

### Dependencies

Expand Down
2 changes: 2 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,10 +572,12 @@ func New(
authtypes.NewModuleAddress(stakingtypes.BondedPoolName), // Allow bond denom to be a restricted coin.
authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName), // Allow bond denom to be a restricted coin.
}

app.MarkerKeeper = markerkeeper.NewKeeper(
appCodec, keys[markertypes.StoreKey], app.GetSubspace(markertypes.ModuleName),
app.AccountKeeper, app.BankKeeper, app.AuthzKeeper, app.FeeGrantKeeper,
app.AttributeKeeper, app.NameKeeper, app.TransferKeeper, markerReqAttrBypassAddrs,
NewGroupCheckerFunc(app.GroupKeeper),
)

app.MetadataKeeper = metadatakeeper.NewKeeper(
Expand Down
34 changes: 34 additions & 0 deletions app/group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package app

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/group"
)

// GroupCheckerFunc convenient type to match the GroupChecker interface.
type GroupCheckerFunc func(sdk.Context, sdk.AccAddress) bool

// GroupPolicyQuerier provides functionality to query group policies.
type GroupPolicyQuerier interface {
GroupPolicyInfo(goCtx context.Context, request *group.QueryGroupPolicyInfoRequest) (*group.QueryGroupPolicyInfoResponse, error)
}

// IsGroupAddress checks if the account is a group address.
func (t GroupCheckerFunc) IsGroupAddress(ctx sdk.Context, account sdk.AccAddress) bool {
if account == nil {
return false
}
return t(ctx, account)
}

// NewGroupCheckerFunc creates a new GroupChecker function for checking if an account is in a group.
func NewGroupCheckerFunc(querier GroupPolicyQuerier) GroupCheckerFunc {
return GroupCheckerFunc(func(ctx sdk.Context, account sdk.AccAddress) bool {
msg := &group.QueryGroupPolicyInfoRequest{Address: account.String()}
goCtx := sdk.WrapSDKContext(ctx)
_, err := querier.GroupPolicyInfo(goCtx, msg)
return err == nil
})
}
74 changes: 74 additions & 0 deletions app/group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package app

import (
"context"
"testing"

"github.com/stretchr/testify/assert"

cerrs "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/group"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)

func TestNewGroupCheckerFunc(t *testing.T) {
querier := NewMockGroupPolicyQuerier(true)
checker := NewGroupCheckerFunc(querier)
assert.NotNil(t, checker, "should return a group checker function")
}

func TestIsGroupAddress(t *testing.T) {
tests := []struct {
name string
querySuccess bool
address sdk.AccAddress
}{
{
name: "should be true with group address",
querySuccess: true,
address: sdk.AccAddress("test"),
},
{
name: "should return false with non group address",
querySuccess: false,
address: sdk.AccAddress("test"),
},
{
name: "should return false with nil address",
querySuccess: false,
address: nil,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
querier := NewMockGroupPolicyQuerier(tc.querySuccess)
checker := NewGroupCheckerFunc(querier)
ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil)
success := checker.IsGroupAddress(ctx, tc.address)
assert.Equal(t, tc.querySuccess, success, "should correctly detect if the supplied address is a group address")
})
}
}

// MockGroupPolicyQuerier mocks the querier so a GroupKeeper isn't needed.
type MockGroupPolicyQuerier struct {
isGroupAddress bool
}

// NewMockGroupPolicyQuerier creates a new MockGroupPolicyQuerier.
func NewMockGroupPolicyQuerier(isGroupAddress bool) *MockGroupPolicyQuerier {
return &MockGroupPolicyQuerier{
isGroupAddress: isGroupAddress,
}
}

// GroupPolicyInfo provides a stubbed implementation of the GroupPolicyInfo method.
func (t MockGroupPolicyQuerier) GroupPolicyInfo(goCtx context.Context, request *group.QueryGroupPolicyInfoRequest) (*group.QueryGroupPolicyInfoResponse, error) {
var err error
if !t.isGroupAddress {
err = cerrs.New("", 1, "")
}
return nil, err
}
5 changes: 5 additions & 0 deletions x/marker/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ type Keeper struct {
// When sending from one of these, if there are required attributes, the destination must have them;
// if there aren't required attributes, it behaves as if the sender has transfer permission.
reqAttrBypassAddrs types.ImmutableAccAddresses

// groupChecker provides a way to check if an account is in a group.
groupChecker types.GroupChecker
}

// NewKeeper returns a marker keeper. It handles:
Expand All @@ -105,6 +108,7 @@ func NewKeeper(
nameKeeper types.NameKeeper,
ibcTransferServer types.IbcTransferMsgServer,
reqAttrBypassAddrs []sdk.AccAddress,
checker types.GroupChecker,
) Keeper {
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
Expand All @@ -125,6 +129,7 @@ func NewKeeper(
ibcTransferModuleAddr: authtypes.NewModuleAddress(ibctypes.ModuleName),
ibcTransferServer: ibcTransferServer,
reqAttrBypassAddrs: types.NewImmutableAccAddresses(reqAttrBypassAddrs),
groupChecker: checker,
}
bankKeeper.AppendSendRestriction(rv.SendRestrictionFn)
return rv
Expand Down
23 changes: 22 additions & 1 deletion x/marker/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/group"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cosmos/cosmos-sdk/x/quarantine"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
Expand Down Expand Up @@ -754,9 +755,28 @@ func TestCanForceTransferFrom(t *testing.T) {
app.AccountKeeper.SetAccount(ctx, acc)
}

createGroup := func() sdk.AccAddress {
goCtx := sdk.WrapSDKContext(ctx)
msg, err := group.NewMsgCreateGroupWithPolicy("cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
[]group.MemberRequest{
{
Address: "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
Weight: "1",
Metadata: "",
},
},
"", "", true, group.NewPercentageDecisionPolicy("0.5", time.Second, time.Second))
require.NoError(t, err, "NewMsgCreateGroupWithPolicy")
res, err := app.GroupKeeper.CreateGroupWithPolicy(goCtx, msg)
require.NoError(t, err, "CreateGroupWithPolicy")

return sdk.MustAccAddressFromBech32(res.GroupPolicyAddress)
}

addrNoAcc := sdk.AccAddress("addrNoAcc___________")
addrSeq0 := sdk.AccAddress("addrSeq0____________")
addrSeq1 := sdk.AccAddress("addrSeq1____________")
addrGroup := createGroup()
setAcc(addrSeq0, 0)
setAcc(addrSeq1, 1)

Expand All @@ -768,6 +788,7 @@ func TestCanForceTransferFrom(t *testing.T) {
{name: "address without an account", from: addrNoAcc, exp: true},
{name: "address with sequence 0", from: addrSeq0, exp: false},
{name: "address with sequence 1", from: addrSeq1, exp: true},
{name: "group address", from: addrGroup, exp: true},
}

for _, tc := range tests {
Expand Down Expand Up @@ -1831,7 +1852,7 @@ func TestBypassAddrsLocked(t *testing.T) {
sdk.AccAddress("addrs[4]____________"),
}

mk := markerkeeper.NewKeeper(nil, nil, paramtypes.NewSubspace(nil, nil, nil, nil, "test"), nil, &dummyBankKeeper{}, nil, nil, nil, nil, nil, addrs)
mk := markerkeeper.NewKeeper(nil, nil, paramtypes.NewSubspace(nil, nil, nil, nil, "test"), nil, &dummyBankKeeper{}, nil, nil, nil, nil, nil, addrs, nil)

// Now that the keeper has been created using the provided addresses, change the first byte of
// the first address to something else. Then, get the addresses back from the keeper and make
Expand Down
5 changes: 5 additions & 0 deletions x/marker/keeper/marker.go
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,11 @@ func (k Keeper) TransferCoin(ctx sdk.Context, from, to, admin sdk.AccAddress, am
// canForceTransferFrom returns true if funds can be forcefully transferred out of the provided address.
func (k Keeper) canForceTransferFrom(ctx sdk.Context, from sdk.AccAddress) bool {
acc := k.authKeeper.GetAccount(ctx, from)
// If the account is a group address, then it will allow the transfer.
if k.groupChecker != nil && k.groupChecker.IsGroupAddress(ctx, from) {
return true
}

// If acc is nil, there's no funds in it, so the transfer will fail anyway.
// In that case, return true from here so it can fail later with a more accurate message.
// If there is an account, only allow force transfers if the sequence number isn't zero.
Expand Down
2 changes: 1 addition & 1 deletion x/marker/keeper/proposal_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type IntegrationTestSuite struct {
func (s *IntegrationTestSuite) SetupSuite() {
s.app = provenance.Setup(s.T())
s.ctx = s.app.BaseApp.NewContext(false, tmproto.Header{})
s.k = markerkeeper.NewKeeper(s.app.AppCodec(), s.app.GetKey(markertypes.ModuleName), s.app.GetSubspace(markertypes.ModuleName), s.app.AccountKeeper, s.app.BankKeeper, s.app.AuthzKeeper, s.app.FeeGrantKeeper, s.app.AttributeKeeper, s.app.NameKeeper, s.app.TransferKeeper, nil)
s.k = markerkeeper.NewKeeper(s.app.AppCodec(), s.app.GetKey(markertypes.ModuleName), s.app.GetSubspace(markertypes.ModuleName), s.app.AccountKeeper, s.app.BankKeeper, s.app.AuthzKeeper, s.app.FeeGrantKeeper, s.app.AttributeKeeper, s.app.NameKeeper, s.app.TransferKeeper, nil, nil)
s.accountAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
}

Expand Down
1 change: 1 addition & 0 deletions x/marker/simulation/proposals_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func TestProposalContents(t *testing.T) {
app.NameKeeper,
app.TransferKeeper,
nil,
nil,
),
)
require.Len(t, weightedProposalContent, 6)
Expand Down
5 changes: 5 additions & 0 deletions x/marker/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,8 @@ type GovKeeper interface {
type IbcTransferMsgServer interface {
Transfer(goCtx context.Context, msg *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error)
}

// GroupChecker defines the functionality for checking if an account is part of a group.
type GroupChecker interface {
IsGroupAddress(sdk.Context, sdk.AccAddress) bool
}

0 comments on commit ae5647e

Please sign in to comment.