diff --git a/examples/stride/setup_test.go b/examples/stride/setup_test.go index 16823805f..87f87652b 100644 --- a/examples/stride/setup_test.go +++ b/examples/stride/setup_test.go @@ -1,11 +1,14 @@ package stride_test import ( + "context" "encoding/json" "fmt" "github.com/icza/dyno" + "github.com/strangelove-ventures/ibctest/v3/chain/cosmos" "github.com/strangelove-ventures/ibctest/v3/ibc" + "github.com/strangelove-ventures/ibctest/v3/test" ) const ( @@ -91,6 +94,21 @@ type DepositRecordWrapper struct { DepositRecord []DepositRecord `json:"DepositRecord"` } +type UserRedemptionRecordWrapper struct { + UserRedemptionRecord []UserRedemptionRecord `json:"UserRedemptionRecord"` +} + +type UserRedemptionRecord struct { + ID string `json:"id"` + Sender string `json:"sender"` + Receiver string `json:"receiver"` + Amount string `json:"amount"` + Denom string `json:"denom"` + HostZoneID string `json:"hostZoneId"` + EpochNumber string `json:"epochNumber"` + ClaimIsPending bool `json:"claimIsPending"` +} + func ModifyGenesisStride() func(ibc.ChainConfig, []byte) ([]byte, error) { return func(cfg ibc.ChainConfig, genbz []byte) ([]byte, error) { g := make(map[string]interface{}) @@ -159,3 +177,33 @@ func ModifyGenesisStrideCounterparty() func(ibc.ChainConfig, []byte) ([]byte, er return out, nil } } + +// PollForHostZoneStakedBalance polls until the host zone for the given chainID has a non-zero staked balance +func PollForHostZoneStakedBalance(ctx context.Context, chain *cosmos.CosmosChain, startHeight, maxHeight uint64, chainID string) (HostZoneWrapper, error) { + var zero HostZoneWrapper + doPoll := func(ctx context.Context, height uint64) (any, error) { + stdout, _, err := chain.FullNodes[0].ExecQuery(ctx, + "stakeibc", "show-host-zone", chainID, + ) + if err != nil { + return zero, err + } + hostZone := new(HostZoneWrapper) + err = json.Unmarshal(stdout, &hostZone) + if err != nil { + return zero, err + } + + if hostZone.HostZone.StakedBal == "0" { + return zero, fmt.Errorf("host zone for %s has zero staked balance", chainID) + } + + return *hostZone, nil + } + bp := test.BlockPoller{CurrentHeight: chain.Height, PollFunc: doPoll} + p, err := bp.DoPoll(ctx, startHeight, maxHeight) + if err != nil { + return zero, err + } + return p.(HostZoneWrapper), nil +} diff --git a/examples/stride/stride_redemptions_test.go b/examples/stride/stride_redemptions_test.go index 48af35ecc..fba47a3e4 100644 --- a/examples/stride/stride_redemptions_test.go +++ b/examples/stride/stride_redemptions_test.go @@ -3,7 +3,7 @@ package stride_test import ( "context" "encoding/json" - "fmt" + "strconv" "testing" "github.com/cosmos/cosmos-sdk/types" @@ -81,8 +81,8 @@ func TestStrideRedemptions(t *testing.T) { r := ibctest.NewBuiltinRelayerFactory( ibc.CosmosRly, zaptest.NewLogger(t), - relayer.ImagePull(false), - relayer.CustomDockerImage("relayer", "local", "100:1000"), + //relayer.ImagePull(false), + relayer.CustomDockerImage("ghcr.io/cosmos/relayer", "andrew-client_icq", "100:1000"), relayer.StartupFlags("-p", "events"), ).Build(t, client, network) @@ -123,7 +123,7 @@ func TestStrideRedemptions(t *testing.T) { strideUser, gaiaUser := users[0], users[1] strideFullNode := stride.FullNodes[0] - gaiaFullNode := gaia.FullNodes[0] + //gaiaFullNode := gaia.FullNodes[0] // Wait a few blocks for user accounts to be created on chain. err = test.WaitForBlocks(ctx, 2, stride, gaia) @@ -249,6 +249,12 @@ func TestStrideRedemptions(t *testing.T) { err = json.Unmarshal(stdout, &gaiaHostZone) require.NoError(t, err) + strideUserIBCAtomBefore, err := stride.GetBalance(ctx, strideAddr, atomIBCDenom) + require.NoError(t, err) + + strideUserSTAtomBefore, err := stride.GetBalance(ctx, strideAddr, "st"+gaiaCfg.Denom) + require.NoError(t, err) + // Liquid stake some atom _, err = strideFullNode.ExecTx(ctx, strideUser.KeyName, "stakeibc", "liquid-stake", @@ -256,37 +262,95 @@ func TestStrideRedemptions(t *testing.T) { ) require.NoError(t, err) + err = test.WaitForBlocks(ctx, 10, stride, gaia) + require.NoError(t, err) + + strideUserIBCAtomAfter, err := stride.GetBalance(ctx, strideAddr, atomIBCDenom) + require.NoError(t, err) + + strideUserSTAtomAfter, err := stride.GetBalance(ctx, strideAddr, "st"+gaiaCfg.Denom) + require.NoError(t, err) + + require.Equal(t, strideUserIBCAtomBefore-10000, strideUserIBCAtomAfter) + require.Equal(t, strideUserSTAtomBefore+10000, strideUserSTAtomAfter) + // wait for delegation - for { - err = test.WaitForBlocks(ctx, 1, stride, gaia) - require.NoError(t, err) - - stdout, _, err := strideFullNode.ExecQuery(ctx, - "stakeibc", "show-host-zone", gaiaCfg.ChainID, - ) - require.NoError(t, err) - err = json.Unmarshal(stdout, &gaiaHostZone) - require.NoError(t, err) - - if gaiaHostZone.HostZone.StakedBal != "0" { - break - } - } + height, err := stride.Height(ctx) + require.NoError(t, err) + + _, err = PollForHostZoneStakedBalance(ctx, stride, height, height+70, gaiaCfg.ChainID) + require.NoError(t, err) + + redemptionAmount := int64(5) // Redeem _, err = strideFullNode.ExecTx(ctx, strideUser.KeyName, "stakeibc", "redeem-stake", - "5000", gaiaCfg.ChainID, gaiaUser.Address, + strconv.FormatInt(redemptionAmount, 10), gaiaCfg.ChainID, gaiaAddress, ) + require.NoError(t, err) - err = test.WaitForBlocks(ctx, 100, stride, gaia) + // err = test.WaitForBlocks(ctx, 20, stride, gaia) + // require.NoError(t, err) // Check that tokens were transfered to the redemption account - redemptionAddress := gaiaHostZone.HostZone.RedemptionAccount.Address - redemptionBalance, err := gaiaFullNode.Chain.GetBalance(ctx, redemptionAddress, "uatom") + // redemptionBalance, err := gaiaFullNode.Chain.GetBalance(ctx, hz.HostZone.RedemptionAccount.Address, gaiaCfg.Denom) + // require.NoError(t, err) + // require.Greater(t, redemptionBalance, int64(0)) + + // fmt.Printf("redemption balance: %d\n", redemptionBalance) + + stdout, _, err = strideFullNode.ExecQuery(ctx, + "records", "list-user-redemption-record", + ) + require.NoError(t, err) + + var userRedemptionRecords UserRedemptionRecordWrapper + err = json.Unmarshal(stdout, &userRedemptionRecords) + require.NoError(t, err) + require.Len(t, userRedemptionRecords.UserRedemptionRecord, 1) + redemptionRecord := userRedemptionRecords.UserRedemptionRecord[0] + require.Equal(t, redemptionRecord.HostZoneID, gaiaCfg.ChainID) + require.False(t, redemptionRecord.ClaimIsPending) + require.Equal(t, redemptionRecord.Amount, strconv.FormatInt(redemptionAmount, 10)) + require.Equal(t, redemptionRecord.Denom, gaiaCfg.Denom) + require.Equal(t, redemptionRecord.Sender, strideAddr) + require.Equal(t, redemptionRecord.Receiver, gaiaAddress) + + // wait for unbondings to process + err = test.WaitForBlocks(ctx, 100, stride, gaia) + require.NoError(t, err) + + balanceBeforeClaim, err := gaia.GetBalance(ctx, gaiaAddress, gaiaCfg.Denom) + require.NoError(t, err) + + _, err = strideFullNode.ExecTx(ctx, strideUser.KeyName, + "stakeibc", "claim-undelegated-tokens", gaiaCfg.ChainID, + redemptionRecord.EpochNumber, strideAddr, + ) + require.NoError(t, err) + + stdout, _, err = strideFullNode.ExecQuery(ctx, + "records", "list-user-redemption-record", + ) + require.NoError(t, err) + + err = json.Unmarshal(stdout, &userRedemptionRecords) require.NoError(t, err) + require.Len(t, userRedemptionRecords.UserRedemptionRecord, 1) + redemptionRecord = userRedemptionRecords.UserRedemptionRecord[0] + require.Equal(t, redemptionRecord.HostZoneID, gaiaCfg.ChainID) + require.True(t, redemptionRecord.ClaimIsPending) + require.Equal(t, redemptionRecord.Amount, strconv.FormatInt(redemptionAmount, 10)) + require.Equal(t, redemptionRecord.Denom, gaiaCfg.Denom) + require.Equal(t, redemptionRecord.Sender, strideAddr) + require.Equal(t, redemptionRecord.Receiver, gaiaAddress) - fmt.Println("BALANCE:", redemptionBalance) + err = test.WaitForBlocks(ctx, 100, stride, gaia) + require.NoError(t, err) + + balanceAfterClaim, err := gaia.GetBalance(ctx, gaiaAddress, gaiaCfg.Denom) + require.NoError(t, err) - require.True(t, redemptionBalance > 0) + require.Equal(t, balanceBeforeClaim+redemptionAmount, balanceAfterClaim) }