Skip to content

Commit

Permalink
Merge branch 'CNS-965-pending-ibc-iprpc-fund' into CNS-966-pending-ib…
Browse files Browse the repository at this point in the history
…c-iprpc-fund-query
  • Loading branch information
oren-lava committed Jun 2, 2024
2 parents d358d88 + 12a19c9 commit 4a158de
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 10 deletions.
3 changes: 1 addition & 2 deletions x/rewards/client/cli/query_generate_ibc_iprpc_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ func getTimeoutHeight(clientQueryCtx client.Context, portId string, channelId st
clientHeight, ok := clientState.GetLatestHeight().(clienttypes.Height)
if !ok {
return clienttypes.ZeroHeight(), fmt.Errorf("invalid height type. expected type: %T, got: %T", clienttypes.Height{}, clientState.GetLatestHeight())

}

defaultTimeoutHeightStr := ibctransfertypes.DefaultRelativePacketTimeoutHeight
Expand All @@ -210,5 +209,5 @@ func getTimeoutHeight(clientQueryCtx client.Context, portId string, channelId st
}

func escapeMemo(memo string) string {
return fmt.Sprintf("%q", string(memo))
return fmt.Sprintf("%q", memo)
}
38 changes: 32 additions & 6 deletions x/rewards/keeper/ibc_iprpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,34 @@ func (k Keeper) NewPendingIbcIprpcFund(ctx sdk.Context, creator string, spec str
)
}

// divide funds by duration since we use addSpecFunds() when applying the PendingIbcIprpcFund
// which assumes that each month will get the input fund
monthlyFund := sdk.NewCoin(fund.Denom, fund.Amount.QuoRaw(int64(duration)))
if monthlyFund.IsZero() {
return utils.LavaFormatWarning("fund amount cannot be less than duration", fmt.Errorf("cannot create PendingIbcIprpcFund"),
utils.LogAttr("creator", creator),
utils.LogAttr("spec", spec),
utils.LogAttr("duration", duration),
utils.LogAttr("funds", fund),
)
}

// leftovers will be transferred to the community pool
leftovers := sdk.NewCoin(fund.Denom, fund.Amount.Sub(monthlyFund.Amount.MulRaw(int64(duration))))
if !leftovers.IsZero() {
receiverName, _ := types.IbcIprpcReceiverAddress()
err := k.FundCommunityPoolFromModule(ctx, sdk.NewCoins(leftovers), receiverName)
if err != nil {
return utils.LavaFormatError("cannot transfer monthly fund leftovers to community pool for PendingIbcIprpcFund", err,
utils.LogAttr("creator", creator),
utils.LogAttr("spec", spec),
utils.LogAttr("duration", duration),
utils.LogAttr("funds", fund),
utils.LogAttr("leftovers", leftovers),
)
}
}

// get index for the new object
latestPendingIbcIprpcFund := k.GetLatestPendingIbcIprpcFund(ctx)
newIndex := uint64(0)
Expand All @@ -143,7 +171,7 @@ func (k Keeper) NewPendingIbcIprpcFund(ctx sdk.Context, creator string, spec str
Creator: creator,
Spec: spec,
Duration: duration,
Fund: fund,
Fund: monthlyFund,
Expiry: expiry,
}

Expand All @@ -158,16 +186,14 @@ func (k Keeper) NewPendingIbcIprpcFund(ctx sdk.Context, creator string, spec str
)
}

k.SetPendingIbcIprpcFund(ctx, pendingIbcIprpcFund)

return nil
}

// SetPendingIbcIprpcFund set an PendingIbcIprpcFund in the PendingIbcIprpcFund store
func (k Keeper) SetPendingIbcIprpcFund(ctx sdk.Context, PendingIbcIprpcFund types.PendingIbcIprpcFund) {
func (k Keeper) SetPendingIbcIprpcFund(ctx sdk.Context, pendingIbcIprpcFund types.PendingIbcIprpcFund) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PendingIbcIprpcFundPrefix))
b := k.cdc.MustMarshal(&PendingIbcIprpcFund)
store.Set(maps.GetIDBytes(PendingIbcIprpcFund.Index), b)
b := k.cdc.MustMarshal(&pendingIbcIprpcFund)
store.Set(maps.GetIDBytes(pendingIbcIprpcFund.Index), b)
}

// IsPendingIbcIprpcFund gets an PendingIbcIprpcFund from the PendingIbcIprpcFund store
Expand Down
50 changes: 48 additions & 2 deletions x/rewards/keeper/ibc_iprpc_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package keeper_test

import (
"testing"

"strconv"
"testing"
"time"

sdkerrors "cosmossdk.io/errors"
Expand Down Expand Up @@ -404,3 +403,50 @@ func TestPendingIbcIprpcFundsQuery(t *testing.T) {
})
}
}

// TestPendingIbcIprpcFundNewFunds tests that when creating a new PendingIbcIprpcFund the original
// fund gets divided by duration and the division leftovers are transferred to the community pool
func TestPendingIbcIprpcFundNewFunds(t *testing.T) {
template := []struct {
name string
funds math.Int
duration uint64
expectedFundsInPending math.Int
expectedFundsInCommunity math.Int
success bool
}{
{"divisiable - 9ulava", math.NewInt(9), 3, math.NewInt(3), math.ZeroInt(), true},
{"not divisiable - 10ulava", math.NewInt(10), 3, math.NewInt(3), math.OneInt(), true},
{"less than duration - 1ulava", math.NewInt(1), 3, math.ZeroInt(), math.ZeroInt(), false},
{"one month duration - 10ulava", math.NewInt(10), 1, math.NewInt(10), math.ZeroInt(), true},
}

for _, tt := range template {
t.Run(tt.name, func(t *testing.T) {
ts := newTester(t, false)
keeper, ctx := ts.Keepers.Rewards, ts.Ctx
spec := ts.Spec("mock")
funds := sdk.NewCoin(ts.TokenDenom(), tt.funds)

// set the IPRPC receiver balance manually since we don't call the IBC middleware
// this is crucial since the leftover funds are taken from it to the community pool
_, iprpcReceiverAddr := types.IbcIprpcReceiverAddress()
ts.Keepers.BankKeeper.SetBalance(ctx, iprpcReceiverAddr, sdk.NewCoins(funds))

// create a new PendingIbcIprpcFund
err := keeper.NewPendingIbcIprpcFund(ctx, "creator", spec.Index, tt.duration, funds)
if tt.success {
require.NoError(t, err)
latest := keeper.GetLatestPendingIbcIprpcFund(ts.Ctx)
require.True(t, latest.Fund.Amount.Equal(tt.expectedFundsInPending))
} else {
require.Error(t, err)
}

// check community pool balance
communityCoins := ts.Keepers.Distribution.GetFeePoolCommunityCoins(ts.Ctx)
communityBalance := communityCoins.AmountOf(ts.TokenDenom()).TruncateInt()
require.True(t, communityBalance.Equal(tt.expectedFundsInCommunity))
})
}
}

0 comments on commit 4a158de

Please sign in to comment.