Skip to content

Commit

Permalink
fix payment fee deduction (#29)
Browse files Browse the repository at this point in the history
* add payment fee in stream send msg

* update tx proto generated file

* deduct payment fee from sender instead of amount

* update payment fee in stream send message

* update tests with payment fee

* fix lint
  • Loading branch information
harish551 authored Jan 29, 2024
1 parent e878d52 commit b80a68c
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 75 deletions.
5 changes: 5 additions & 0 deletions proto/OmniFlix/streampay/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ message MsgStreamSend {
StreamType stream_type = 5 [(gogoproto.moretags) = "yaml:\"stream_type\""];
repeated Period periods = 6 [(gogoproto.nullable) = true];
bool cancellable = 7;
cosmos.base.v1beta1.Coin payment_fee = 8 [
(gogoproto.moretags) = "yaml:\"payment_fee\"",
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"
];
}

message MsgStreamSendResponse {
Expand Down
2 changes: 2 additions & 0 deletions x/streampay/client/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
FlagDelayed = "delayed"
FlagStreamPeriodsFile = "stream-periods-file"
FlagCancellable = "cancellable"
FlagPaymentFee = "payment-fee"
)

var FsStreamSend = flag.NewFlagSet("", flag.ContinueOnError)
Expand All @@ -18,4 +19,5 @@ func init() {
FsStreamSend.Bool(FlagDelayed, false, "to create a delayed stream payment")
FsStreamSend.String(FlagStreamPeriodsFile, "", "stream periods json file")
FsStreamSend.Bool(FlagCancellable, false, "to create cancellable stream payment")
FsStreamSend.String(FlagPaymentFee, "", "payment fee")
}
16 changes: 13 additions & 3 deletions x/streampay/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ func GetCmdStreamSend() *cobra.Command {
"cancellation of stream payments:\n" +
"using --cancellable flag, you can create a cancellable stream payment\n",
Example: fmt.Sprintf(
"$ %s tx streampay stream-send [recipient] [amount] --duration <duration>"+
"$ %s tx streampay stream-send [recipient] [amount] --payment-fee [amount] --duration <duration>"+
" --chain-id <chain-id> --from <sender> --fees <fees>\n\n"+
"delayed payment:\n"+
"$ %s tx streampay stream-send [recipient] [amount] --duration <stream-duration> --delayed"+
"$ %s tx streampay stream-send [recipient] [amount] --payment-fee [amount]--duration <stream-duration> --delayed"+
" --chain-id <chain-id> --from <sender> --fees <fees>\n\n"+
"periodic payment:\n"+
"$ %s tx streampay stream-send [recipient] [amount] --stream-periods-file <stream-periods-file>"+
"$ %s tx streampay stream-send [recipient] [amount] --payment-fee [amount] --stream-periods-file <stream-periods-file>"+
" --chain-id <chain-id> --from <sender> --fees <fees>\n\n",
version.AppName, version.AppName, version.AppName,
),
Expand Down Expand Up @@ -123,6 +123,14 @@ func GetCmdStreamSend() *cobra.Command {
if err != nil {
return err
}
paymentFeeStr, err := cmd.Flags().GetString(FlagPaymentFee)
if err != nil {
return err
}
paymentFee, err := sdk.ParseCoinNormalized(paymentFeeStr)
if err != nil {
return err
}

msg := types.NewMsgStreamSend(
sender.String(),
Expand All @@ -132,6 +140,7 @@ func GetCmdStreamSend() *cobra.Command {
duration,
periods,
cancellable,
paymentFee,
)

if err := msg.ValidateBasic(); err != nil {
Expand All @@ -144,6 +153,7 @@ func GetCmdStreamSend() *cobra.Command {

cmd.Flags().AddFlagSet(FsStreamSend)
_ = cmd.MarkFlagRequired(FlagDuration)
_ = cmd.MarkFlagRequired(FlagPaymentFee)
flags.AddTxFlagsToCmd(cmd)

return cmd
Expand Down
4 changes: 3 additions & 1 deletion x/streampay/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (suite *KeeperTestSuite) SetupTest() {
for _, acc := range suite.TestAccs {
suite.FundAcc(acc, fundAccsAmount)
}
suite.App.StreamPayKeeper.SetParams(suite.Ctx, types.DefaultParams())
_ = suite.App.StreamPayKeeper.SetParams(suite.Ctx, types.DefaultParams())

suite.queryClient = types.NewQueryClient(suite.QueryHelper)
suite.msgServer = keeper.NewMsgServerImpl(suite.App.StreamPayKeeper)
Expand All @@ -46,6 +46,7 @@ func (suite *KeeperTestSuite) CreateDefaultStreamPayment(cancellable bool) {
Duration: 100,
Periods: nil,
Cancellable: cancellable,
PaymentFee: sdk.NewInt64Coin("uspay", 1_000_000),
})
suite.defaultStreamPaymentId = res.StreamId
}
Expand All @@ -60,6 +61,7 @@ func (suite *KeeperTestSuite) CreateStreamPayment(streamType types.StreamType, c
Duration: 100,
Periods: nil,
Cancellable: cancellable,
PaymentFee: sdk.NewInt64Coin("uspay", 1_000_000),
})
return res.StreamId
}
Expand Down
10 changes: 6 additions & 4 deletions x/streampay/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,19 @@ func (m msgServer) StreamSend(goCtx context.Context, msg *types.MsgStreamSend) (
return nil, err
}
feePercentage := m.Keeper.GetStreamPaymentFeePercentage(ctx)
feeAmount := sdk.NewCoin(msg.Amount.Denom, sdk.NewDecFromInt(msg.Amount.Amount).Mul(feePercentage).TruncateInt())
amountToSend := msg.Amount.SubAmount(feeAmount.Amount)
requiredFeeAmount := sdk.NewCoin(msg.Amount.Denom, sdk.NewDecFromInt(msg.Amount.Amount).Mul(feePercentage).TruncateInt())
if !msg.PaymentFee.Equal(requiredFeeAmount) {
return nil, errorsmod.Wrap(types.ErrInvalidStreamPaymentFee, "fee coin didn't match with stream coin")
}

if err := m.distributionKeeper.FundCommunityPool(ctx, sdk.NewCoins(feeAmount), sender); err != nil {
if err := m.distributionKeeper.FundCommunityPool(ctx, sdk.NewCoins(requiredFeeAmount), sender); err != nil {
return nil, err
}

streamPaymentId, err := m.Keeper.CreateStreamPayment(
ctx,
sender, recipient,
amountToSend,
msg.Amount,
msg.StreamType,
msg.Duration,
msg.Periods,
Expand Down
134 changes: 122 additions & 12 deletions x/streampay/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func (suite *KeeperTestSuite) TestStreamSendMsg() {
duration time.Duration
periods []*types.Period
cancellable bool
paymentFee sdk.Coin
valid bool
expectedMessageEvents int
}{
Expand All @@ -28,9 +29,58 @@ func (suite *KeeperTestSuite) TestStreamSendMsg() {
duration: time.Second * 100,
periods: nil,
cancellable: false,
paymentFee: sdk.NewInt64Coin("uspay", 1_000_000),
valid: true,
expectedMessageEvents: 1,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
amount: sdk.NewInt64Coin("uspay", 100_000_000),
streamType: types.TypeContinuous,
duration: time.Second * 100,
periods: nil,
cancellable: false,
paymentFee: sdk.NewInt64Coin("uspay", 10_000),
valid: false,
expectedMessageEvents: 0,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
amount: sdk.NewInt64Coin("uspay", 100_000_000),
streamType: types.TypeContinuous,
duration: time.Second * 100,
periods: nil,
cancellable: false,
paymentFee: sdk.NewInt64Coin("uspy", 1_000_000),
valid: false,
expectedMessageEvents: 0,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
amount: sdk.NewInt64Coin("uspay", 1_000_000),
streamType: types.TypeContinuous,
duration: time.Second * 100,
periods: nil,
cancellable: false,
paymentFee: sdk.Coin{Denom: "", Amount: sdk.NewInt(-1)},
valid: false,
expectedMessageEvents: 0,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
amount: sdk.Coin{Denom: "", Amount: sdk.NewInt(-1)},
streamType: types.TypeContinuous,
duration: time.Second * 100,
periods: nil,
cancellable: false,
paymentFee: sdk.NewInt64Coin("uspay", 1_000_000),
valid: false,
expectedMessageEvents: 0,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
Expand All @@ -39,13 +89,14 @@ func (suite *KeeperTestSuite) TestStreamSendMsg() {
duration: time.Second * 100,
periods: nil,
cancellable: false,
paymentFee: sdk.NewInt64Coin("uspay", 1_000_000),
valid: true,
expectedMessageEvents: 1,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
amount: sdk.NewInt64Coin("uspay", 100_000_000),
amount: sdk.NewInt64Coin("uspay", 10_000_000),
streamType: types.TypePeriodic,
duration: time.Second * 100,
periods: []*types.Period{
Expand Down Expand Up @@ -91,26 +142,85 @@ func (suite *KeeperTestSuite) TestStreamSendMsg() {
},
},
cancellable: true,
paymentFee: sdk.NewInt64Coin("uspay", 100_000),
valid: true,
expectedMessageEvents: 1,
},
{
sender: suite.TestAccs[0].String(),
recipient: suite.TestAccs[1].String(),
amount: sdk.NewInt64Coin("uspay", 100_000_000),
streamType: types.TypePeriodic,
duration: time.Second * 100,
periods: []*types.Period{
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
{
Amount: 1_000_000,
Duration: 10,
},
},
cancellable: true,
paymentFee: sdk.NewInt64Coin("uspay", 1_000_000),
valid: false,
expectedMessageEvents: 0,
},
} {
suite.Run("create stream payment", func() {
ctx := suite.Ctx.WithEventManager(sdk.NewEventManager())
suite.Require().Equal(0, len(ctx.EventManager().Events()))
// Test stream send message
_, err := suite.msgServer.StreamSend(
sdk.WrapSDKContext(ctx),
types.NewMsgStreamSend(
tc.sender,
tc.recipient,
tc.amount,
tc.streamType,
tc.duration,
tc.periods,
tc.cancellable,
),
msg := types.NewMsgStreamSend(
tc.sender,
tc.recipient,
tc.amount,
tc.streamType,
tc.duration,
tc.periods,
tc.cancellable,
tc.paymentFee,
)
err := msg.ValidateBasic()
if err == nil {
_, err = suite.msgServer.StreamSend(
sdk.WrapSDKContext(ctx),
msg,
)
}
if tc.valid {
suite.Require().NoError(err)
}
Expand Down
5 changes: 5 additions & 0 deletions x/streampay/types/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func NewMsgStreamSend(
duration time.Duration,
periods []*Period,
cancellable bool,
paymentFee sdk.Coin,
) *MsgStreamSend {
return &MsgStreamSend{
Sender: sender,
Expand All @@ -37,6 +38,7 @@ func NewMsgStreamSend(
Duration: duration,
Periods: periods,
Cancellable: cancellable,
PaymentFee: paymentFee,
}
}

Expand All @@ -56,6 +58,9 @@ func (msg MsgStreamSend) ValidateBasic() error {
if err := validateAmount(msg.Amount); err != nil {
return err
}
if err := validateAmount(msg.PaymentFee); err != nil {
return err
}
if err := ValidateDuration(msg.Duration); err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions x/streampay/types/messages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestMsgStreamSend(t *testing.T) {
time.Second*100,
periods,
false,
sdk.NewInt64Coin("uspay", 1_000_000),
)

return after(validMsg)
Expand Down
Loading

0 comments on commit b80a68c

Please sign in to comment.