Skip to content

Commit

Permalink
[1834]: Unit tests on the send restriction function.
Browse files Browse the repository at this point in the history
  • Loading branch information
SpicyLemon committed Feb 8, 2024
1 parent 0edadca commit 3665667
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 25 deletions.
12 changes: 10 additions & 2 deletions x/marker/keeper/send_restrictions.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ func (k Keeper) validateSendDenom(ctx sdk.Context, fromAddr, toAddr, admin sdk.A
// intermediary account and deposit them from there, or give the bypass account deposit and transfer permissions.
// It's assumed that a marker address cannot be in the bypass list.
if toMarker != nil {
return fmt.Errorf("%s does not have transfer access for %s", fromAddr.String(), denom)
addr := admin
if len(addr) == 0 {
addr = fromAddr
}
return fmt.Errorf("%s does not have transfer access for %s", addr.String(), denom)
}

// If there aren't any required attributes, transfer permission is required unless coming from a bypass account.
Expand All @@ -119,7 +123,11 @@ func (k Keeper) validateSendDenom(ctx sdk.Context, fromAddr, toAddr, admin sdk.A
if k.IsReqAttrBypassAddr(fromAddr) {
return nil
}
return fmt.Errorf("%s does not have transfer permissions for %s", fromAddr.String(), denom)
addr := admin
if len(addr) == 0 {
addr = fromAddr
}
return fmt.Errorf("%s does not have transfer permissions for %s", addr.String(), denom)
}

// At this point, we know there are required attributes and that fromAddr does not have transfer permission.
Expand Down
204 changes: 181 additions & 23 deletions x/marker/keeper/send_restrictions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ func TestSendRestrictionFn(t *testing.T) {

app := simapp.Setup(t)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
ctxWithBypass := types.WithBypass(ctx)
// ctxP returns a pointer to the provided context.
ctxP := func(ctx sdk.Context) *sdk.Context {
return &ctx
}
owner := sdk.AccAddress("owner_address_______")
app.AccountKeeper.SetAccount(ctx, app.AccountKeeper.NewAccountWithAddress(ctx, owner))
require.NoError(t, app.NameKeeper.SetNameRecord(ctx, "kyc.provenance.io", owner, false), "SetNameRecord kyc.provenance.io")
Expand Down Expand Up @@ -59,7 +62,11 @@ func TestSendRestrictionFn(t *testing.T) {
addrWithoutAttrs := sdk.AccAddress("addr_without_attribs")
addrWithTransfer := sdk.AccAddress("addr_with_transfer__")
addrWithDeposit := sdk.AccAddress("addrWithDeposit_____")
addrWithWithdraw := sdk.AccAddress("addrWithWithdraw____")
addrWithTranDep := sdk.AccAddress("addrWithTranDep_____")
addrWithTranWithdraw := sdk.AccAddress("addrWithTranWithdraw")
addrWithTranDepWithdraw := sdk.AccAddress("addrWithTranDepWithd")
addrWithDepWithdraw := sdk.AccAddress("addrWithDepWithdraw_")
addrWithDenySend := sdk.AccAddress("addrWithDenySend_____")
addrOther := sdk.AccAddress("addrOther___________")

Expand All @@ -70,55 +77,88 @@ func TestSendRestrictionFn(t *testing.T) {
coin := types.MarkerType_Coin
restricted := types.MarkerType_RestrictedCoin

acctNum := uint64(0)
newMarker := func(denom string, markerType types.MarkerType, reqAttrs []string) *types.MarkerAccount {
baseAcct := authtypes.NewBaseAccount(types.MustGetMarkerAddress(denom), nil, acctNum, 0)
acctNum++
var access []types.AccessGrant
newMarkerAcc := func(denom string, markerType types.MarkerType, reqAttrs []string) *types.MarkerAccount {
addr, err := types.MarkerAddress(denom)
require.NoError(t, err, "MarkerAddress(%q)", denom)

rv := &types.MarkerAccount{
BaseAccount: authtypes.NewBaseAccountWithAddress(addr),
Manager: owner.String(),
Status: types.StatusProposed,
Denom: denom,
Supply: sdk.NewInt(1000),
MarkerType: markerType,
SupplyFixed: true,
AllowGovernanceControl: true,
AllowForcedTransfer: false,
RequiredAttributes: reqAttrs,
}

if markerType == restricted {
access = []types.AccessGrant{
rv.AccessControl = []types.AccessGrant{
{Address: addrWithTransfer.String(), Permissions: types.AccessList{types.Access_Transfer}},
{Address: addrWithDeposit.String(), Permissions: types.AccessList{types.Access_Deposit}},
{Address: addrWithWithdraw.String(), Permissions: types.AccessList{types.Access_Withdraw}},
{Address: addrWithTranDep.String(), Permissions: types.AccessList{types.Access_Deposit, types.Access_Transfer}},
{Address: addrWithTranWithdraw.String(), Permissions: types.AccessList{types.Access_Withdraw, types.Access_Transfer}},
{Address: addrWithDepWithdraw.String(), Permissions: types.AccessList{types.Access_Deposit, types.Access_Withdraw}},
{Address: addrWithTranDepWithdraw.String(), Permissions: types.AccessList{types.Access_Deposit, types.Access_Withdraw, types.Access_Transfer}},
// It's silly to give any permissions to a bypass address, but I do so in here to hit some test cases.
{Address: addrWithBypass.String(), Permissions: types.AccessList{types.Access_Deposit}},
}
}
rv := types.NewMarkerAccount(
baseAcct,
sdk.NewInt64Coin(denom, 1000),
owner,
access,
types.StatusFinalized,
markerType,
true, // supply fixed
true, // allow gov
false, // no force transfer
reqAttrs,
)
app.MarkerKeeper.SetMarker(ctx, rv)

return rv
}
createActiveMarker := func(marker *types.MarkerAccount) *types.MarkerAccount {
nav := []types.NetAssetValue{types.NewNetAssetValue(sdk.NewInt64Coin(types.UsdDenom, int64(1)), 1)}
err := app.MarkerKeeper.AddSetNetAssetValues(ctx, marker, nav, t.Name())
require.NoError(t, err, "AddSetNetAssetValues(%v, %v, %v)", marker.Denom, nav, t.Name())
err = app.MarkerKeeper.AddFinalizeAndActivateMarker(ctx, marker)
require.NoError(t, err, "AddFinalizeAndActivateMarker(%s)", marker.Denom)
return marker
}
newMarker := func(denom string, markerType types.MarkerType, reqAttrs []string) *types.MarkerAccount {
return createActiveMarker(newMarkerAcc(denom, markerType, reqAttrs))
}
newPendingMarker := func(denom string, markerType types.MarkerType, reqAttrs []string) *types.MarkerAccount {
rv := newMarkerAcc(denom, markerType, reqAttrs)
err := app.MarkerKeeper.AddMarkerAccount(ctx, rv)
require.NoError(t, err, "AddMarkerAccount(%s)", denom)
return rv

}

nrDenom := "nonrestrictedmarker"
nrMarker := newMarker(nrDenom, coin, nil)

rDenomNoAttr := "restrictedmarkernoreqattributes"
rMarkerNoAttr := newMarker(rDenomNoAttr, restricted, nil)
app.MarkerKeeper.AddSendDeny(ctx, rMarkerNoAttr.GetAddress(), addrWithDenySend)

rDenom1AttrNoOneHas := "restrictedmarkerreqattributes2"
newMarker(rDenom1AttrNoOneHas, restricted, []string{"some.attribute.that.i.require"})

rDenom1Attr := "restrictedmarkerreqattributes3"
rMarker1Attr := newMarker(rDenom1Attr, restricted, []string{"kyc.provenance.io"})
require.NoError(t, app.AttributeKeeper.SetAttribute(ctx,
attrTypes.Attribute{
Name: "kyc.provenance.io",
Value: []byte("string value"),
Address: rMarker1Attr.GetAddress().String(),
AttributeType: attrTypes.AttributeType_String,
},
owner,
), "SetAttribute kyc.provenance.io")

rDenom2Attrs := "restrictedmarkerreqattributes4"
newMarker(rDenom2Attrs, restricted, []string{"kyc.provenance.io", "not-kyc.provenance.io"})
rMarker2Attrs := newMarker(rDenom2Attrs, restricted, []string{"kyc.provenance.io", "not-kyc.provenance.io"})

rDenom3Attrs := "restrictedmarkerreqattributes5"
newMarker(rDenom3Attrs, restricted, []string{"kyc.provenance.io", "not-kyc.provenance.io", "foo.provenance.io"})

app.MarkerKeeper.AddSendDeny(ctx, rMarkerNoAttr.GetAddress(), addrWithDenySend)
rDenomPending := "stillpending"
rMarkerPending := newPendingMarker(rDenomPending, restricted, nil)

testCases := []struct {
name string
Expand Down Expand Up @@ -176,7 +216,7 @@ func TestSendRestrictionFn(t *testing.T) {
{
// This should be the exact same test as the above one, but with a bypass context, so no error is expected.
name: "with bypass, restricted marker with required attributes but none match",
ctx: &ctxWithBypass,
ctx: ctxP(types.WithBypass(ctx)),
from: owner,
to: addrWithAttrs,
amt: cz(c(1, rDenom1AttrNoOneHas)),
Expand Down Expand Up @@ -394,6 +434,124 @@ func TestSendRestrictionFn(t *testing.T) {
amt: cz(c(1, rDenomNoAttr)),
expErr: "",
},
{
name: "from marker: no admin",
from: rMarkerNoAttr.GetAddress(),
to: addrWithAttrs,
amt: cz(c(2, rDenomNoAttr)),
expErr: "cannot withdraw from marker account " + rMarkerNoAttr.GetAddress().String() + " (" + rDenomNoAttr + ")",
},
{
name: "from marker: admin without withdraw permission",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTransfer)),
from: rMarkerNoAttr.GetAddress(),
to: addrWithAttrs,
amt: cz(c(2, rDenomNoAttr)),
expErr: addrWithTransfer.String() + " does not have withdraw access for " + rMarkerNoAttr.GetAddress().String() + " (" + rDenomNoAttr + ")",
},
{
name: "from marker: withdraw marker funds from inactive marker",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTranWithdraw)),
from: rMarkerPending.GetAddress(),
to: addrWithAttrs,
amt: cz(c(2, rDenomNoAttr), c(1, rDenomPending), c(5, rDenom3Attrs)),
expErr: fmt.Sprintf("cannot withdraw marker created coins (%s) from marker %s (%s) that is not in active status (proposed)",
cz(c(2, rDenomNoAttr), c(1, rDenomPending), c(5, rDenom3Attrs)), rMarkerPending.GetAddress().String(), rDenomPending,
),
},
{
name: "from marker: withdraw non-marker funds from inactive marker",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTranWithdraw)),
from: rMarkerPending.GetAddress(),
to: addrWithAttrs,
amt: cz(c(2, rDenomNoAttr), c(5, rDenom3Attrs)),
},
{
name: "from marker: withdraw from active marker",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTranWithdraw)),
from: rMarkerNoAttr.GetAddress(),
to: addrWithAttrs,
amt: cz(c(3, rDenomNoAttr)),
},
{
name: "with admin: does not have transfer: okay otherwise",
ctx: ctxP(types.WithTransferAgent(ctx, addrOther)),
from: owner,
to: addrWithAttrs,
amt: cz(c(1, rDenom1Attr), c(1, nrDenom)),
},
{
name: "with admin: has transfer: would otherwise fail",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTransfer)),
from: addrWithDenySend,
to: addrWithAttrs,
amt: cz(c(1, rDenomNoAttr)),
},
{
name: "from marker to marker: admin only has transfer",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTransfer)),
from: rMarkerNoAttr.GetAddress(),
to: rMarker1Attr.GetAddress(),
amt: cz(c(1, rDenom1AttrNoOneHas)),
expErr: addrWithTransfer.String() + " does not have withdraw access for " +
rMarkerNoAttr.GetAddress().String() +
" (" + rDenomNoAttr + ")",
},
{
name: "from marker to marker: admin only has deposit",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithDeposit)),
from: rMarkerNoAttr.GetAddress(),
to: rMarker1Attr.GetAddress(),
amt: cz(c(1, rDenom1AttrNoOneHas)),
expErr: addrWithDeposit.String() + " does not have withdraw access for " +
rMarkerNoAttr.GetAddress().String() +
" (" + rDenomNoAttr + ")",
},
{
name: "from marker to marker: admin only has withdraw",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithWithdraw)),
from: rMarkerNoAttr.GetAddress(),
to: rMarker1Attr.GetAddress(),
amt: cz(c(1, rDenom1AttrNoOneHas)),
expErr: addrWithWithdraw.String() + " does not have deposit access for " +
rMarker1Attr.GetAddress().String() +
" (" + rDenom1Attr + ")",
},
{
name: "from marker to marker: admin only has transfer and deposit",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTranDep)),
from: rMarkerNoAttr.GetAddress(),
to: rMarker1Attr.GetAddress(),
amt: cz(c(1, rDenom1AttrNoOneHas)),
expErr: addrWithTranDep.String() + " does not have withdraw access for " +
rMarkerNoAttr.GetAddress().String() +
" (" + rDenomNoAttr + ")",
},
{
name: "from marker to marker: admin only has transfer and withdraw",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTranWithdraw)),
from: rMarkerNoAttr.GetAddress(),
to: rMarker1Attr.GetAddress(),
amt: cz(c(1, rDenom1AttrNoOneHas)),
expErr: addrWithTranWithdraw.String() + " does not have deposit access for " +
rMarker1Attr.GetAddress().String() +
" (" + rDenom1Attr + ")",
},
{
name: "from marker to marker: admin only has deposit and withdraw",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithDepWithdraw)),
from: rMarker1Attr.GetAddress(),
to: rMarker2Attrs.GetAddress(),
amt: cz(c(1, rDenom1Attr)),
expErr: addrWithDepWithdraw.String() + " does not have transfer access for " + rDenom1Attr,
},
{
name: "from marker to marker: admin has transfer and deposit and withdraw",
ctx: ctxP(types.WithTransferAgent(ctx, addrWithTranDepWithdraw)),
from: rMarker1Attr.GetAddress(),
to: rMarker2Attrs.GetAddress(),
amt: cz(c(1, rDenomNoAttr)),
},
}

for _, tc := range testCases {
Expand Down

0 comments on commit 3665667

Please sign in to comment.