mirror of https://github.com/certusone/wasmd.git
844 lines
34 KiB
Go
844 lines
34 KiB
Go
package integration
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
wasmvm "github.com/CosmWasm/wasmvm/v3"
|
|
wasmvmtypes "github.com/CosmWasm/wasmvm/v3/types"
|
|
ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types"
|
|
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" //nolint:staticcheck
|
|
channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types"
|
|
ibctesting "github.com/cosmos/ibc-go/v10/testing"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
sdkmath "cosmossdk.io/math"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
wasmibctesting "github.com/CosmWasm/wasmd/tests/wasmibctesting"
|
|
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
|
|
"github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
|
|
"github.com/CosmWasm/wasmd/x/wasm/types"
|
|
)
|
|
|
|
// GetTransferCoin creates a transfer coin with the port ID and channel ID
|
|
// prefixed to the base denom.
|
|
func GetTransferCoin(portID, channelID, baseDenom string, amount sdkmath.Int) sdk.Coin {
|
|
denomTrace := fmt.Sprintf("%s/%s/%s",
|
|
portID,
|
|
channelID,
|
|
baseDenom,
|
|
)
|
|
hash := sha256.Sum256([]byte(denomTrace))
|
|
ibcDenom := fmt.Sprintf("ibc/%s", strings.ToUpper(hex.EncodeToString(hash[:])))
|
|
return sdk.NewCoin(ibcDenom, amount)
|
|
}
|
|
|
|
func TestFromIBCTransferToContract(t *testing.T) {
|
|
// scenario: given two chains,
|
|
// with a contract on chain B
|
|
// then the contract can handle the receiving side of an ics20 transfer
|
|
// that was started on chain A via ibc transfer module
|
|
|
|
transferAmount := sdkmath.NewInt(1)
|
|
specs := map[string]struct {
|
|
contract wasmtesting.IBCContractCallbacks
|
|
setupContract func(t *testing.T, contract wasmtesting.IBCContractCallbacks, chain *wasmibctesting.WasmTestChain)
|
|
expChainAPendingSendPackets int
|
|
expChainBPendingSendPackets int
|
|
expChainABalanceDiff sdkmath.Int
|
|
expChainBBalanceDiff sdkmath.Int
|
|
expErr bool
|
|
}{
|
|
"ack": {
|
|
contract: &ackReceiverContract{},
|
|
setupContract: func(t *testing.T, contract wasmtesting.IBCContractCallbacks, chain *wasmibctesting.WasmTestChain) {
|
|
c := contract.(*ackReceiverContract)
|
|
c.t = t
|
|
c.chain = chain
|
|
},
|
|
expChainAPendingSendPackets: 0,
|
|
expChainBPendingSendPackets: 0,
|
|
expChainABalanceDiff: transferAmount.Neg(),
|
|
expChainBBalanceDiff: transferAmount,
|
|
},
|
|
"nack": {
|
|
contract: &nackReceiverContract{},
|
|
setupContract: func(t *testing.T, contract wasmtesting.IBCContractCallbacks, chain *wasmibctesting.WasmTestChain) {
|
|
c := contract.(*nackReceiverContract)
|
|
c.t = t
|
|
},
|
|
expChainAPendingSendPackets: 0,
|
|
expChainBPendingSendPackets: 0,
|
|
expChainABalanceDiff: sdkmath.ZeroInt(),
|
|
expChainBBalanceDiff: sdkmath.ZeroInt(),
|
|
},
|
|
"error": {
|
|
contract: &errorReceiverContract{},
|
|
setupContract: func(t *testing.T, contract wasmtesting.IBCContractCallbacks, chain *wasmibctesting.WasmTestChain) {
|
|
c := contract.(*errorReceiverContract)
|
|
c.t = t
|
|
},
|
|
expChainAPendingSendPackets: 1,
|
|
expChainBPendingSendPackets: 0,
|
|
expChainABalanceDiff: transferAmount.Neg(),
|
|
expChainBBalanceDiff: sdkmath.ZeroInt(),
|
|
expErr: true,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(spec.contract),
|
|
)}
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, []wasmkeeper.Option{}, chainAOpts)
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
myContractAddr := chainB.SeedNewContractInstance()
|
|
contractBPortID := chainB.ContractInfo(myContractAddr).IBCPortID
|
|
|
|
spec.setupContract(t, spec.contract, chainB)
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: "transfer",
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: contractBPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
|
|
originalChainABalance := chainA.Balance(chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom)
|
|
// when transfer via sdk transfer from A (module) -> B (contract)
|
|
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, transferAmount)
|
|
timeoutHeight := clienttypes.NewHeight(1, 110)
|
|
|
|
msg := ibctransfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, chainA.SenderAccount.GetAddress().String(), chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "")
|
|
_, err := chainA.SendMsgs(msg)
|
|
require.NoError(t, err)
|
|
require.NoError(t, path.EndpointB.UpdateClient())
|
|
|
|
// then
|
|
require.Equal(t, 1, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, 0, len(*chainB.PendingSendPackets))
|
|
|
|
// and when relay to chain B and handle Ack on chain A
|
|
err = wasmibctesting.RelayAndAckPendingPackets(path)
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// then
|
|
require.Equal(t, spec.expChainAPendingSendPackets, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, spec.expChainBPendingSendPackets, len(*chainB.PendingSendPackets))
|
|
|
|
// and source chain balance was decreased
|
|
newChainABalance := chainA.Balance(chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom)
|
|
assert.Equal(t, originalChainABalance.Amount.Add(spec.expChainABalanceDiff), newChainABalance.Amount)
|
|
|
|
// and dest chain balance contains voucher
|
|
expBalance := GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinToSendToB.Denom, spec.expChainBBalanceDiff)
|
|
gotBalance := chainB.Balance(chainB.SenderAccount.GetAddress(), expBalance.Denom)
|
|
assert.Equal(t, expBalance, gotBalance, "got total balance: %s", chainB.AllBalances(chainB.SenderAccount.GetAddress()))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestContractCanInitiateIBCTransferMsg(t *testing.T) {
|
|
// scenario: given two chains,
|
|
// with a contract on chain A
|
|
// then the contract can start an ibc transfer via ibctransfertypes.NewMsgTransfer
|
|
// that is handled on chain A by the ibc transfer module and
|
|
// received on chain B via ibc transfer module as well
|
|
|
|
myContract := &sendViaIBCTransferContract{t: t}
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContract)),
|
|
}
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
myContractAddr := chainA.SeedNewContractInstance()
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: ibctransfertypes.PortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: ibctransfertypes.PortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
|
|
// when contract is triggered to send IBCTransferMsg
|
|
receiverAddress := chainB.SenderAccount.GetAddress()
|
|
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))
|
|
|
|
// start transfer from chainA to chainB
|
|
startMsg := &types.MsgExecuteContract{
|
|
Sender: chainA.SenderAccount.GetAddress().String(),
|
|
Contract: myContractAddr.String(),
|
|
Msg: startTransfer{
|
|
ChannelID: path.EndpointA.ChannelID,
|
|
CoinsToSend: coinToSendToB,
|
|
ReceiverAddr: receiverAddress.String(),
|
|
}.GetBytes(),
|
|
}
|
|
// trigger contract to start the transfer
|
|
_, err := chainA.SendMsgs(startMsg)
|
|
require.NoError(t, err)
|
|
|
|
// then
|
|
require.Equal(t, 1, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, 0, len(*chainB.PendingSendPackets))
|
|
|
|
// and when relay to chain B and handle Ack on chain A
|
|
err = wasmibctesting.RelayAndAckPendingPackets(path)
|
|
require.NoError(t, err)
|
|
|
|
// then
|
|
require.Equal(t, 0, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, 0, len(*chainB.PendingSendPackets))
|
|
|
|
// and dest chain balance contains voucher
|
|
bankKeeperB := chainB.GetWasmApp().BankKeeper
|
|
expBalance := GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinToSendToB.Denom, coinToSendToB.Amount)
|
|
gotBalance := chainB.Balance(chainB.SenderAccount.GetAddress(), expBalance.Denom)
|
|
assert.Equal(t, expBalance, gotBalance, "got total balance: %s", bankKeeperB.GetAllBalances(chainB.GetContext(), chainB.SenderAccount.GetAddress()))
|
|
}
|
|
|
|
func TestContractCanEmulateIBCTransferMessage(t *testing.T) {
|
|
// scenario: given two chains,
|
|
// with a contract on chain A
|
|
// then the contract can emulate the ibc transfer module in the contract to send an ibc packet
|
|
// which is received on chain B via ibc transfer module
|
|
|
|
myContract := &sendEmulatedIBCTransferContract{t: t}
|
|
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContract)),
|
|
}
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
|
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
myContractAddr := chainA.SeedNewContractInstance()
|
|
myContract.contractAddr = myContractAddr.String()
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainA.ContractInfo(myContractAddr).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: ibctransfertypes.PortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
|
|
// when contract is triggered to send the ibc package to chain B
|
|
timeout := uint64(chainB.LatestCommittedHeader.Header.Time.Add(time.Hour).UnixNano()) // enough time to not timeout
|
|
receiverAddress := chainB.SenderAccount.GetAddress()
|
|
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))
|
|
|
|
// start transfer from chainA to chainB
|
|
startMsg := &types.MsgExecuteContract{
|
|
Sender: chainA.SenderAccount.GetAddress().String(),
|
|
Contract: myContractAddr.String(),
|
|
Msg: startTransfer{
|
|
ChannelID: path.EndpointA.ChannelID,
|
|
CoinsToSend: coinToSendToB,
|
|
ReceiverAddr: receiverAddress.String(),
|
|
ContractIBCPort: chainA.ContractInfo(myContractAddr).IBCPortID,
|
|
Timeout: timeout,
|
|
}.GetBytes(),
|
|
Funds: sdk.NewCoins(coinToSendToB),
|
|
}
|
|
_, err := chainA.SendMsgs(startMsg)
|
|
require.NoError(t, err)
|
|
|
|
// then
|
|
require.Equal(t, 1, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, 0, len(*chainB.PendingSendPackets))
|
|
|
|
// and when relay to chain B and handle Ack on chain A
|
|
err = wasmibctesting.RelayAndAckPendingPackets(path)
|
|
require.NoError(t, err)
|
|
|
|
// then
|
|
require.Equal(t, 0, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, 0, len(*chainB.PendingSendPackets))
|
|
|
|
// and dest chain balance contains voucher
|
|
expBalance := GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinToSendToB.Denom, coinToSendToB.Amount)
|
|
gotBalance := chainB.Balance(chainB.SenderAccount.GetAddress(), expBalance.Denom)
|
|
assert.Equal(t, expBalance, gotBalance, "got total balance: %s", chainB.AllBalances(chainB.SenderAccount.GetAddress()))
|
|
}
|
|
|
|
func TestContractCanEmulateIBCTransferMessageWithTimeout(t *testing.T) {
|
|
// scenario: given two chains,
|
|
// with a contract on chain A
|
|
// then the contract can emulate the ibc transfer module in the contract to send an ibc packet
|
|
// which is not received on chain B and times out
|
|
|
|
myContract := &sendEmulatedIBCTransferContract{t: t}
|
|
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContract)),
|
|
}
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
|
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
myContractAddr := chainA.SeedNewContractInstance()
|
|
myContract.contractAddr = myContractAddr.String()
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainA.ContractInfo(myContractAddr).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: ibctransfertypes.PortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
coordinator.UpdateTime()
|
|
|
|
// when contract is triggered to send the ibc package to chain B
|
|
timeout := uint64(chainB.LatestCommittedHeader.Header.Time.Add(time.Nanosecond).UnixNano()) // will timeout
|
|
receiverAddress := chainB.SenderAccount.GetAddress()
|
|
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))
|
|
initialContractBalance := chainA.Balance(myContractAddr, sdk.DefaultBondDenom)
|
|
initialSenderBalance := chainA.Balance(chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom)
|
|
|
|
// custom payload data to be transferred into a proper ICS20 ibc packet
|
|
startMsg := &types.MsgExecuteContract{
|
|
Sender: chainA.SenderAccount.GetAddress().String(),
|
|
Contract: myContractAddr.String(),
|
|
Msg: startTransfer{
|
|
ChannelID: path.EndpointA.ChannelID,
|
|
CoinsToSend: coinToSendToB,
|
|
ReceiverAddr: receiverAddress.String(),
|
|
ContractIBCPort: chainA.ContractInfo(myContractAddr).IBCPortID,
|
|
Timeout: timeout,
|
|
}.GetBytes(),
|
|
Funds: sdk.NewCoins(coinToSendToB),
|
|
}
|
|
_, err := chainA.SendMsgs(startMsg)
|
|
require.NoError(t, err)
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
// then
|
|
newContractBalance := chainA.Balance(myContractAddr, sdk.DefaultBondDenom)
|
|
assert.Equal(t, initialContractBalance.Add(coinToSendToB), newContractBalance) // hold in escrow
|
|
|
|
// when timeout packet send (by the relayer)
|
|
err = wasmibctesting.TimeoutPendingPackets(coordinator, path)
|
|
require.NoError(t, err)
|
|
coordinator.CommitBlock(chainA.TestChain)
|
|
|
|
// then
|
|
require.Equal(t, 0, len(*chainA.PendingSendPackets))
|
|
require.Equal(t, 0, len(*chainB.PendingSendPackets))
|
|
|
|
// and then verify account balances restored
|
|
newContractBalance = chainA.Balance(myContractAddr, sdk.DefaultBondDenom)
|
|
assert.Equal(t, initialContractBalance.String(), newContractBalance.String())
|
|
newSenderBalance := chainA.Balance(chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom)
|
|
assert.Equal(t, initialSenderBalance.String(), newSenderBalance.String())
|
|
}
|
|
|
|
func TestContractEmulateIBCTransferMessageOnDiffContractIBCChannel(t *testing.T) {
|
|
// scenario: given two chains, A and B
|
|
// with 2 contract A1 and A2 on chain A
|
|
// then the contract A2 try to send an ibc packet via IBC Channel that create by A1 and B
|
|
myContractA1 := &sendEmulatedIBCTransferContract{}
|
|
myContractA2 := &sendEmulatedIBCTransferContract{}
|
|
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractA1),
|
|
),
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractA2),
|
|
),
|
|
}
|
|
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts)
|
|
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
myContractAddr1 := chainA.SeedNewContractInstance()
|
|
myContractA1.contractAddr = myContractAddr1.String()
|
|
myContractAddr2 := chainA.SeedNewContractInstance()
|
|
myContractA2.contractAddr = myContractAddr2.String()
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainA.ContractInfo(myContractAddr1).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: ibctransfertypes.PortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
|
|
// when contract is triggered to send the ibc package to chain B
|
|
timeout := uint64(chainB.LatestCommittedHeader.Header.Time.Add(time.Hour).UnixNano()) // enough time to not timeout
|
|
receiverAddress := chainB.SenderAccount.GetAddress()
|
|
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))
|
|
|
|
// start transfer from chainA - A2 to chainB via IBC channel
|
|
startMsg := &types.MsgExecuteContract{
|
|
Sender: chainA.SenderAccount.GetAddress().String(),
|
|
Contract: myContractAddr2.String(),
|
|
Msg: startTransfer{
|
|
ChannelID: path.EndpointA.ChannelID,
|
|
CoinsToSend: coinToSendToB,
|
|
ReceiverAddr: receiverAddress.String(),
|
|
Timeout: timeout,
|
|
}.GetBytes(),
|
|
Funds: sdk.NewCoins(coinToSendToB),
|
|
}
|
|
_, err := chainA.SendMsgs(startMsg)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestContractHandlesChannelClose(t *testing.T) {
|
|
// scenario: a contract is the sending side of an ics20 transfer but the packet was not received
|
|
// on the destination chain within the timeout boundaries
|
|
myContractA := &captureCloseContract{}
|
|
myContractB := &captureCloseContract{}
|
|
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractA)),
|
|
}
|
|
chainBOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractB)),
|
|
}
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts, chainBOpts)
|
|
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
myContractAddrA := chainA.SeedNewContractInstance()
|
|
_ = chainB.SeedNewContractInstance() // skip one instance
|
|
myContractAddrB := chainB.SeedNewContractInstance()
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainA.ContractInfo(myContractAddrA).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainB.ContractInfo(myContractAddrB).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
wasmibctesting.CloseChannel(coordinator, &path.Path)
|
|
assert.True(t, myContractB.closeCalled)
|
|
}
|
|
|
|
func TestContractHandlesChannelCloseNotOwned(t *testing.T) {
|
|
// scenario: given two chains,
|
|
// with a contract A1, A2 on chain A, contract B on chain B
|
|
// contract A2 try to close ibc channel that create between A1 and B
|
|
|
|
myContractA1 := &closeChannelContract{}
|
|
myContractA2 := &closeChannelContract{}
|
|
myContractB := &closeChannelContract{}
|
|
|
|
var (
|
|
chainAOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractA1)),
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractA2)),
|
|
}
|
|
chainBOpts = []wasmkeeper.Option{
|
|
wasmkeeper.WithWasmEngine(
|
|
wasmtesting.NewIBCContractMockWasmEngine(myContractB)),
|
|
}
|
|
coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts, chainBOpts)
|
|
|
|
chainA = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(1)))
|
|
chainB = wasmibctesting.NewWasmTestChain(coordinator.GetChain(ibctesting.GetChainID(2)))
|
|
)
|
|
|
|
coordinator.CommitBlock(chainA.TestChain, chainB.TestChain)
|
|
myContractAddrA1 := chainA.SeedNewContractInstance()
|
|
myContractAddrA2 := chainA.SeedNewContractInstance()
|
|
_ = chainB.SeedNewContractInstance() // skip one instance
|
|
_ = chainB.SeedNewContractInstance() // skip one instance
|
|
myContractAddrB := chainB.SeedNewContractInstance()
|
|
|
|
path := wasmibctesting.NewWasmPath(chainA, chainB)
|
|
path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainA.ContractInfo(myContractAddrA1).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{
|
|
PortID: chainB.ContractInfo(myContractAddrB).IBCPortID,
|
|
Version: ibctransfertypes.V1,
|
|
Order: channeltypes.UNORDERED,
|
|
}
|
|
coordinator.SetupConnections(&path.Path)
|
|
coordinator.CreateChannels(&path.Path)
|
|
|
|
closeIBCChannelMsg := &types.MsgExecuteContract{
|
|
Sender: chainA.SenderAccount.GetAddress().String(),
|
|
Contract: myContractAddrA2.String(),
|
|
Msg: closeIBCChannel{
|
|
ChannelID: path.EndpointA.ChannelID,
|
|
}.GetBytes(),
|
|
Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))),
|
|
}
|
|
|
|
_, err := chainA.SendMsgs(closeIBCChannelMsg)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
var _ wasmtesting.IBCContractCallbacks = &captureCloseContract{}
|
|
|
|
// contract that sets a flag on IBC channel close only.
|
|
type captureCloseContract struct {
|
|
contractStub
|
|
closeCalled bool
|
|
}
|
|
|
|
func (c *captureCloseContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
c.closeCalled = true
|
|
return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 1, nil
|
|
}
|
|
|
|
var _ wasmtesting.IBCContractCallbacks = &sendViaIBCTransferContract{}
|
|
|
|
// contract that initiates an ics-20 transfer on execute via sdk message
|
|
type sendViaIBCTransferContract struct {
|
|
contractStub
|
|
t *testing.T
|
|
}
|
|
|
|
func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
|
|
var in startTransfer
|
|
if err := json.Unmarshal(executeMsg, &in); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
ibcMsg := &wasmvmtypes.IBCMsg{
|
|
Transfer: &wasmvmtypes.TransferMsg{
|
|
ToAddress: in.ReceiverAddr,
|
|
Amount: wasmvmtypes.NewCoin(in.CoinsToSend.Amount.Uint64(), in.CoinsToSend.Denom),
|
|
ChannelID: in.ChannelID,
|
|
Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{
|
|
Revision: 1,
|
|
Height: 110,
|
|
}},
|
|
},
|
|
}
|
|
|
|
return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil
|
|
}
|
|
|
|
var _ wasmtesting.IBCContractCallbacks = &sendEmulatedIBCTransferContract{}
|
|
|
|
// contract that interacts as an ics20 sending side via IBC packets
|
|
// It can also handle the timeout.
|
|
type sendEmulatedIBCTransferContract struct {
|
|
contractStub
|
|
t *testing.T
|
|
contractAddr string
|
|
}
|
|
|
|
func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
|
|
var in startTransfer
|
|
if err := json.Unmarshal(executeMsg, &in); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
require.Len(s.t, info.Funds, 1)
|
|
require.Equal(s.t, in.CoinsToSend.Amount.String(), info.Funds[0].Amount)
|
|
require.Equal(s.t, in.CoinsToSend.Denom, info.Funds[0].Denom)
|
|
dataPacket := ibctransfertypes.NewFungibleTokenPacketData(
|
|
in.CoinsToSend.Denom, in.CoinsToSend.Amount.String(), info.Sender, in.ReceiverAddr, "memo",
|
|
)
|
|
if err := dataPacket.ValidateBasic(); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
ibcMsg := &wasmvmtypes.IBCMsg{
|
|
SendPacket: &wasmvmtypes.SendPacketMsg{
|
|
ChannelID: in.ChannelID,
|
|
Data: dataPacket.GetBytes(),
|
|
Timeout: wasmvmtypes.IBCTimeout{Timestamp: in.Timeout},
|
|
},
|
|
}
|
|
return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil
|
|
}
|
|
|
|
func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
packet := msg.Packet
|
|
|
|
var data ibctransfertypes.FungibleTokenPacketData
|
|
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(packet.Data, &data); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
if err := data.ValidateBasic(); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
amount, _ := sdkmath.NewIntFromString(data.Amount)
|
|
|
|
returnTokens := &wasmvmtypes.BankMsg{
|
|
Send: &wasmvmtypes.SendMsg{
|
|
ToAddress: data.Sender,
|
|
Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{wasmvmtypes.NewCoin(amount.Uint64(), data.Denom)},
|
|
},
|
|
}
|
|
|
|
return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: returnTokens}}}}}, 0, nil
|
|
}
|
|
|
|
var _ wasmtesting.IBCContractCallbacks = &closeChannelContract{}
|
|
|
|
type closeChannelContract struct {
|
|
contractStub
|
|
}
|
|
|
|
func (c *closeChannelContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 1, nil
|
|
}
|
|
|
|
func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) {
|
|
var in closeIBCChannel
|
|
if err := json.Unmarshal(executeMsg, &in); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
ibcMsg := &wasmvmtypes.IBCMsg{
|
|
CloseChannel: &wasmvmtypes.CloseChannelMsg{
|
|
ChannelID: in.ChannelID,
|
|
},
|
|
}
|
|
|
|
return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil
|
|
}
|
|
|
|
type closeIBCChannel struct {
|
|
ChannelID string
|
|
}
|
|
|
|
func (g closeIBCChannel) GetBytes() types.RawContractMessage {
|
|
b, err := json.Marshal(g)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// custom contract execute payload
|
|
type startTransfer struct {
|
|
ChannelID string
|
|
CoinsToSend sdk.Coin
|
|
ReceiverAddr string
|
|
ContractIBCPort string
|
|
Timeout uint64
|
|
}
|
|
|
|
func (g startTransfer) GetBytes() types.RawContractMessage {
|
|
b, err := json.Marshal(g)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
var _ wasmtesting.IBCContractCallbacks = &ackReceiverContract{}
|
|
|
|
// contract that acts as the receiving side for an ics-20 transfer.
|
|
type ackReceiverContract struct {
|
|
contractStub
|
|
t *testing.T
|
|
chain *wasmibctesting.WasmTestChain
|
|
}
|
|
|
|
func (c *ackReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) {
|
|
packet := msg.Packet
|
|
|
|
var src ibctransfertypes.FungibleTokenPacketData
|
|
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(packet.Data, &src); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
require.NoError(c.t, src.ValidateBasic())
|
|
|
|
srcV2 := ibctransfertypes.NewInternalTransferRepresentation(ibctransfertypes.Token{Denom: ibctransfertypes.NewDenom(src.Denom), Amount: src.Amount}, src.Sender, src.Receiver, src.Memo)
|
|
|
|
// call original ibctransfer keeper to not copy all code into this
|
|
ibcPacket := toIBCPacket(packet)
|
|
ctx := c.chain.GetContext() // HACK: please note that this is not reverted after checkTX
|
|
err := c.chain.GetWasmApp().TransferKeeper.OnRecvPacket(ctx, srcV2, ibcPacket.SourcePort, ibcPacket.SourceChannel, ibcPacket.DestinationPort, ibcPacket.DestinationChannel)
|
|
if err != nil {
|
|
return nil, 0, errorsmod.Wrap(err, "within our smart contract")
|
|
}
|
|
|
|
var log []wasmvmtypes.EventAttribute // note: all events are under `wasm` event type
|
|
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}).Acknowledgement()
|
|
return &wasmvmtypes.IBCReceiveResult{Ok: &wasmvmtypes.IBCReceiveResponse{Acknowledgement: ack, Attributes: log}}, 0, nil
|
|
}
|
|
|
|
func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
var data ibctransfertypes.FungibleTokenPacketData
|
|
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(msg.OriginalPacket.Data, &data); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
dataV2 := ibctransfertypes.NewInternalTransferRepresentation(ibctransfertypes.Token{Denom: ibctransfertypes.NewDenom(data.Denom), Amount: data.Amount}, data.Sender, data.Receiver, data.Memo)
|
|
// call original ibctransfer keeper to not copy all code into this
|
|
|
|
var ack channeltypes.Acknowledgement
|
|
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(msg.Acknowledgement.Data, &ack); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
// call original ibctransfer keeper to not copy all code into this
|
|
ctx := c.chain.GetContext() // HACK: please note that this is not reverted after checkTX
|
|
ibcPacket := toIBCPacket(msg.OriginalPacket)
|
|
err := c.chain.GetWasmApp().TransferKeeper.OnAcknowledgementPacket(ctx, ibcPacket.SourcePort, ibcPacket.SourceChannel, dataV2, ack)
|
|
if err != nil {
|
|
return nil, 0, errorsmod.Wrap(err, "within our smart contract")
|
|
}
|
|
|
|
return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil
|
|
}
|
|
|
|
// contract that acts as the receiving side for an ics-20 transfer and always returns a nack.
|
|
type nackReceiverContract struct {
|
|
contractStub
|
|
t *testing.T
|
|
}
|
|
|
|
func (c *nackReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) {
|
|
packet := msg.Packet
|
|
|
|
var src ibctransfertypes.FungibleTokenPacketData
|
|
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(packet.Data, &src); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
require.NoError(c.t, src.ValidateBasic())
|
|
return &wasmvmtypes.IBCReceiveResult{Err: "nack-testing"}, 0, nil
|
|
}
|
|
|
|
// contract that acts as the receiving side for an ics-20 transfer and always returns an error.
|
|
type errorReceiverContract struct {
|
|
contractStub
|
|
t *testing.T
|
|
}
|
|
|
|
func (c *errorReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) {
|
|
packet := msg.Packet
|
|
|
|
var src ibctransfertypes.FungibleTokenPacketData
|
|
if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(packet.Data, &src); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
require.NoError(c.t, src.ValidateBasic())
|
|
return nil, 0, errors.New("error-testing")
|
|
}
|
|
|
|
// simple helper struct that implements connection setup methods.
|
|
type contractStub struct{}
|
|
|
|
func (s *contractStub) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) {
|
|
return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil
|
|
}
|
|
|
|
func (s *contractStub) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelConnectMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil
|
|
}
|
|
|
|
func (s *contractStub) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (s *contractStub) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketReceiveMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (s *contractStub) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil
|
|
}
|
|
|
|
func (s *contractStub) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) {
|
|
panic("implement me")
|
|
}
|
|
|
|
func toIBCPacket(p wasmvmtypes.IBCPacket) channeltypes.Packet {
|
|
var height clienttypes.Height
|
|
if p.Timeout.Block != nil {
|
|
height = clienttypes.NewHeight(p.Timeout.Block.Revision, p.Timeout.Block.Height)
|
|
}
|
|
return channeltypes.Packet{
|
|
Sequence: p.Sequence,
|
|
SourcePort: p.Src.PortID,
|
|
SourceChannel: p.Src.ChannelID,
|
|
DestinationPort: p.Dest.PortID,
|
|
DestinationChannel: p.Dest.ChannelID,
|
|
Data: p.Data,
|
|
TimeoutHeight: height,
|
|
TimeoutTimestamp: p.Timeout.Timestamp,
|
|
}
|
|
}
|