-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(
campaign
): add event for campaign auction creation (#841)
* initialize hook * add campaign auction event * add hooks * upgrade fundraising * add hooks * emit event * emit for both auction type * error handling * add remove keeper methods * test body * test cases * liunt * add issue links * Update proto/campaign/events.proto Co-authored-by: Alex Johnson <alex.johnson@tendermint.com> * ID Co-authored-by: Alex Johnson <alex.johnson@tendermint.com> Co-authored-by: Danilo Pantani <danpantani@gmail.com>
- Loading branch information
1 parent
ee188db
commit b6a5d1d
Showing
11 changed files
with
598 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
package keeper | ||
|
||
import ( | ||
"time" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
|
||
fundraisingtypes "github.com/tendermint/fundraising/x/fundraising/types" | ||
"github.com/tendermint/spn/x/campaign/types" | ||
profiletypes "github.com/tendermint/spn/x/profile/types" | ||
) | ||
|
||
// EmitCampaignAuctionCreated emits EventCampaignAuctionCreated event if an auction is created for a campaign from a coordinator | ||
func (k Keeper) EmitCampaignAuctionCreated( | ||
ctx sdk.Context, | ||
auctionID uint64, | ||
auctioneer string, | ||
sellingCoin sdk.Coin, | ||
) (bool, error) { | ||
campaignID, err := types.VoucherCampaign(sellingCoin.Denom) | ||
if err != nil { | ||
// not a campaign auction | ||
return false, nil | ||
} | ||
|
||
// verify the auctioneer is the coordinator of the campaign | ||
campaign, found := k.GetCampaign(ctx, campaignID) | ||
if !found { | ||
return false, sdkerrors.Wrapf(types.ErrCampaignNotFound, | ||
"voucher %s is associated to an non-existing campaign %d", | ||
sellingCoin.Denom, | ||
campaignID, | ||
) | ||
|
||
} | ||
coord, found := k.profileKeeper.GetCoordinator(ctx, campaign.CoordinatorID) | ||
if !found { | ||
return false, sdkerrors.Wrapf(profiletypes.ErrCoordInvalid, | ||
"campaign %d coordinator doesn't exist %d", | ||
campaignID, | ||
campaign.CoordinatorID, | ||
) | ||
} | ||
|
||
// if the coordinator if the auctioneer, we emit a CampaignAuctionCreated event | ||
if coord.Address != auctioneer { | ||
return false, nil | ||
} | ||
|
||
err = ctx.EventManager().EmitTypedEvents( | ||
&types.EventCampaignAuctionCreated{ | ||
CampaignID: campaignID, | ||
AuctionID: auctionID, | ||
}, | ||
) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
return true, nil | ||
} | ||
|
||
// CampaignAuctionEventHooks returns a CampaignAuctionEventHooks associated with the campaign keeper | ||
func (k Keeper) CampaignAuctionEventHooks() CampaignAuctionEventHooks { | ||
return CampaignAuctionEventHooks{ | ||
campaignKeeper: k, | ||
} | ||
} | ||
|
||
// CampaignAuctionEventHooks implements fundraising hooks and emit events on auction creation | ||
type CampaignAuctionEventHooks struct { | ||
campaignKeeper Keeper | ||
} | ||
|
||
// Implements FundraisingHooks interface | ||
var _ fundraisingtypes.FundraisingHooks = CampaignAuctionEventHooks{} | ||
|
||
// AfterFixedPriceAuctionCreated emits a CampaignAuctionCreated event if created for a campaign | ||
func (h CampaignAuctionEventHooks) AfterFixedPriceAuctionCreated( | ||
ctx sdk.Context, | ||
auctionID uint64, | ||
auctioneer string, | ||
_ sdk.Dec, | ||
sellingCoin sdk.Coin, | ||
_ string, | ||
_ []fundraisingtypes.VestingSchedule, | ||
_ time.Time, | ||
_ time.Time, | ||
) { | ||
// TODO: investigate error handling for hooks | ||
// https://github.com/tendermint/spn/issues/869 | ||
_, _ = h.campaignKeeper.EmitCampaignAuctionCreated(ctx, auctionID, auctioneer, sellingCoin) | ||
} | ||
|
||
// AfterBatchAuctionCreated emits a CampaignAuctionCreated event if created for a campaign | ||
func (h CampaignAuctionEventHooks) AfterBatchAuctionCreated( | ||
ctx sdk.Context, | ||
auctionID uint64, | ||
auctioneer string, | ||
_ sdk.Dec, | ||
_ sdk.Dec, | ||
sellingCoin sdk.Coin, | ||
_ string, | ||
_ []fundraisingtypes.VestingSchedule, | ||
_ uint32, | ||
_ sdk.Dec, | ||
_ time.Time, | ||
_ time.Time, | ||
) { | ||
// TODO: investigate error handling for hooks | ||
// https://github.com/tendermint/spn/issues/869 | ||
_, _ = h.campaignKeeper.EmitCampaignAuctionCreated(ctx, auctionID, auctioneer, sellingCoin) | ||
} | ||
|
||
// BeforeFixedPriceAuctionCreated implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeFixedPriceAuctionCreated( | ||
_ sdk.Context, | ||
_ string, | ||
_ sdk.Dec, | ||
_ sdk.Coin, | ||
_ string, | ||
_ []fundraisingtypes.VestingSchedule, | ||
_ time.Time, | ||
_ time.Time, | ||
) { | ||
} | ||
|
||
// BeforeBatchAuctionCreated implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeBatchAuctionCreated( | ||
_ sdk.Context, | ||
_ string, | ||
_ sdk.Dec, | ||
_ sdk.Dec, | ||
_ sdk.Coin, | ||
_ string, | ||
_ []fundraisingtypes.VestingSchedule, | ||
_ uint32, | ||
_ sdk.Dec, | ||
_ time.Time, | ||
_ time.Time, | ||
) { | ||
} | ||
|
||
// BeforeAuctionCanceled implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeAuctionCanceled( | ||
_ sdk.Context, | ||
_ uint64, | ||
_ string, | ||
) { | ||
} | ||
|
||
// BeforeBidPlaced implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeBidPlaced( | ||
_ sdk.Context, | ||
_ uint64, | ||
_ uint64, | ||
_ string, | ||
_ fundraisingtypes.BidType, | ||
_ sdk.Dec, | ||
_ sdk.Coin, | ||
) { | ||
} | ||
|
||
// BeforeBidModified implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeBidModified( | ||
_ sdk.Context, | ||
_ uint64, | ||
_ uint64, | ||
_ string, | ||
_ fundraisingtypes.BidType, | ||
_ sdk.Dec, | ||
_ sdk.Coin, | ||
) { | ||
} | ||
|
||
// BeforeAllowedBiddersAdded implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeAllowedBiddersAdded( | ||
_ sdk.Context, | ||
_ []fundraisingtypes.AllowedBidder, | ||
) { | ||
} | ||
|
||
// BeforeAllowedBidderUpdated implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeAllowedBidderUpdated( | ||
_ sdk.Context, | ||
_ uint64, | ||
_ sdk.AccAddress, | ||
_ sdk.Int, | ||
) { | ||
} | ||
|
||
// BeforeSellingCoinsAllocated implements FundraisingHooks | ||
func (h CampaignAuctionEventHooks) BeforeSellingCoinsAllocated( | ||
_ sdk.Context, | ||
_ uint64, | ||
_ map[string]sdk.Int, | ||
_ map[string]sdk.Int, | ||
) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package keeper_test | ||
|
||
import ( | ||
"testing" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/stretchr/testify/require" | ||
tc "github.com/tendermint/spn/testutil/constructor" | ||
testkeeper "github.com/tendermint/spn/testutil/keeper" | ||
"github.com/tendermint/spn/testutil/sample" | ||
"github.com/tendermint/spn/x/campaign/types" | ||
profiletypes "github.com/tendermint/spn/x/profile/types" | ||
) | ||
|
||
func TestKeeper_EmitCampaignAuctionCreated(t *testing.T) { | ||
ctx, tk, _ := testkeeper.NewTestSetup(t) | ||
|
||
type inputState struct { | ||
noCampaign bool | ||
noCoordinator bool | ||
campaign types.Campaign | ||
coordinator profiletypes.Coordinator | ||
} | ||
|
||
coordinator := sample.Address(r) | ||
|
||
tests := []struct { | ||
name string | ||
inputState inputState | ||
auctionId uint64 | ||
auctioneer string | ||
sellingCoin sdk.Coin | ||
emitted bool | ||
err error | ||
}{ | ||
{ | ||
name: "should prevent emitting event if selling coin is not a voucher", | ||
inputState: inputState{ | ||
noCampaign: true, | ||
noCoordinator: true, | ||
}, | ||
sellingCoin: tc.Coin(t, "1000foo"), | ||
emitted: false, | ||
}, | ||
{ | ||
name: "should return error if selling coin is a voucher of a non existing campaign", | ||
inputState: inputState{ | ||
noCampaign: true, | ||
noCoordinator: true, | ||
}, | ||
sellingCoin: tc.Coin(t, "1000"+types.VoucherDenom(5, "foo")), | ||
err: types.ErrCampaignNotFound, | ||
}, | ||
{ | ||
name: "should return error if selling coin is a voucher of a campaign with non existing coordinator", | ||
inputState: inputState{ | ||
campaign: types.Campaign{ | ||
CampaignID: 10, | ||
CoordinatorID: 20, | ||
}, | ||
noCoordinator: true, | ||
}, | ||
sellingCoin: tc.Coin(t, "1000"+types.VoucherDenom(10, "foo")), | ||
err: profiletypes.ErrCoordInvalid, | ||
}, | ||
{ | ||
name: "should prevent emitting event if the auctioneer is not the coordinator of the campaign", | ||
inputState: inputState{ | ||
campaign: types.Campaign{ | ||
CampaignID: 100, | ||
CoordinatorID: 200, | ||
}, | ||
coordinator: profiletypes.Coordinator{ | ||
CoordinatorID: 200, | ||
Address: sample.Address(r), | ||
}, | ||
}, | ||
auctioneer: sample.Address(r), | ||
sellingCoin: tc.Coin(t, "1000"+types.VoucherDenom(100, "foo")), | ||
emitted: false, | ||
}, | ||
{ | ||
name: "should allow emitting event if the auctioneer is the coordinator of the campaign", | ||
inputState: inputState{ | ||
campaign: types.Campaign{ | ||
CampaignID: 1000, | ||
CoordinatorID: 2000, | ||
}, | ||
coordinator: profiletypes.Coordinator{ | ||
CoordinatorID: 2000, | ||
Address: coordinator, | ||
}, | ||
}, | ||
auctioneer: coordinator, | ||
sellingCoin: tc.Coin(t, "1000"+types.VoucherDenom(1000, "foo")), | ||
emitted: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
// initialize input state | ||
if !tt.inputState.noCampaign { | ||
tk.CampaignKeeper.SetCampaign(ctx, tt.inputState.campaign) | ||
} | ||
if !tt.inputState.noCoordinator { | ||
tk.ProfileKeeper.SetCoordinator(ctx, tt.inputState.coordinator) | ||
} | ||
|
||
emitted, err := tk.CampaignKeeper.EmitCampaignAuctionCreated(ctx, tt.auctionId, tt.auctioneer, tt.sellingCoin) | ||
if tt.err != nil { | ||
require.ErrorIs(t, err, tt.err) | ||
} else { | ||
require.NoError(t, err) | ||
require.EqualValues(t, tt.emitted, emitted) | ||
} | ||
|
||
// clean state | ||
if !tt.inputState.noCampaign { | ||
tk.CampaignKeeper.RemoveCampaign(ctx, tt.inputState.campaign.CampaignID) | ||
} | ||
if !tt.inputState.noCoordinator { | ||
tk.ProfileKeeper.RemoveCoordinator(ctx, tt.inputState.coordinator.CoordinatorID) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.