Skip to content

Commit

Permalink
Merge branch 'main' into audit_fix_stylist
Browse files Browse the repository at this point in the history
  • Loading branch information
sontrinh16 authored Oct 30, 2023
2 parents 6e2a207 + 20bb508 commit 1802a3a
Show file tree
Hide file tree
Showing 16 changed files with 849 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/

# Primary repo maintainers
* @joe-bowman @ajansari95 @muku314115 @ThanhNhann @faddat @sontrinh16 @anhductn2001
* @joe-bowman @ThanhNhann @faddat @sontrinh16 @anhductn2001
4 changes: 2 additions & 2 deletions x/interchainstaking/keeper/callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func DepositIntervalCallback(k *Keeper, ctx sdk.Context, args []byte, query icqt
for _, txn := range txs.TxResponses {
req := tx.GetTxRequest{Hash: txn.TxHash}
hashBytes := k.cdc.MustMarshal(&req)
_, found = k.GetReceipt(ctx, types.GetReceiptKey(zone.ChainId, txn.TxHash))
_, found = k.GetReceipt(ctx, zone.ChainId, txn.TxHash)
if found {
k.Logger(ctx).Debug("Found previously handled tx. Ignoring.", "txhash", txn.TxHash)
continue
Expand Down Expand Up @@ -445,7 +445,7 @@ func DepositTxCallback(k *Keeper, ctx sdk.Context, args []byte, query icqtypes.Q
return fmt.Errorf("invalid tx for query - expected %s, got %s", queryRequest.Hash, hashStr)
}

_, found = k.GetReceipt(ctx, types.GetReceiptKey(zone.ChainId, hashStr))
_, found = k.GetReceipt(ctx, zone.ChainId, hashStr)
if found {
k.Logger(ctx).Info("Found previously handled tx. Ignoring.", "txhash", hashStr)
return nil
Expand Down
228 changes: 228 additions & 0 deletions x/interchainstaking/keeper/callbacks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ import (
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/proto/tendermint/types"

"cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/types/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

ibctypes "github.com/cosmos/ibc-go/v5/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types"
lightclienttypes "github.com/cosmos/ibc-go/v5/modules/light-clients/07-tendermint/types"

"github.com/quicksilver-zone/quicksilver/app"
Expand Down Expand Up @@ -802,6 +806,230 @@ func (suite *KeeperTestSuite) TestHandleValideRewardsCallback() {
})
}

func (suite *KeeperTestSuite) TestHandleDistributeRewardsCallback() {
suite.SetupTest()
suite.setupTestZones()
quicksilver := suite.GetQuicksilverApp(suite.chainA)
gaia := suite.GetQuicksilverApp(suite.chainB)
quicksilver.InterchainstakingKeeper.CallbackHandler().RegisterCallbacks()

ctxA := suite.chainA.GetContext()
ctxB := suite.chainB.GetContext()
vals := gaia.StakingKeeper.GetAllValidators(ctxB)

zone, found := quicksilver.InterchainstakingKeeper.GetZone(ctxA, suite.chainB.ChainID)
suite.True(found)
params := quicksilver.InterchainstakingKeeper.GetParams(ctxA)
commisionRate := sdk.MustNewDecFromStr("0.2")
params.CommissionRate = commisionRate
quicksilver.InterchainstakingKeeper.SetParams(ctxA, params)

prevRedemptionRate := zone.RedemptionRate
tests := []struct {
name string
zoneSetup func()
connectionSetup func() string
responseMsg func() []byte
queryMsg icqtypes.Query
check func()
pass bool
}{
{
// delta = ratio / redemption_rate
// The original redemption rate is 1 so if ratio exceed (-0.95, 1.02) range,
// it would be kept in the boundary
name: "valid case with positive rewards and -95% < delta < 102%",
zoneSetup: func() {
balances := sdk.NewCoins(
sdk.NewCoin(
zone.LocalDenom,
math.NewInt(100_000_000),
),
)
err := quicksilver.MintKeeper.MintCoins(ctxA, balances)
suite.NoError(err)
qAssetAmount := quicksilver.BankKeeper.GetSupply(ctxA, zone.LocalDenom)
suite.Equal(balances[0], qAssetAmount)

delegation := icstypes.Delegation{DelegationAddress: zone.DelegationAddress.Address, ValidatorAddress: vals[0].OperatorAddress, Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(100_000_000))}
quicksilver.InterchainstakingKeeper.SetDelegation(ctxA, &zone, delegation)
},
connectionSetup: func() string {
channelID := quicksilver.IBCKeeper.ChannelKeeper.GenerateChannelIdentifier(ctxA)
quicksilver.IBCKeeper.ChannelKeeper.SetChannel(ctxA, icstypes.TransferPort, channelID, channeltypes.Channel{State: channeltypes.OPEN, Ordering: channeltypes.ORDERED, Counterparty: channeltypes.Counterparty{PortId: icstypes.TransferPort, ChannelId: channelID}, ConnectionHops: []string{suite.path.EndpointA.ConnectionID}})
quicksilver.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctxA, icstypes.TransferPort, channelID, 1)
return channelID
},
responseMsg: func() []byte {
balances := sdk.NewCoins(
sdk.NewCoin(
zone.BaseDenom,
math.NewInt(1_000_000),
),
)

response := banktypes.QueryAllBalancesResponse{
Balances: balances,
}
respbz, err := quicksilver.AppCodec().Marshal(&response)
suite.NoError(err)
return respbz
},
queryMsg: icqtypes.Query{ChainId: suite.chainB.ChainID},
check: func() {
zone, _ := quicksilver.InterchainstakingKeeper.GetZone(ctxA, suite.chainB.ChainID)
redemptionRate := zone.RedemptionRate

// The ratio is calculated as:
// ratio = (total_delegate + total_unbonding + epoch_rewards) / total_q_asset
// total_delegate = total_q_asset = 100_000_000
// total_unbonding = 0
// epoch_rewards = balances * (1 - commission_rate) = 1_000_000 * 0.8
// Therefore, ratio should be 1.008
ratio := sdk.MustNewDecFromStr("1.008")
suite.Equal(ratio.Mul(prevRedemptionRate), redemptionRate)
},
pass: true,
},
{
name: "valid case with no rewards",
zoneSetup: func() {},
connectionSetup: func() string {
channelID := quicksilver.IBCKeeper.ChannelKeeper.GenerateChannelIdentifier(ctxA)
quicksilver.IBCKeeper.ChannelKeeper.SetChannel(ctxA, icstypes.TransferPort, channelID, channeltypes.Channel{State: channeltypes.OPEN, Ordering: channeltypes.ORDERED, Counterparty: channeltypes.Counterparty{PortId: icstypes.TransferPort, ChannelId: channelID}, ConnectionHops: []string{suite.path.EndpointA.ConnectionID}})
quicksilver.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctxA, icstypes.TransferPort, channelID, 1)
return channelID
},
responseMsg: func() []byte {
response := banktypes.QueryAllBalancesResponse{
Balances: sdk.Coins{},
}
respbz, err := quicksilver.AppCodec().Marshal(&response)
suite.NoError(err)
return respbz
},
queryMsg: icqtypes.Query{ChainId: suite.chainB.ChainID},
check: func() {
zone, _ := quicksilver.InterchainstakingKeeper.GetZone(ctxA, suite.chainB.ChainID)
redemptionRate := zone.RedemptionRate

suite.Equal(prevRedemptionRate, redemptionRate)
},
pass: true,
},
{
name: "invalid chainId query",
zoneSetup: func() {},
connectionSetup: func() string {
channelID := quicksilver.IBCKeeper.ChannelKeeper.GenerateChannelIdentifier(ctxA)
quicksilver.IBCKeeper.ChannelKeeper.SetChannel(ctxA, icstypes.TransferPort, channelID, channeltypes.Channel{State: channeltypes.OPEN, Ordering: channeltypes.ORDERED, Counterparty: channeltypes.Counterparty{PortId: icstypes.TransferPort, ChannelId: channelID}, ConnectionHops: []string{suite.path.EndpointA.ConnectionID}})
quicksilver.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctxA, icstypes.TransferPort, channelID, 1)
return channelID
},
responseMsg: func() []byte {
balances := sdk.NewCoins(
sdk.NewCoin(
zone.BaseDenom,
math.NewInt(10_000_000),
),
)

response := banktypes.QueryAllBalancesResponse{
Balances: balances,
}
respbz, err := quicksilver.AppCodec().Marshal(&response)
suite.NoError(err)
return respbz
},
queryMsg: icqtypes.Query{ChainId: ""},
check: func() {},
pass: false,
},
{
name: "invalid response",
zoneSetup: func() {},
connectionSetup: func() string {
channelID := quicksilver.IBCKeeper.ChannelKeeper.GenerateChannelIdentifier(ctxA)
quicksilver.IBCKeeper.ChannelKeeper.SetChannel(ctxA, icstypes.TransferPort, channelID, channeltypes.Channel{State: channeltypes.OPEN, Ordering: channeltypes.ORDERED, Counterparty: channeltypes.Counterparty{PortId: icstypes.TransferPort, ChannelId: channelID}, ConnectionHops: []string{suite.path.EndpointA.ConnectionID}})
quicksilver.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctxA, icstypes.TransferPort, channelID, 1)
return channelID
},
responseMsg: func() []byte {
balance := sdk.NewCoin(
zone.BaseDenom,
math.NewInt(10_000_000),
)
respbz, err := quicksilver.AppCodec().Marshal(&balance)
suite.NoError(err)
return respbz
},
queryMsg: icqtypes.Query{ChainId: suite.chainB.ChainID},
check: func() {},
pass: false,
},
{
name: "no connection setup",
zoneSetup: func() {},
connectionSetup: func() string {
return ""
},
responseMsg: func() []byte {
balances := sdk.NewCoins(
sdk.NewCoin(
zone.BaseDenom,
math.NewInt(10_000_000),
),
)

response := banktypes.QueryAllBalancesResponse{
Balances: balances,
}
respbz, err := quicksilver.AppCodec().Marshal(&response)
suite.NoError(err)
return respbz
},
queryMsg: icqtypes.Query{ChainId: suite.chainB.ChainID},
check: func() {},
pass: false,
},
}
for _, test := range tests {
suite.Run(test.name, func() {
// Send coin to withdrawal address
balances := sdk.NewCoins(
sdk.NewCoin(
zone.BaseDenom,
math.NewInt(10_000_000),
),
)
err := gaia.MintKeeper.MintCoins(ctxB, balances)
suite.NoError(err)
addr, err := addressutils.AccAddressFromBech32(zone.WithdrawalAddress.Address, "")
suite.NoError(err)
err = gaia.BankKeeper.SendCoinsFromModuleToAccount(ctxB, minttypes.ModuleName, addr, balances)
suite.NoError(err)

test.zoneSetup()
channelID := test.connectionSetup()

respbz := test.responseMsg()
err = keeper.DistributeRewardsFromWithdrawAccount(quicksilver.InterchainstakingKeeper, ctxA, respbz, test.queryMsg)
if test.pass {
suite.NoError(err)
} else {
suite.Error(err)
}

test.check()
channel, found := quicksilver.IBCKeeper.ChannelKeeper.GetChannel(ctxA, icstypes.TransferPort, channelID)
if found {
channel.State = channeltypes.CLOSED
quicksilver.IBCKeeper.ChannelKeeper.SetChannel(ctxA, icstypes.TransferPort, channelID, channel)
}
})
}
}

