0g-chain/tests/e2e-ibc/main_test.go
2024-04-29 10:13:28 -07:00

212 lines
7.0 KiB
Go

package main_test
import (
"context"
"fmt"
"testing"
"time"
"cosmossdk.io/math"
transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/strangelove-ventures/interchaintest/v8"
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"github.com/strangelove-ventures/interchaintest/v8/testreporter"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
kavainterchain "github.com/kava-labs/kava/tests/interchain"
)
const (
kavaChainId = "kava_8888-1"
kavaEvmChainId = int64(8888)
)
func TestInterchainIBC(t *testing.T) {
ctx := context.Background()
// setup chains
cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{
{Name: "kava", ChainConfig: kavainterchain.DefaultKavaChainConfig(kavaChainId)},
{Name: "gaia", Version: "v15.2.0", ChainConfig: ibc.ChainConfig{GasPrices: "0.0uatom"}},
{Name: "osmosis", Version: "v24.0.1"},
})
chains, err := cf.Chains(t.Name())
require.NoError(t, err)
kava, gaia, osmosis := chains[0].(*cosmos.CosmosChain), chains[1].(*cosmos.CosmosChain), chains[2].(*cosmos.CosmosChain)
// setup relayer
client, network := interchaintest.DockerSetup(t)
r := interchaintest.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t)).
Build(t, client, network)
// configure interchain
const kavaGaiaIbcPath = "kava-gaia-demo"
const kavaOsmosisIbcPath = "kava-osmo-demo"
ic := interchaintest.NewInterchain().
AddChain(kava).
AddChain(gaia).
AddChain(osmosis).
AddRelayer(r, "relayer").
AddLink(interchaintest.InterchainLink{
Chain1: kava,
Chain2: gaia,
Relayer: r,
Path: kavaGaiaIbcPath,
}).
AddLink(interchaintest.InterchainLink{
Chain1: kava,
Chain2: osmosis,
Relayer: r,
Path: kavaOsmosisIbcPath,
})
// Log location
f, err := interchaintest.CreateLogFile(fmt.Sprintf("%d.json", time.Now().Unix()))
require.NoError(t, err)
// Reporter/logs
rep := testreporter.NewReporter(f)
eRep := rep.RelayerExecReporter(t)
// Build interchain
err = ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{
TestName: t.Name(),
Client: client,
NetworkID: network,
SkipPathCreation: false},
)
require.NoError(t, err)
// start the relayer so we don't need to manually Flush() packets
err = r.StartRelayer(ctx, eRep, kavaGaiaIbcPath, kavaOsmosisIbcPath)
require.NoError(t, err)
defer r.StopRelayer(ctx, eRep)
// Create and Fund User Wallets
fundAmount := math.NewInt(10_000_000)
users := interchaintest.GetAndFundTestUsers(t, ctx, "default", fundAmount, kava, gaia, osmosis)
kavaUser := users[0]
gaiaUser := users[1]
osmosisUser := users[2]
// wait for new block to ensure initial funding complete
height, err := kava.Height(ctx)
require.NoError(t, err)
h := height
for h <= height {
h, err = kava.Height(ctx)
require.NoError(t, err)
}
// check initial balance
kavaUserBalInitial, err := kava.GetBalance(ctx, kavaUser.FormattedAddress(), kava.Config().Denom)
require.NoError(t, err)
require.True(t, kavaUserBalInitial.Equal(fundAmount))
// get ibc channel ids
gaiaChannelInfo, err := r.GetChannels(ctx, eRep, gaia.Config().ChainID)
require.NoError(t, err)
osmoChannelInfo, err := r.GetChannels(ctx, eRep, osmosis.Config().ChainID)
require.NoError(t, err)
gaiaToKavaChannelID := gaiaChannelInfo[0].ChannelID
kavaToGaiaChannelID := gaiaChannelInfo[0].Counterparty.ChannelID
osmoToKavaChannelID := osmoChannelInfo[0].ChannelID
kavaToOsmoChannelID := osmoChannelInfo[0].Counterparty.ChannelID
// determine ibc denoms
srcDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", gaiaToKavaChannelID, kava.Config().Denom))
kavaOnGaiaDenom := srcDenomTrace.IBCDenom()
srcDenomTrace = transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", osmoToKavaChannelID, kava.Config().Denom))
kavaOnOsmoDenom := srcDenomTrace.IBCDenom()
amountToSend := math.NewInt(1_000_000)
// IBC transfer kava to cosmoshub
// inspired by https://github.com/strangelove-ventures/interchaintest/blob/main/examples/ibc/learn_ibc_test.go
t.Run("ibc transfer kava -> cosmoshub", func(t *testing.T) {
dstAddress := gaiaUser.FormattedAddress()
transfer := ibc.WalletAmount{
Address: dstAddress,
Denom: kava.Config().Denom,
Amount: amountToSend,
}
tx, err := kava.SendIBCTransfer(ctx, kavaToGaiaChannelID, kavaUser.KeyName(), transfer, ibc.TransferOptions{})
require.NoError(t, err)
require.NoError(t, tx.Validate())
// manually flush packets so we don't need to wait for the relayer
require.NoError(t, r.Flush(ctx, eRep, kavaGaiaIbcPath, kavaToGaiaChannelID))
// verify balance deducted from kava account
expectedBal := kavaUserBalInitial.Sub(amountToSend)
kavaUserBalNew, err := kava.GetBalance(ctx, kavaUser.FormattedAddress(), kava.Config().Denom)
require.NoError(t, err)
require.True(t, kavaUserBalNew.Equal(expectedBal))
// verify cosmoshub account received funds
gaiaUserBalNew, err := gaia.GetBalance(ctx, gaiaUser.FormattedAddress(), kavaOnGaiaDenom)
require.NoError(t, err)
require.True(t, gaiaUserBalNew.Equal(amountToSend))
})
// use coins IBC'd to cosmoshub, send them to osmosis using pfm
t.Run("packet forwarding middleware: cosmoshub -> kava -> osmosis", func(t *testing.T) {
dstAddress := osmosisUser.FormattedAddress()
transfer := ibc.WalletAmount{
Address: "pfm", // purposefully invalid b/c we are forwarding through kava onward to osmosis!
Denom: kavaOnGaiaDenom,
Amount: amountToSend,
}
tx, err := gaia.SendIBCTransfer(ctx, gaiaToKavaChannelID, gaiaUser.KeyName(), transfer, ibc.TransferOptions{
// packet forwarding middleware!
Memo: fmt.Sprintf(`{
"forward": {
"receiver": "%s",
"port": "transfer",
"channel": "%s"
}
}`, dstAddress, kavaToOsmoChannelID),
})
require.NoError(t, err)
require.NoError(t, tx.Validate())
require.Eventually(t, func() bool {
// verify transfer to osmosis
osmosisUserBalNew, err := osmosis.GetBalance(ctx, osmosisUser.FormattedAddress(), kavaOnOsmoDenom)
require.NoError(t, err)
return osmosisUserBalNew.Equal(amountToSend)
}, 15*time.Second, time.Second, "osmosis never received funds")
// verify cosmoshub account no longer has the funds
gaiaUserBalNew, err := gaia.GetBalance(ctx, gaiaUser.FormattedAddress(), kavaOnGaiaDenom)
require.NoError(t, err)
require.True(t, gaiaUserBalNew.Equal(math.ZeroInt()))
})
t.Run("query evm data", func(t *testing.T) {
evmUrl, err := kava.FullNodes[0].GetHostAddress(ctx, "8545/tcp")
require.NoError(t, err)
evmClient, err := ethclient.Dial(evmUrl)
require.NoError(t, err, "failed to connect to evm")
bal, err := evmClient.BalanceAt(ctx, common.BytesToAddress(kavaUser.Address()), nil)
require.NoError(t, err)
// convert ukava to akava
expected := fundAmount.Sub(amountToSend).MulRaw(1e12)
require.Equal(t, expected.BigInt().String(), bal.String())
})
}