mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 10:17:28 +00:00 
			
		
		
		
	feat: e2e test eip712 signing & erc20 interactions (#1535)
* add helpers & tests for erc20 eth_call query & transfer * make encoding config public * add evm client & raw evm signer to account * test eip712 signing and broadcast * update for cosmos v46 * update kvtool * temporarily disable ibc tests & skip shutdown * disable all but eip712 test and massively simplify * add EIP712 tx builder & setup basic MsgSend test * reenable all tests * add eip712 test that deposits erc20 into earn * update kvtool to master branch
This commit is contained in:
		
							parent
							
								
									91e7933a55
								
							
						
					
					
						commit
						3366b3b3e3
					
				@ -1,4 +1,5 @@
 | 
				
			|||||||
# E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC is for a funded account used to intialize all new testing accounts.
 | 
					# E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC is for a funded account used to intialize all new testing accounts.
 | 
				
			||||||
 | 
					# Should be funded with KAVA and have an ERC20 balance
 | 
				
			||||||
E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC='tent fitness boat among census primary pipe nose dream glance cave turtle electric fabric jacket shaft easy myself genuine this sibling pulse word unfold'
 | 
					E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC='tent fitness boat among census primary pipe nose dream glance cave turtle electric fabric jacket shaft easy myself genuine this sibling pulse word unfold'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# E2E_KVTOOL_KAVA_CONFIG_TEMPLATE is the kvtool template used to start the chain. See the `kava.configTemplate` flag in kvtool.
 | 
					# E2E_KVTOOL_KAVA_CONFIG_TEMPLATE is the kvtool template used to start the chain. See the `kava.configTemplate` flag in kvtool.
 | 
				
			||||||
@ -22,3 +23,7 @@ E2E_KAVA_UPGRADE_NAME=
 | 
				
			|||||||
E2E_KAVA_UPGRADE_HEIGHT=
 | 
					E2E_KAVA_UPGRADE_HEIGHT=
 | 
				
			||||||
# E2E_KAVA_UPGRADE_BASE_IMAGE_TAG is the tag of the docker image the chain should upgrade from.
 | 
					# E2E_KAVA_UPGRADE_BASE_IMAGE_TAG is the tag of the docker image the chain should upgrade from.
 | 
				
			||||||
E2E_KAVA_UPGRADE_BASE_IMAGE_TAG=
 | 
					E2E_KAVA_UPGRADE_BASE_IMAGE_TAG=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# E2E_KAVA_ERC20_ADDRESS is the address of a pre-deployed ERC20 token.
 | 
				
			||||||
 | 
					# The E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC account should have a balance.
 | 
				
			||||||
 | 
					E2E_KAVA_ERC20_ADDRESS=0xeA7100edA2f805356291B0E55DaD448599a72C6d
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,18 @@
 | 
				
			|||||||
package e2e_test
 | 
					package e2e_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sdkerrors "cosmossdk.io/errors"
 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						txtypes "github.com/cosmos/cosmos-sdk/types/tx"
 | 
				
			||||||
 | 
						banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/app"
 | 
				
			||||||
 | 
						earntypes "github.com/kava-labs/kava/x/earn/types"
 | 
				
			||||||
 | 
						evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/kava-labs/kava/tests/e2e/contracts/greeter"
 | 
						"github.com/kava-labs/kava/tests/e2e/contracts/greeter"
 | 
				
			||||||
	"github.com/kava-labs/kava/tests/util"
 | 
						"github.com/kava-labs/kava/tests/util"
 | 
				
			||||||
@ -35,3 +44,132 @@ func (suite *IntegrationTestSuite) TestEthCallToGreeterContract() {
 | 
				
			|||||||
	suite.Equal("what's up!", beforeGreeting)
 | 
						suite.Equal("what's up!", beforeGreeting)
 | 
				
			||||||
	suite.Equal(updatedGreeting, afterGreeting)
 | 
						suite.Equal(updatedGreeting, afterGreeting)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *IntegrationTestSuite) TestEthCallToErc20() {
 | 
				
			||||||
 | 
						randoReceiver := util.SdkToEvmAddress(app.RandomAddress())
 | 
				
			||||||
 | 
						amount := big.NewInt(1e6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// make unauthenticated eth_call query to check balance
 | 
				
			||||||
 | 
						beforeBalance := suite.GetErc20Balance(randoReceiver)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// make authenticate eth_call to transfer tokens
 | 
				
			||||||
 | 
						res := suite.FundKavaErc20Balance(randoReceiver, amount)
 | 
				
			||||||
 | 
						suite.NoError(res.Err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// make another unauthenticated eth_call query to check new balance
 | 
				
			||||||
 | 
						afterBalance := suite.GetErc20Balance(randoReceiver)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.BigIntsEqual(big.NewInt(0), beforeBalance, "expected before balance to be zero")
 | 
				
			||||||
 | 
						suite.BigIntsEqual(amount, afterBalance, "unexpected post-transfer balance")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *IntegrationTestSuite) TestEip712BasicMessageAuthorization() {
 | 
				
			||||||
 | 
						// create new funded account
 | 
				
			||||||
 | 
						sender := suite.Kava.NewFundedAccount("eip712-msgSend", sdk.NewCoins(ukava(10e6)))
 | 
				
			||||||
 | 
						receiver := app.RandomAddress()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// setup message for sending 1KAVA to random receiver
 | 
				
			||||||
 | 
						msgs := []sdk.Msg{
 | 
				
			||||||
 | 
							banktypes.NewMsgSend(sender.SdkAddress, receiver, sdk.NewCoins(ukava(1e6))),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create tx
 | 
				
			||||||
 | 
						tx := suite.NewEip712TxBuilder(
 | 
				
			||||||
 | 
							sender,
 | 
				
			||||||
 | 
							suite.Kava,
 | 
				
			||||||
 | 
							1e6,
 | 
				
			||||||
 | 
							sdk.NewCoins(ukava(1e4)),
 | 
				
			||||||
 | 
							msgs,
 | 
				
			||||||
 | 
							"this is a memo",
 | 
				
			||||||
 | 
						).GetTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txBytes, err := suite.Kava.EncodingConfig.TxConfig.TxEncoder()(tx)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broadcast tx
 | 
				
			||||||
 | 
						res, err := suite.Kava.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
 | 
				
			||||||
 | 
							TxBytes: txBytes,
 | 
				
			||||||
 | 
							Mode:    txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 6*time.Second)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// check that the message was processed & the kava is transferred.
 | 
				
			||||||
 | 
						balRes, err := suite.Kava.Bank.Balance(context.Background(), &banktypes.QueryBalanceRequest{
 | 
				
			||||||
 | 
							Address: receiver.String(),
 | 
				
			||||||
 | 
							Denom:   "ukava",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewInt(1e6), balRes.Balance.Amount)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Note that this test works because the deployed erc20 is configured in evmutil & earn params.
 | 
				
			||||||
 | 
					func (suite *IntegrationTestSuite) TestEip712ConvertToCoinAndDepositToEarn() {
 | 
				
			||||||
 | 
						amount := sdk.NewInt(10e6) // 10 USDC
 | 
				
			||||||
 | 
						sdkDenom := "erc20/multichain/usdc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create new funded account
 | 
				
			||||||
 | 
						depositor := suite.Kava.NewFundedAccount("eip712-earn-depositor", sdk.NewCoins(ukava(1e6)))
 | 
				
			||||||
 | 
						// give them erc20 balance to deposit
 | 
				
			||||||
 | 
						fundRes := suite.FundKavaErc20Balance(depositor.EvmAddress, amount.BigInt())
 | 
				
			||||||
 | 
						suite.NoError(fundRes.Err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// setup messages for convert to coin & deposit into earn
 | 
				
			||||||
 | 
						convertMsg := evmutiltypes.NewMsgConvertERC20ToCoin(
 | 
				
			||||||
 | 
							evmutiltypes.NewInternalEVMAddress(depositor.EvmAddress),
 | 
				
			||||||
 | 
							depositor.SdkAddress,
 | 
				
			||||||
 | 
							evmutiltypes.NewInternalEVMAddress(suite.DeployedErc20Address),
 | 
				
			||||||
 | 
							amount,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						depositMsg := earntypes.NewMsgDeposit(
 | 
				
			||||||
 | 
							depositor.SdkAddress.String(),
 | 
				
			||||||
 | 
							sdk.NewCoin(sdkDenom, amount),
 | 
				
			||||||
 | 
							earntypes.STRATEGY_TYPE_SAVINGS,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						msgs := []sdk.Msg{
 | 
				
			||||||
 | 
							// convert to coin
 | 
				
			||||||
 | 
							&convertMsg,
 | 
				
			||||||
 | 
							// deposit into earn
 | 
				
			||||||
 | 
							depositMsg,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create tx
 | 
				
			||||||
 | 
						tx := suite.NewEip712TxBuilder(
 | 
				
			||||||
 | 
							depositor,
 | 
				
			||||||
 | 
							suite.Kava,
 | 
				
			||||||
 | 
							1e6,
 | 
				
			||||||
 | 
							sdk.NewCoins(ukava(1e4)),
 | 
				
			||||||
 | 
							msgs,
 | 
				
			||||||
 | 
							"depositing my USDC into Earn!",
 | 
				
			||||||
 | 
						).GetTx()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txBytes, err := suite.Kava.EncodingConfig.TxConfig.TxEncoder()(tx)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// broadcast tx
 | 
				
			||||||
 | 
						res, err := suite.Kava.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
 | 
				
			||||||
 | 
							TxBytes: txBytes,
 | 
				
			||||||
 | 
							Mode:    txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 6*time.Second)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// check that depositor no longer has erc20 balance
 | 
				
			||||||
 | 
						balance := suite.GetErc20Balance(depositor.EvmAddress)
 | 
				
			||||||
 | 
						suite.BigIntsEqual(big.NewInt(0), balance, "expected no erc20 balance")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// check that account has an earn deposit position
 | 
				
			||||||
 | 
						earnRes, err := suite.Kava.Earn.Deposits(context.Background(), &earntypes.QueryDepositsRequest{
 | 
				
			||||||
 | 
							Depositor: depositor.SdkAddress.String(),
 | 
				
			||||||
 | 
							Denom:     sdkDenom,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						suite.Len(earnRes.Deposits, 1)
 | 
				
			||||||
 | 
						suite.Equal(sdk.NewDecFromInt(amount), earnRes.Deposits[0].Shares.AmountOf(sdkDenom))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1 @@
 | 
				
			|||||||
Subproject commit 6022e137686e6ab648174b3487c3ee82ec7056ae
 | 
					Subproject commit 9111087667b4ec136a4dd684762e41515a240a0f
 | 
				
			||||||
@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	sdkmath "cosmossdk.io/math"
 | 
						sdkmath "cosmossdk.io/math"
 | 
				
			||||||
	"github.com/cosmos/cosmos-sdk/crypto/hd"
 | 
						"github.com/cosmos/cosmos-sdk/crypto/hd"
 | 
				
			||||||
 | 
						"github.com/cosmos/cosmos-sdk/crypto/types"
 | 
				
			||||||
	sdk "github.com/cosmos/cosmos-sdk/types"
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
 | 
						banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
 | 
				
			||||||
	"github.com/cosmos/go-bip39"
 | 
						"github.com/cosmos/go-bip39"
 | 
				
			||||||
@ -17,6 +18,7 @@ import (
 | 
				
			|||||||
	ethtypes "github.com/ethereum/go-ethereum/core/types"
 | 
						ethtypes "github.com/ethereum/go-ethereum/core/types"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/crypto"
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
	"github.com/evmos/ethermint/crypto/ethsecp256k1"
 | 
						"github.com/evmos/ethermint/crypto/ethsecp256k1"
 | 
				
			||||||
 | 
						emtests "github.com/evmos/ethermint/tests"
 | 
				
			||||||
	emtypes "github.com/evmos/ethermint/types"
 | 
						emtypes "github.com/evmos/ethermint/types"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -28,6 +30,7 @@ type SigningAccount struct {
 | 
				
			|||||||
	name     string
 | 
						name     string
 | 
				
			||||||
	mnemonic string
 | 
						mnemonic string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evmPrivKey *ethsecp256k1.PrivKey
 | 
				
			||||||
	evmSigner  *util.EvmSigner
 | 
						evmSigner  *util.EvmSigner
 | 
				
			||||||
	evmReqChan chan<- util.EvmTxRequest
 | 
						evmReqChan chan<- util.EvmTxRequest
 | 
				
			||||||
	evmResChan <-chan util.EvmTxResponse
 | 
						evmResChan <-chan util.EvmTxResponse
 | 
				
			||||||
@ -66,7 +69,7 @@ func (chain *Chain) AddNewSigningAccount(name string, hdPath *hd.BIP44Params, ch
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	kavaSigner := util.NewKavaSigner(
 | 
						kavaSigner := util.NewKavaSigner(
 | 
				
			||||||
		chainId,
 | 
							chainId,
 | 
				
			||||||
		chain.encodingConfig,
 | 
							chain.EncodingConfig,
 | 
				
			||||||
		chain.Auth,
 | 
							chain.Auth,
 | 
				
			||||||
		chain.Tx,
 | 
							chain.Tx,
 | 
				
			||||||
		privKey,
 | 
							privKey,
 | 
				
			||||||
@ -100,6 +103,7 @@ func (chain *Chain) AddNewSigningAccount(name string, hdPath *hd.BIP44Params, ch
 | 
				
			|||||||
		mnemonic: mnemonic,
 | 
							mnemonic: mnemonic,
 | 
				
			||||||
		l:        logger,
 | 
							l:        logger,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							evmPrivKey: privKey,
 | 
				
			||||||
		evmSigner:  evmSigner,
 | 
							evmSigner:  evmSigner,
 | 
				
			||||||
		evmReqChan: evmReqChan,
 | 
							evmReqChan: evmReqChan,
 | 
				
			||||||
		evmResChan: evmResChan,
 | 
							evmResChan: evmResChan,
 | 
				
			||||||
@ -168,6 +172,11 @@ func (a *SigningAccount) SignAndBroadcastEvmTx(req util.EvmTxRequest) EvmTxRespo
 | 
				
			|||||||
	return response
 | 
						return response
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (a *SigningAccount) SignRawEvmData(msg []byte) ([]byte, types.PubKey, error) {
 | 
				
			||||||
 | 
						keyringSigner := emtests.NewSigner(a.evmPrivKey)
 | 
				
			||||||
 | 
						return keyringSigner.SignByAddress(a.SdkAddress, msg)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewFundedAccount creates a SigningAccount for a random account & funds the account from the whale.
 | 
					// NewFundedAccount creates a SigningAccount for a random account & funds the account from the whale.
 | 
				
			||||||
func (chain *Chain) NewFundedAccount(name string, funds sdk.Coins) *SigningAccount {
 | 
					func (chain *Chain) NewFundedAccount(name string, funds sdk.Coins) *SigningAccount {
 | 
				
			||||||
	entropy, err := bip39.NewEntropy(128)
 | 
						entropy, err := bip39.NewEntropy(128)
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
 | 
						banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/common"
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/ethclient"
 | 
						"github.com/ethereum/go-ethereum/ethclient"
 | 
				
			||||||
 | 
						evmtypes "github.com/evmos/ethermint/x/evm/types"
 | 
				
			||||||
	"github.com/stretchr/testify/require"
 | 
						"github.com/stretchr/testify/require"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/kava-labs/kava/app"
 | 
						"github.com/kava-labs/kava/app"
 | 
				
			||||||
@ -25,9 +26,8 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Chain wraps query clients & accounts for a network
 | 
					// Chain wraps query clients & accounts for a network
 | 
				
			||||||
type Chain struct {
 | 
					type Chain struct {
 | 
				
			||||||
	encodingConfig kavaparams.EncodingConfig
 | 
						accounts map[string]*SigningAccount
 | 
				
			||||||
	accounts       map[string]*SigningAccount
 | 
						t        *testing.T
 | 
				
			||||||
	t              *testing.T
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StakingDenom string
 | 
						StakingDenom string
 | 
				
			||||||
	ChainId      string
 | 
						ChainId      string
 | 
				
			||||||
@ -35,10 +35,13 @@ type Chain struct {
 | 
				
			|||||||
	EvmClient     *ethclient.Client
 | 
						EvmClient     *ethclient.Client
 | 
				
			||||||
	ContractAddrs map[string]common.Address
 | 
						ContractAddrs map[string]common.Address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EncodingConfig kavaparams.EncodingConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Auth      authtypes.QueryClient
 | 
						Auth      authtypes.QueryClient
 | 
				
			||||||
	Bank      banktypes.QueryClient
 | 
						Bank      banktypes.QueryClient
 | 
				
			||||||
	Community communitytypes.QueryClient
 | 
						Community communitytypes.QueryClient
 | 
				
			||||||
	Earn      earntypes.QueryClient
 | 
						Earn      earntypes.QueryClient
 | 
				
			||||||
 | 
						Evm       evmtypes.QueryClient
 | 
				
			||||||
	Tm        tmservice.ServiceClient
 | 
						Tm        tmservice.ServiceClient
 | 
				
			||||||
	Tx        txtypes.ServiceClient
 | 
						Tx        txtypes.ServiceClient
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -53,7 +56,7 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
 | 
				
			|||||||
		ChainId:       details.ChainId,
 | 
							ChainId:       details.ChainId,
 | 
				
			||||||
		ContractAddrs: make(map[string]common.Address),
 | 
							ContractAddrs: make(map[string]common.Address),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	chain.encodingConfig = app.MakeEncodingConfig()
 | 
						chain.EncodingConfig = app.MakeEncodingConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	grpcUrl := fmt.Sprintf("http://localhost:%s", details.GrpcPort)
 | 
						grpcUrl := fmt.Sprintf("http://localhost:%s", details.GrpcPort)
 | 
				
			||||||
	grpcConn, err := util.NewGrpcConnection(grpcUrl)
 | 
						grpcConn, err := util.NewGrpcConnection(grpcUrl)
 | 
				
			||||||
@ -71,6 +74,7 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
 | 
				
			|||||||
	chain.Bank = banktypes.NewQueryClient(grpcConn)
 | 
						chain.Bank = banktypes.NewQueryClient(grpcConn)
 | 
				
			||||||
	chain.Community = communitytypes.NewQueryClient(grpcConn)
 | 
						chain.Community = communitytypes.NewQueryClient(grpcConn)
 | 
				
			||||||
	chain.Earn = earntypes.NewQueryClient(grpcConn)
 | 
						chain.Earn = earntypes.NewQueryClient(grpcConn)
 | 
				
			||||||
 | 
						chain.Evm = evmtypes.NewQueryClient(grpcConn)
 | 
				
			||||||
	chain.Tm = tmservice.NewServiceClient(grpcConn)
 | 
						chain.Tm = tmservice.NewServiceClient(grpcConn)
 | 
				
			||||||
	chain.Tx = txtypes.NewServiceClient(grpcConn)
 | 
						chain.Tx = txtypes.NewServiceClient(grpcConn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,9 @@ type SuiteConfig struct {
 | 
				
			|||||||
	// Tag of kava docker image that will be upgraded to the current image before tests are run, if upgrade is enabled.
 | 
						// Tag of kava docker image that will be upgraded to the current image before tests are run, if upgrade is enabled.
 | 
				
			||||||
	KavaUpgradeBaseImageTag string
 | 
						KavaUpgradeBaseImageTag string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The contract address of a deployed ERC-20 token
 | 
				
			||||||
 | 
						KavaErc20Address string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// When true, the chains will remain running after tests complete (pass or fail)
 | 
						// When true, the chains will remain running after tests complete (pass or fail)
 | 
				
			||||||
	SkipShutdown bool
 | 
						SkipShutdown bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -41,6 +44,7 @@ func ParseSuiteConfig() SuiteConfig {
 | 
				
			|||||||
		// new accounts created during tests. it will be available under Accounts["whale"]
 | 
							// new accounts created during tests. it will be available under Accounts["whale"]
 | 
				
			||||||
		FundedAccountMnemonic:   nonemptyStringEnv("E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC"),
 | 
							FundedAccountMnemonic:   nonemptyStringEnv("E2E_KAVA_FUNDED_ACCOUNT_MNEMONIC"),
 | 
				
			||||||
		KavaConfigTemplate:      nonemptyStringEnv("E2E_KVTOOL_KAVA_CONFIG_TEMPLATE"),
 | 
							KavaConfigTemplate:      nonemptyStringEnv("E2E_KVTOOL_KAVA_CONFIG_TEMPLATE"),
 | 
				
			||||||
 | 
							KavaErc20Address:        nonemptyStringEnv("E2E_KAVA_ERC20_ADDRESS"),
 | 
				
			||||||
		IncludeIbcTests:         mustParseBool("E2E_INCLUDE_IBC_TESTS"),
 | 
							IncludeIbcTests:         mustParseBool("E2E_INCLUDE_IBC_TESTS"),
 | 
				
			||||||
		IncludeAutomatedUpgrade: mustParseBool("E2E_INCLUDE_AUTOMATED_UPGRADE"),
 | 
							IncludeAutomatedUpgrade: mustParseBool("E2E_INCLUDE_AUTOMATED_UPGRADE"),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										107
									
								
								tests/e2e/testutil/eip712.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								tests/e2e/testutil/eip712.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					package testutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/cosmos/cosmos-sdk/client"
 | 
				
			||||||
 | 
						codectypes "github.com/cosmos/cosmos-sdk/codec/types"
 | 
				
			||||||
 | 
						sdk "github.com/cosmos/cosmos-sdk/types"
 | 
				
			||||||
 | 
						"github.com/cosmos/cosmos-sdk/types/tx/signing"
 | 
				
			||||||
 | 
						"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
 | 
				
			||||||
 | 
						authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
 | 
				
			||||||
 | 
						authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
 | 
						"github.com/evmos/ethermint/ethereum/eip712"
 | 
				
			||||||
 | 
						emtypes "github.com/evmos/ethermint/types"
 | 
				
			||||||
 | 
						evmtypes "github.com/evmos/ethermint/x/evm/types"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *E2eTestSuite) NewEip712TxBuilder(
 | 
				
			||||||
 | 
						acc *SigningAccount, chain *Chain, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg, memo string,
 | 
				
			||||||
 | 
					) client.TxBuilder {
 | 
				
			||||||
 | 
						// get account details
 | 
				
			||||||
 | 
						var accDetails authtypes.AccountI
 | 
				
			||||||
 | 
						a, err := chain.Auth.Account(context.Background(), &authtypes.QueryAccountRequest{
 | 
				
			||||||
 | 
							Address: acc.SdkAddress.String(),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						err = chain.EncodingConfig.InterfaceRegistry.UnpackAny(a.Account, &accDetails)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get nonce & acc number
 | 
				
			||||||
 | 
						nonce := accDetails.GetSequence()
 | 
				
			||||||
 | 
						accNumber := accDetails.GetAccountNumber()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get chain id
 | 
				
			||||||
 | 
						pc, err := emtypes.ParseChainID(chain.ChainId)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						ethChainId := pc.Uint64()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						evmParams, err := chain.Evm.Params(context.Background(), &evmtypes.QueryParamsRequest{})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fee := legacytx.NewStdFee(gas, gasAmount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// build EIP712 tx
 | 
				
			||||||
 | 
						// -- untyped data
 | 
				
			||||||
 | 
						untypedData := eip712.ConstructUntypedEIP712Data(
 | 
				
			||||||
 | 
							chain.ChainId,
 | 
				
			||||||
 | 
							accNumber,
 | 
				
			||||||
 | 
							nonce,
 | 
				
			||||||
 | 
							0, // no timeout
 | 
				
			||||||
 | 
							fee,
 | 
				
			||||||
 | 
							msgs,
 | 
				
			||||||
 | 
							memo,
 | 
				
			||||||
 | 
							nil,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						// -- typed data
 | 
				
			||||||
 | 
						typedData, err := eip712.WrapTxToTypedData(ethChainId, msgs, untypedData, &eip712.FeeDelegationOptions{
 | 
				
			||||||
 | 
							FeePayer: acc.SdkAddress,
 | 
				
			||||||
 | 
						}, evmParams.Params)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -- raw data hash!
 | 
				
			||||||
 | 
						data, err := eip712.ComputeTypedDataHash(typedData)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// -- sign the hash
 | 
				
			||||||
 | 
						signature, pubKey, err := acc.SignRawEvmData(data)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
						signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// add ExtensionOptionsWeb3Tx extension
 | 
				
			||||||
 | 
						var option *codectypes.Any
 | 
				
			||||||
 | 
						option, err = codectypes.NewAnyWithValue(&emtypes.ExtensionOptionsWeb3Tx{
 | 
				
			||||||
 | 
							FeePayer:         acc.SdkAddress.String(),
 | 
				
			||||||
 | 
							TypedDataChainID: ethChainId,
 | 
				
			||||||
 | 
							FeePayerSig:      signature,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create cosmos sdk tx builder
 | 
				
			||||||
 | 
						txBuilder := chain.EncodingConfig.TxConfig.NewTxBuilder()
 | 
				
			||||||
 | 
						builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
 | 
				
			||||||
 | 
						suite.True(ok)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						builder.SetExtensionOptions(option)
 | 
				
			||||||
 | 
						builder.SetFeeAmount(fee.Amount)
 | 
				
			||||||
 | 
						builder.SetGasLimit(fee.Gas)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sigsV2 := signing.SignatureV2{
 | 
				
			||||||
 | 
							PubKey: pubKey,
 | 
				
			||||||
 | 
							Data: &signing.SingleSignatureData{
 | 
				
			||||||
 | 
								SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Sequence: nonce,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = builder.SetSignatures(sigsV2)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = builder.SetMsgs(msgs...)
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						builder.SetMemo(memo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return builder
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,12 +1,29 @@
 | 
				
			|||||||
package testutil
 | 
					package testutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "github.com/kava-labs/kava/tests/e2e/contracts/greeter"
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
 | 
						ethtypes "github.com/ethereum/go-ethereum/core/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/tests/e2e/contracts/greeter"
 | 
				
			||||||
 | 
						"github.com/kava-labs/kava/tests/util"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// InitKavaEvmData is run after the chain is running, but before the tests are run.
 | 
					// InitKavaEvmData is run after the chain is running, but before the tests are run.
 | 
				
			||||||
// It is used to initialize some EVM state, such as deploying contracts.
 | 
					// It is used to initialize some EVM state, such as deploying contracts.
 | 
				
			||||||
func (suite *E2eTestSuite) InitKavaEvmData() {
 | 
					func (suite *E2eTestSuite) InitKavaEvmData() {
 | 
				
			||||||
	whale := suite.Kava.GetAccount(FundedAccountName)
 | 
						whale := suite.Kava.GetAccount(FundedAccountName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ensure funded account has nonzero erc20 balance
 | 
				
			||||||
 | 
						balance := suite.GetErc20Balance(whale.EvmAddress)
 | 
				
			||||||
 | 
						if balance.Cmp(big.NewInt(0)) != 1 {
 | 
				
			||||||
 | 
							panic(fmt.Sprintf("expected funded account (%s) to have erc20 balance", whale.EvmAddress.Hex()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// deploy an example contract
 | 
						// deploy an example contract
 | 
				
			||||||
	greeterAddr, _, _, err := greeter.DeployGreeter(
 | 
						greeterAddr, _, _, err := greeter.DeployGreeter(
 | 
				
			||||||
		whale.evmSigner.Auth,
 | 
							whale.evmSigner.Auth,
 | 
				
			||||||
@ -16,3 +33,29 @@ func (suite *E2eTestSuite) InitKavaEvmData() {
 | 
				
			|||||||
	suite.NoError(err, "failed to deploy a contract to the EVM")
 | 
						suite.NoError(err, "failed to deploy a contract to the EVM")
 | 
				
			||||||
	suite.Kava.ContractAddrs["greeter"] = greeterAddr
 | 
						suite.Kava.ContractAddrs["greeter"] = greeterAddr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *E2eTestSuite) FundKavaErc20Balance(toAddress common.Address, amount *big.Int) EvmTxResponse {
 | 
				
			||||||
 | 
						// funded account should have erc20 balance
 | 
				
			||||||
 | 
						whale := suite.Kava.GetAccount(FundedAccountName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data := util.BuildErc20TransferCallData(whale.EvmAddress, toAddress, amount)
 | 
				
			||||||
 | 
						nonce, err := suite.Kava.EvmClient.PendingNonceAt(context.Background(), whale.EvmAddress)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req := util.EvmTxRequest{
 | 
				
			||||||
 | 
							Tx:   ethtypes.NewTransaction(nonce, suite.DeployedErc20Address, big.NewInt(0), 1e5, big.NewInt(1e10), data),
 | 
				
			||||||
 | 
							Data: fmt.Sprintf("fund %s with ERC20 balance (%s)", toAddress.Hex(), amount.String()),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return whale.SignAndBroadcastEvmTx(req)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *E2eTestSuite) GetErc20Balance(address common.Address) *big.Int {
 | 
				
			||||||
 | 
						resData, err := suite.Kava.EvmClient.CallContract(context.Background(), ethereum.CallMsg{
 | 
				
			||||||
 | 
							To:   &suite.DeployedErc20Address,
 | 
				
			||||||
 | 
							Data: util.BuildErc20BalanceOfCallData(address),
 | 
				
			||||||
 | 
						}, nil)
 | 
				
			||||||
 | 
						suite.NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return new(big.Int).SetBytes(resData)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,8 +2,10 @@ package testutil
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
	"github.com/stretchr/testify/suite"
 | 
						"github.com/stretchr/testify/suite"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/kava-labs/kava/app"
 | 
						"github.com/kava-labs/kava/app"
 | 
				
			||||||
@ -30,7 +32,8 @@ type E2eTestSuite struct {
 | 
				
			|||||||
	Kava *Chain
 | 
						Kava *Chain
 | 
				
			||||||
	Ibc  *Chain
 | 
						Ibc  *Chain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UpgradeHeight int64
 | 
						UpgradeHeight        int64
 | 
				
			||||||
 | 
						DeployedErc20Address common.Address
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (suite *E2eTestSuite) SetupSuite() {
 | 
					func (suite *E2eTestSuite) SetupSuite() {
 | 
				
			||||||
@ -41,6 +44,7 @@ func (suite *E2eTestSuite) SetupSuite() {
 | 
				
			|||||||
	suiteConfig := ParseSuiteConfig()
 | 
						suiteConfig := ParseSuiteConfig()
 | 
				
			||||||
	suite.config = suiteConfig
 | 
						suite.config = suiteConfig
 | 
				
			||||||
	suite.UpgradeHeight = suiteConfig.KavaUpgradeHeight
 | 
						suite.UpgradeHeight = suiteConfig.KavaUpgradeHeight
 | 
				
			||||||
 | 
						suite.DeployedErc20Address = common.HexToAddress(suiteConfig.KavaErc20Address)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	runnerConfig := runner.Config{
 | 
						runnerConfig := runner.Config{
 | 
				
			||||||
		KavaConfigTemplate: suiteConfig.KavaConfigTemplate,
 | 
							KavaConfigTemplate: suiteConfig.KavaConfigTemplate,
 | 
				
			||||||
@ -105,3 +109,8 @@ func (suite *E2eTestSuite) SkipIfUpgradeDisabled() {
 | 
				
			|||||||
func (suite *E2eTestSuite) KavaHomePath() string {
 | 
					func (suite *E2eTestSuite) KavaHomePath() string {
 | 
				
			||||||
	return filepath.Join("kvtool", "full_configs", "generated", "kava", "initstate", ".kava")
 | 
						return filepath.Join("kvtool", "full_configs", "generated", "kava", "initstate", ".kava")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BigIntsEqual is a helper method for comparing the equality of two big ints
 | 
				
			||||||
 | 
					func (suite *E2eTestSuite) BigIntsEqual(expected *big.Int, actual *big.Int, msg string) {
 | 
				
			||||||
 | 
						suite.Truef(expected.Cmp(actual) == 0, "%s (expected: %s, actual: %s)", msg, expected.String(), actual.String())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										40
									
								
								tests/util/erc20.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/util/erc20.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					package util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
 | 
						"golang.org/x/crypto/sha3"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EvmContractMethodId encodes a method signature to the method id used in eth calldata.
 | 
				
			||||||
 | 
					func EvmContractMethodId(signature string) []byte {
 | 
				
			||||||
 | 
						transferFnSignature := []byte(signature)
 | 
				
			||||||
 | 
						hash := sha3.NewLegacyKeccak256()
 | 
				
			||||||
 | 
						hash.Write(transferFnSignature)
 | 
				
			||||||
 | 
						return hash.Sum(nil)[:4]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func BuildErc20TransferCallData(from common.Address, to common.Address, amount *big.Int) []byte {
 | 
				
			||||||
 | 
						methodId := EvmContractMethodId("transfer(address,uint256)")
 | 
				
			||||||
 | 
						paddedAddress := common.LeftPadBytes(to.Bytes(), 32)
 | 
				
			||||||
 | 
						paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var data []byte
 | 
				
			||||||
 | 
						data = append(data, methodId...)
 | 
				
			||||||
 | 
						data = append(data, paddedAddress...)
 | 
				
			||||||
 | 
						data = append(data, paddedAmount...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func BuildErc20BalanceOfCallData(address common.Address) []byte {
 | 
				
			||||||
 | 
						methodId := EvmContractMethodId("balanceOf(address)")
 | 
				
			||||||
 | 
						paddedAddress := common.LeftPadBytes(address.Bytes(), 32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var data []byte
 | 
				
			||||||
 | 
						data = append(data, methodId...)
 | 
				
			||||||
 | 
						data = append(data, paddedAddress...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,10 +2,13 @@ package util
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/kava-labs/kava/app/params"
 | 
						"github.com/kava-labs/kava/app/params"
 | 
				
			||||||
 | 
						"google.golang.org/grpc/codes"
 | 
				
			||||||
 | 
						grpcstatus "google.golang.org/grpc/status"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	errorsmod "cosmossdk.io/errors"
 | 
						errorsmod "cosmossdk.io/errors"
 | 
				
			||||||
	sdkclient "github.com/cosmos/cosmos-sdk/client"
 | 
						sdkclient "github.com/cosmos/cosmos-sdk/client"
 | 
				
			||||||
@ -19,6 +22,10 @@ import (
 | 
				
			|||||||
	tmmempool "github.com/tendermint/tendermint/mempool"
 | 
						tmmempool "github.com/tendermint/tendermint/mempool"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						ErrSdkBroadcastTimeout = errors.New("timed out waiting for tx to be committed to block")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type KavaMsgRequest struct {
 | 
					type KavaMsgRequest struct {
 | 
				
			||||||
	Msgs      []sdk.Msg
 | 
						Msgs      []sdk.Msg
 | 
				
			||||||
	GasLimit  uint64
 | 
						GasLimit  uint64
 | 
				
			||||||
@ -420,3 +427,35 @@ func Sign(
 | 
				
			|||||||
func GetAccAddress(privKey cryptotypes.PrivKey) sdk.AccAddress {
 | 
					func GetAccAddress(privKey cryptotypes.PrivKey) sdk.AccAddress {
 | 
				
			||||||
	return privKey.PubKey().Address().Bytes()
 | 
						return privKey.PubKey().Address().Bytes()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WaitForSdkTxCommit polls the chain until the tx hash is found or times out.
 | 
				
			||||||
 | 
					// Returns an error immediately if tx hash is empty
 | 
				
			||||||
 | 
					func WaitForSdkTxCommit(txClient txtypes.ServiceClient, txHash string, timeout time.Duration) (*sdk.TxResponse, error) {
 | 
				
			||||||
 | 
						if txHash == "" {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("tx hash is empty")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						var txRes *sdk.TxResponse
 | 
				
			||||||
 | 
						var res *txtypes.GetTxResponse
 | 
				
			||||||
 | 
						outOfTime := time.After(timeout)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case <-outOfTime:
 | 
				
			||||||
 | 
								err = ErrSdkBroadcastTimeout
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								res, err = txClient.GetTx(context.Background(), &txtypes.GetTxRequest{Hash: txHash})
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									status, ok := grpcstatus.FromError(err)
 | 
				
			||||||
 | 
									if ok && status.Code() == codes.NotFound {
 | 
				
			||||||
 | 
										// tx still not committed to a block. retry!
 | 
				
			||||||
 | 
										time.Sleep(100 * time.Millisecond)
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								txRes = res.TxResponse
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return txRes, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user