func (suite *KeeperTestSuite) TestAllBalancesCallback() {
suite.Run("all balances non-zero)", func() {
suite.SetupTest()
Expand Down
2 changes: 1 addition & 1 deletion x/interchainstaking/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func (k *Keeper) TxStatus(c context.Context, req *types.QueryTxStatusRequest) (*

ctx := sdk.UnwrapSDKContext(c)

txReceipt, found := k.GetReceipt(ctx, types.GetReceiptKey(req.GetChainId(), req.GetTxHash()))
txReceipt, found := k.GetReceipt(ctx, req.GetChainId(), req.GetTxHash())
if !found {
return nil, status.Error(codes.NotFound, fmt.Sprintf("no receipt found matching %s", req.TxHash))
}
Expand Down
12 changes: 6 additions & 6 deletions x/interchainstaking/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() {
zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID)
suite.True(found)

distribution := []*types.Distribution{
distributions := []*types.Distribution{
{
Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress,
Amount: 10000000,
Expand All @@ -788,7 +788,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() {
ctx,
zone.ChainId,
delegatorAddress,
distribution,
distributions,
testAddress,
sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(15000000))),
sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)),
Expand Down Expand Up @@ -877,7 +877,7 @@ func (suite *KeeperTestSuite) TestKeeper_UserWithdrawalRecords() {
zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID)
suite.True(found)

distribution := []*types.Distribution{
distributions := []*types.Distribution{
{
Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress,
Amount: 10000000,
Expand All @@ -893,7 +893,7 @@ func (suite *KeeperTestSuite) TestKeeper_UserWithdrawalRecords() {
ctx,
zone.ChainId,
delegatorAddress,
distribution,
distributions,
testAddress,
sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(15000000))),
sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)),
Expand Down Expand Up @@ -970,7 +970,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() {
zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID)
suite.True(found)

distribution := []*types.Distribution{
distributions := []*types.Distribution{
{
Valoper: icsKeeper.GetValidators(ctx, suite.chainB.ChainID)[0].ValoperAddress,
Amount: 10000000,
Expand All @@ -986,7 +986,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() {
ctx,
zone.ChainId,
delegatorAddress,
distribution,
distributions,
testAddress,
sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(15000000))),
sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)),
Expand Down
13 changes: 10 additions & 3 deletions x/interchainstaking/keeper/ibc_packet_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,8 @@ func (k *Keeper) HandleTokenizedShares(ctx sdk.Context, msg sdk.Msg, sharesAmoun
}

for _, dist := range withdrawalRecord.Distribution {
if sharesAmount.Equal(dist.Amount) {
withdrawalRecord.Amount.Add(sharesAmount)
if equalLsmCoin(dist.Valoper, dist.Amount, sharesAmount) {
withdrawalRecord.Amount = withdrawalRecord.Amount.Add(sharesAmount)
// matched amount
if len(withdrawalRecord.Distribution) == len(withdrawalRecord.Amount) {
// we just added the last tokens
Expand Down Expand Up @@ -937,7 +937,7 @@ func (k *Keeper) HandleDelegate(ctx sdk.Context, msg sdk.Msg, memo string) error
}
}
default:
receipt, found := k.GetReceipt(ctx, types.GetReceiptKey(zone.ChainId, memo))
receipt, found := k.GetReceipt(ctx, zone.ChainId, memo)
if !found {
return fmt.Errorf("unable to find receipt for hash %s", memo)
}
Expand Down Expand Up @@ -1240,3 +1240,10 @@ func (*Keeper) prepareRewardsDistributionMsgs(zone types.Zone, rewards sdkmath.I
Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, rewards)),
}
}

func equalLsmCoin(valoper string, amount uint64, lsmAmount sdk.Coin) bool {
if strings.Contains(lsmAmount.Denom, valoper) {
return lsmAmount.Amount.Equal(sdk.NewIntFromUint64(amount))
}
return false
}
Loading

0 comments on commit 1802a3a

Please sign in to comment.