mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-20 15:05:21 +00:00
test(e2e): lower cost to run on live networks (#1646)
* add cost summary to e2e test suite runs * lower cost of test * refactor initial funding to use new BankSend() * reduce gas used for initial funding * return all sdk funds on shutdown * enable refunds when running against live network * save more cosmos coins! require less total overall * track erc20s on Chain * refactor erc20 funding with new TransferErc20() * return all registered erc20 balance * lower erc20 e2e test values * withdraw earn position & convert back to erc20 * lower gas fees in e2e tests * fix env variable typo * add readme note about how to run on live network * log total spend required for e2e tests
This commit is contained in:
parent
7cff7bec23
commit
5cfa33f638
@ -8,7 +8,7 @@ E2E_RUN_KVTOOL_NETWORKS=false
|
||||
# Configure the endpoints for connecting to the running network here.
|
||||
E2E_KAVA_RPC_URL='http://localhost:26657'
|
||||
E2E_KAVA_GRPC_URL='http://localhost:9090'
|
||||
E2E_KAVA_EMV_RPC_URL='http://localhost:8545'
|
||||
E2E_KAVA_EVM_RPC_URL='http://localhost:8545'
|
||||
|
||||
# E2E_INCLUDE_IBC_TESTS is not currently supported for running tests against a live network.
|
||||
E2E_INCLUDE_IBC_TESTS=false
|
||||
|
@ -2,6 +2,7 @@ package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
@ -16,6 +17,8 @@ import (
|
||||
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
|
||||
)
|
||||
|
||||
const initialCosmosCoinConversionDenomFunds = int64(1e4)
|
||||
|
||||
func setupConvertToCoinTest(
|
||||
suite *IntegrationTestSuite, accountName string,
|
||||
) (denom string, initialFunds sdk.Coins, user *testutil.SigningAccount) {
|
||||
@ -31,8 +34,8 @@ func setupConvertToCoinTest(
|
||||
tokenInfo := params.Params.AllowedCosmosDenoms[0]
|
||||
denom = tokenInfo.CosmosDenom
|
||||
initialFunds = sdk.NewCoins(
|
||||
sdk.NewInt64Coin(suite.Kava.StakingDenom, 1e6), // gas money
|
||||
sdk.NewInt64Coin(denom, 1e6), // conversion-enabled cosmos coin
|
||||
sdk.NewInt64Coin(suite.Kava.StakingDenom, 1e5), // gas money
|
||||
sdk.NewInt64Coin(denom, initialCosmosCoinConversionDenomFunds), // conversion-enabled cosmos coin
|
||||
)
|
||||
|
||||
user = suite.Kava.NewFundedAccount(accountName, initialFunds)
|
||||
@ -40,19 +43,17 @@ func setupConvertToCoinTest(
|
||||
return denom, initialFunds, user
|
||||
}
|
||||
|
||||
// amount must be less than initial funds (1e6)
|
||||
// amount must be less than initial funds (initialCosmosCoinConversionDenomFunds)
|
||||
func (suite *IntegrationTestSuite) setupAccountWithCosmosCoinERC20Balance(
|
||||
accountName string, amount int64,
|
||||
) (user *testutil.SigningAccount, contractAddress *evmutiltypes.InternalEVMAddress, denom string, sdkBalance sdk.Coins) {
|
||||
if amount > 1e6 {
|
||||
panic("test erc20 amount must be less than 1e6")
|
||||
if amount > initialCosmosCoinConversionDenomFunds {
|
||||
panic(fmt.Sprintf("test erc20 amount must be less than %d", initialCosmosCoinConversionDenomFunds))
|
||||
}
|
||||
|
||||
denom, sdkBalance, user = setupConvertToCoinTest(suite, accountName)
|
||||
convertAmount := sdk.NewInt64Coin(denom, amount)
|
||||
|
||||
fee := sdk.NewCoins(ukava(7500))
|
||||
|
||||
// setup user to have erc20 balance
|
||||
msg := evmutiltypes.NewMsgConvertCosmosCoinToERC20(
|
||||
user.SdkAddress.String(),
|
||||
@ -61,8 +62,8 @@ func (suite *IntegrationTestSuite) setupAccountWithCosmosCoinERC20Balance(
|
||||
)
|
||||
tx := util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{&msg},
|
||||
GasLimit: 2e6,
|
||||
FeeAmount: fee,
|
||||
GasLimit: 4e5,
|
||||
FeeAmount: sdk.NewCoins(ukava(400)),
|
||||
Data: "converting sdk coin to erc20",
|
||||
}
|
||||
res := user.SignAndBroadcastKavaTx(tx)
|
||||
@ -87,8 +88,7 @@ func (suite *IntegrationTestSuite) setupAccountWithCosmosCoinERC20Balance(
|
||||
func (suite *IntegrationTestSuite) TestConvertCosmosCoinsToFromERC20() {
|
||||
denom, initialFunds, user := setupConvertToCoinTest(suite, "cosmo-coin-converter")
|
||||
|
||||
fee := sdk.NewCoins(ukava(7500))
|
||||
convertAmount := int64(5e5)
|
||||
convertAmount := int64(5e3)
|
||||
initialModuleBalance := suite.Kava.GetModuleBalances(evmutiltypes.ModuleName).AmountOf(denom)
|
||||
|
||||
///////////////////////////////
|
||||
@ -102,7 +102,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoinsToFromERC20() {
|
||||
tx := util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{&convertToErc20Msg},
|
||||
GasLimit: 2e6,
|
||||
FeeAmount: fee,
|
||||
FeeAmount: sdk.NewCoins(ukava(2000)),
|
||||
Data: "converting sdk coin to erc20",
|
||||
}
|
||||
res := user.SignAndBroadcastKavaTx(tx)
|
||||
@ -144,7 +144,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoinsToFromERC20() {
|
||||
tx = util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{&convertFromErc20Msg},
|
||||
GasLimit: 2e5,
|
||||
FeeAmount: fee,
|
||||
FeeAmount: sdk.NewCoins(ukava(200)),
|
||||
Data: "converting erc20 to cosmos coin",
|
||||
}
|
||||
res = user.SignAndBroadcastKavaTx(tx)
|
||||
@ -168,7 +168,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoinsToFromERC20() {
|
||||
func (suite *IntegrationTestSuite) TestEIP712ConvertCosmosCoinsToFromERC20() {
|
||||
denom, initialFunds, user := setupConvertToCoinTest(suite, "cosmo-coin-converter-eip712")
|
||||
|
||||
convertAmount := int64(5e5)
|
||||
convertAmount := int64(5e3)
|
||||
initialModuleBalance := suite.Kava.GetModuleBalances(evmutiltypes.ModuleName).AmountOf(denom)
|
||||
|
||||
///////////////////////////////
|
||||
@ -237,7 +237,7 @@ func (suite *IntegrationTestSuite) TestEIP712ConvertCosmosCoinsToFromERC20() {
|
||||
user,
|
||||
suite.Kava,
|
||||
2e5,
|
||||
sdk.NewCoins(ukava(1e4)),
|
||||
sdk.NewCoins(ukava(200)),
|
||||
[]sdk.Msg{&convertFromErc20Msg},
|
||||
"",
|
||||
).GetTx()
|
||||
@ -270,7 +270,9 @@ func (suite *IntegrationTestSuite) TestEIP712ConvertCosmosCoinsToFromERC20() {
|
||||
}
|
||||
|
||||
func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ForbiddenERC20Calls() {
|
||||
user, contractAddress, _, _ := suite.setupAccountWithCosmosCoinERC20Balance("cosmo-coin-converter-unhappy", 1e6)
|
||||
// give them erc20 balance so we know that's not preventing these method calls
|
||||
// this test sacrifices the 1 coin by never returning it to the sdk.
|
||||
user, contractAddress, _, _ := suite.setupAccountWithCosmosCoinERC20Balance("cosmo-coin-converter-unhappy", 1)
|
||||
|
||||
suite.Run("users can't mint()", func() {
|
||||
data := util.BuildErc20MintCallData(user.EvmAddress, big.NewInt(1))
|
||||
@ -282,7 +284,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ForbiddenERC20Calls()
|
||||
ðtypes.LegacyTx{
|
||||
Nonce: nonce,
|
||||
GasPrice: minEvmGasPrice,
|
||||
Gas: 1e6,
|
||||
Gas: 1e5,
|
||||
To: &contractAddress.Address,
|
||||
Data: data,
|
||||
},
|
||||
@ -306,7 +308,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ForbiddenERC20Calls()
|
||||
ðtypes.LegacyTx{
|
||||
Nonce: nonce,
|
||||
GasPrice: minEvmGasPrice,
|
||||
Gas: 1e6,
|
||||
Gas: 1e5,
|
||||
To: &contractAddress.Address,
|
||||
Data: data,
|
||||
},
|
||||
@ -324,15 +326,14 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ForbiddenERC20Calls()
|
||||
// - check approval flow of erc20. alice approves bob to move their funds
|
||||
// - check complex conversion flow. bob converts funds they receive on evm back to sdk.Coin
|
||||
func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ERC20Magic() {
|
||||
fee := sdk.NewCoins(ukava(7500))
|
||||
initialAliceAmount := int64(2e5)
|
||||
initialAliceAmount := int64(2e3)
|
||||
alice, contractAddress, denom, _ := suite.setupAccountWithCosmosCoinERC20Balance(
|
||||
"cosmo-coin-converter-complex-alice", initialAliceAmount,
|
||||
)
|
||||
|
||||
gasMoney := sdk.NewCoins(ukava(1e6))
|
||||
gasMoney := sdk.NewCoins(ukava(1e5))
|
||||
bob := suite.Kava.NewFundedAccount("cosmo-coin-converter-complex-bob", gasMoney)
|
||||
amount := big.NewInt(1e5)
|
||||
amount := big.NewInt(1e3) // test assumes this is half of alice's balance.
|
||||
|
||||
// bob can't move alice's funds
|
||||
nonce, err := bob.NextNonce()
|
||||
@ -340,7 +341,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ERC20Magic() {
|
||||
transferFromTxData := ðtypes.LegacyTx{
|
||||
Nonce: nonce,
|
||||
GasPrice: minEvmGasPrice,
|
||||
Gas: 1e6,
|
||||
Gas: 1e5,
|
||||
To: &contractAddress.Address,
|
||||
Value: &big.Int{},
|
||||
Data: util.BuildErc20TransferFromCallData(alice.EvmAddress, bob.EvmAddress, amount),
|
||||
@ -360,7 +361,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ERC20Magic() {
|
||||
Tx: ethtypes.NewTx(ðtypes.LegacyTx{
|
||||
Nonce: nonce,
|
||||
GasPrice: minEvmGasPrice,
|
||||
Gas: 1e6,
|
||||
Gas: 1e5,
|
||||
To: &contractAddress.Address,
|
||||
Value: &big.Int{},
|
||||
Data: util.BuildErc20ApproveCallData(bob.EvmAddress, amount),
|
||||
@ -410,8 +411,8 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ERC20Magic() {
|
||||
)
|
||||
convertTx := util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{&convertMsg},
|
||||
GasLimit: 2e6,
|
||||
FeeAmount: fee,
|
||||
GasLimit: 2e5,
|
||||
FeeAmount: sdk.NewCoins(ukava(200)),
|
||||
Data: "bob converts his new erc20 to an sdk.Coin",
|
||||
}
|
||||
convertRes := bob.SignAndBroadcastKavaTx(convertTx)
|
||||
@ -423,4 +424,17 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoins_ERC20Magic() {
|
||||
// bob should have sdk balance
|
||||
balance := suite.Kava.QuerySdkForBalances(bob.SdkAddress).AmountOf(denom)
|
||||
suite.Equal(sdk.NewIntFromBigInt(amount), balance)
|
||||
|
||||
// alice should have the remaining balance
|
||||
erc20Balance = suite.Kava.GetErc20Balance(contractAddress.Address, alice.EvmAddress)
|
||||
suite.BigIntsEqual(amount, erc20Balance, "expected alice to have half initial funds remaining")
|
||||
|
||||
// convert alice's remaining balance back to sdk coins
|
||||
convertMsg = evmutiltypes.NewMsgConvertCosmosCoinFromERC20(
|
||||
alice.EvmAddress.Hex(),
|
||||
alice.SdkAddress.String(),
|
||||
sdk.NewInt64Coin(denom, amount.Int64()),
|
||||
)
|
||||
convertRes = alice.SignAndBroadcastKavaTx(convertTx)
|
||||
suite.NoError(convertRes.Err)
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ func (suite *IntegrationTestSuite) TestEthCallToGreeterContract() {
|
||||
|
||||
func (suite *IntegrationTestSuite) TestEthCallToErc20() {
|
||||
randoReceiver := util.SdkToEvmAddress(app.RandomAddress())
|
||||
amount := big.NewInt(1e3)
|
||||
amount := big.NewInt(1)
|
||||
|
||||
// make unauthenticated eth_call query to check balance
|
||||
beforeBalance := suite.Kava.GetErc20Balance(suite.DeployedErc20.Address, randoReceiver)
|
||||
@ -108,7 +108,7 @@ func (suite *IntegrationTestSuite) TestEip712BasicMessageAuthorization() {
|
||||
|
||||
// Note that this test works because the deployed erc20 is configured in evmutil & earn params.
|
||||
func (suite *IntegrationTestSuite) TestEip712ConvertToCoinAndDepositToEarn() {
|
||||
amount := sdk.NewInt(1e4) // .04 USDC
|
||||
amount := sdk.NewInt(1e2) // 0.0002 USDC
|
||||
sdkDenom := suite.DeployedErc20.CosmosDenom
|
||||
|
||||
// create new funded account
|
||||
@ -172,4 +172,24 @@ func (suite *IntegrationTestSuite) TestEip712ConvertToCoinAndDepositToEarn() {
|
||||
suite.NoError(err)
|
||||
suite.Len(earnRes.Deposits, 1)
|
||||
suite.Equal(sdk.NewDecFromInt(amount), earnRes.Deposits[0].Shares.AmountOf(sdkDenom))
|
||||
|
||||
// withdraw deposit & convert back to erc20 (this allows refund to recover erc20s used in test)
|
||||
withdraw := earntypes.NewMsgWithdraw(
|
||||
depositor.SdkAddress.String(),
|
||||
sdk.NewCoin(sdkDenom, amount),
|
||||
earntypes.STRATEGY_TYPE_SAVINGS,
|
||||
)
|
||||
convertBack := evmutiltypes.NewMsgConvertCoinToERC20(
|
||||
depositor.SdkAddress.String(),
|
||||
depositor.EvmAddress.Hex(),
|
||||
sdk.NewCoin(sdkDenom, amount),
|
||||
)
|
||||
withdrawAndConvertBack := util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{withdraw, &convertBack},
|
||||
GasLimit: 3e5,
|
||||
FeeAmount: sdk.NewCoins(ukava(300)),
|
||||
Data: "withdrawing from earn & converting back to erc20",
|
||||
}
|
||||
lastRes := depositor.SignAndBroadcastKavaTx(withdrawAndConvertBack)
|
||||
suite.NoError(lastRes.Err)
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func (suite *IntegrationTestSuite) TestChainID() {
|
||||
|
||||
// example test that funds a new account & queries its balance
|
||||
func (suite *IntegrationTestSuite) TestFundedAccount() {
|
||||
funds := ukava(1e7)
|
||||
funds := ukava(1e3)
|
||||
acc := suite.Kava.NewFundedAccount("example-acc", sdk.NewCoins(funds))
|
||||
|
||||
// check that the sdk & evm signers are for the same account
|
||||
@ -125,7 +125,7 @@ func (suite *IntegrationTestSuite) TestIbcTransfer() {
|
||||
ibcAcc := suite.Ibc.NewFundedAccount("ibc-transfer-ibc-side", sdk.NewCoins())
|
||||
|
||||
gasLimit := int64(2e5)
|
||||
fee := ukava(7500)
|
||||
fee := ukava(200)
|
||||
|
||||
fundsToSend := ukava(5e4) // .005 KAVA
|
||||
transferMsg := ibctypes.NewMsgTransfer(
|
||||
|
@ -21,6 +21,19 @@ The variables in `.env` will not override variables that are already present in
|
||||
ie. Running `E2E_INCLUDE_IBC_TESTS=false make test-e2e` will disable the ibc tests regardless of how
|
||||
the variable is set in `.env`.
|
||||
|
||||
### Running on Live Network
|
||||
|
||||
The end-to-end tests support being run on a live network. The primary toggle for setting up the suite to use a live network is the `E2E_RUN_KVTOOL_NETWORKS` flag. When set exactly to `false`, the configuration requires the following three environment variables:
|
||||
* `E2E_KAVA_RPC_URL`
|
||||
* `E2E_KAVA_GRPC_URL`
|
||||
* `E2E_KAVA_EVM_RPC_URL`
|
||||
|
||||
See an example environment configuration with full description of all supported configurations in [`.env.live-network-example`](./.env.live-network-example). This example expects a local kvtool network to be running: `kvtool testnet bootstrap`.
|
||||
|
||||
When run against a live network, the suite will automatically return all the sdk funds sent to `SigningAccount`s on the chain, and will return any ERC20 balance from those accounts if the ERC20 is registered via `Chain.RegisterERC20`. The pre-deployed ERC20 that is required for the tests is registered on setup.
|
||||
|
||||
At this time, live-network tests do not support `E2E_INCLUDE_IBC_TESTS=true` and they do not support automated upgrades.
|
||||
|
||||
## `Chain`s
|
||||
|
||||
A `testutil.Chain` is the abstraction around details, query clients, & signing accounts for interacting with a
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@ -47,6 +48,8 @@ type SigningAccount struct {
|
||||
EvmAddress common.Address
|
||||
SdkAddress sdk.AccAddress
|
||||
|
||||
gasDenom string
|
||||
|
||||
l *log.Logger
|
||||
}
|
||||
|
||||
@ -106,6 +109,8 @@ func (chain *Chain) AddNewSigningAccount(name string, hdPath *hd.BIP44Params, ch
|
||||
mnemonic: mnemonic,
|
||||
l: logger,
|
||||
|
||||
gasDenom: chain.StakingDenom,
|
||||
|
||||
evmPrivKey: privKey,
|
||||
evmSigner: evmSigner,
|
||||
evmReqChan: evmReqChan,
|
||||
@ -170,6 +175,7 @@ func (a *SigningAccount) SignAndBroadcastEvmTx(req util.EvmTxRequest) EvmTxRespo
|
||||
}
|
||||
|
||||
// if we don't have a tx receipt within a given timeout, fail the request
|
||||
a.l.Printf("awaiting evm tx receipt for tx %s\n", res.TxHash)
|
||||
response.Receipt, response.Err = util.WaitForEvmTxReceipt(a.evmSigner.EvmClient, res.TxHash, 10*time.Second)
|
||||
|
||||
return response
|
||||
@ -201,18 +207,11 @@ func (chain *Chain) NewFundedAccount(name string, funds sdk.Coins) *SigningAccou
|
||||
return acc
|
||||
}
|
||||
|
||||
// TODO: verify whale has funds.
|
||||
|
||||
whale := chain.GetAccount(FundedAccountName)
|
||||
whale.l.Printf("attempting to fund created account (%s=%s)\n", name, acc.SdkAddress.String())
|
||||
res := whale.SignAndBroadcastKavaTx(
|
||||
util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{
|
||||
banktypes.NewMsgSend(whale.SdkAddress, acc.SdkAddress, funds),
|
||||
},
|
||||
GasLimit: 2e5,
|
||||
FeeAmount: sdk.NewCoins(sdk.NewCoin(chain.StakingDenom, sdkmath.NewInt(75000))),
|
||||
Data: fmt.Sprintf("initial funding of account %s", name),
|
||||
},
|
||||
)
|
||||
res := whale.BankSend(acc.SdkAddress, funds)
|
||||
|
||||
require.NoErrorf(chain.t, res.Err, "failed to fund new account %s: %s", name, res.Err)
|
||||
|
||||
@ -225,3 +224,32 @@ func (chain *Chain) NewFundedAccount(name string, funds sdk.Coins) *SigningAccou
|
||||
func (a *SigningAccount) NextNonce() (uint64, error) {
|
||||
return a.evmSigner.EvmClient.PendingNonceAt(context.Background(), a.EvmAddress)
|
||||
}
|
||||
|
||||
// BankSend is a helper method for sending funds via x/bank's MsgSend
|
||||
func (a *SigningAccount) BankSend(to sdk.AccAddress, amount sdk.Coins) util.KavaMsgResponse {
|
||||
return a.SignAndBroadcastKavaTx(
|
||||
util.KavaMsgRequest{
|
||||
Msgs: []sdk.Msg{banktypes.NewMsgSend(a.SdkAddress, to, amount)},
|
||||
GasLimit: 2e5, // 200,000 gas
|
||||
FeeAmount: sdk.NewCoins(sdk.NewCoin(a.gasDenom, sdkmath.NewInt(200))), // assume min gas price of .001ukava
|
||||
Data: fmt.Sprintf("sending %s to %s", amount, to),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TransferErc20 is a helper method for sending an erc20 token
|
||||
func (a *SigningAccount) TransferErc20(contract, to common.Address, amount *big.Int) (EvmTxResponse, error) {
|
||||
data := util.BuildErc20TransferCallData(to, amount)
|
||||
nonce, err := a.NextNonce()
|
||||
if err != nil {
|
||||
return EvmTxResponse{}, err
|
||||
}
|
||||
|
||||
req := util.EvmTxRequest{
|
||||
Tx: ethtypes.NewTransaction(nonce, contract, big.NewInt(0), 1e5, big.NewInt(1e10), data),
|
||||
Data: fmt.Sprintf("fund %s with ERC20 balance (%s)", to.Hex(), amount.String()),
|
||||
}
|
||||
|
||||
res := a.SignAndBroadcastEvmTx(req)
|
||||
return res, res.Err
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ type Chain struct {
|
||||
|
||||
EvmClient *ethclient.Client
|
||||
ContractAddrs map[string]common.Address
|
||||
erc20s map[common.Address]struct{}
|
||||
|
||||
EncodingConfig kavaparams.EncodingConfig
|
||||
|
||||
@ -66,6 +67,7 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
|
||||
StakingDenom: details.StakingDenom,
|
||||
ChainId: details.ChainId,
|
||||
ContractAddrs: make(map[string]common.Address),
|
||||
erc20s: make(map[common.Address]struct{}),
|
||||
}
|
||||
chain.EncodingConfig = app.MakeEncodingConfig()
|
||||
|
||||
@ -118,6 +120,57 @@ func (chain *Chain) Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
// ReturnAllFunds loops through all SigningAccounts and sends all their funds back to the
|
||||
// initially funded account.
|
||||
func (chain *Chain) ReturnAllFunds() {
|
||||
whale := chain.GetAccount(FundedAccountName)
|
||||
fmt.Println(chain.erc20s)
|
||||
for _, a := range chain.accounts {
|
||||
if a.SdkAddress.String() != whale.SdkAddress.String() {
|
||||
// NOTE: assumes all cosmos coin conversion funds have been converted back to sdk.
|
||||
|
||||
// return all erc20 balance
|
||||
for erc20Addr := range chain.erc20s {
|
||||
erc20Bal := chain.GetErc20Balance(erc20Addr, a.EvmAddress)
|
||||
// if account has no balance, do nothing
|
||||
if erc20Bal.Cmp(big.NewInt(0)) == 0 {
|
||||
continue
|
||||
}
|
||||
_, err := a.TransferErc20(erc20Addr, whale.EvmAddress, erc20Bal)
|
||||
if err != nil {
|
||||
a.l.Printf("FAILED TO RETURN ERC20 FUNDS (contract: %s, balance: %d): %s\n",
|
||||
erc20Addr, erc20Bal, err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// get sdk balance of account
|
||||
balance := chain.QuerySdkForBalances(a.SdkAddress)
|
||||
// assumes 200,000 gas w/ min fee of .001
|
||||
gas := sdk.NewInt64Coin(chain.StakingDenom, 200)
|
||||
|
||||
// ensure they have enough gas to return funds
|
||||
if balance.AmountOf(chain.StakingDenom).LT(gas.Amount) {
|
||||
a.l.Printf("ACCOUNT LACKS GAS MONEY TO RETURN FUNDS: %s\n", balance)
|
||||
continue
|
||||
}
|
||||
|
||||
// send it all back (minus gas) to the whale!
|
||||
res := a.BankSend(whale.SdkAddress, balance.Sub(gas))
|
||||
if res.Err != nil {
|
||||
a.l.Printf("failed to return funds: %s\n", res.Err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterErc20 is a method to record the address of erc20s on this chain.
|
||||
// The full balances of each registered erc20 will be returned to the funded
|
||||
// account when ReturnAllFunds is called.
|
||||
func (chain *Chain) RegisterErc20(address common.Address) {
|
||||
chain.erc20s[address] = struct{}{}
|
||||
}
|
||||
|
||||
// QuerySdkForBalances gets the balance of a particular address on this Chain.
|
||||
func (chain *Chain) QuerySdkForBalances(addr sdk.AccAddress) sdk.Coins {
|
||||
res, err := chain.Bank.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{
|
||||
|
@ -110,7 +110,7 @@ func ParseLiveNetworkConfig() LiveNetworkConfig {
|
||||
return LiveNetworkConfig{
|
||||
KavaRpcUrl: nonemptyStringEnv("E2E_KAVA_RPC_URL"),
|
||||
KavaGrpcUrl: nonemptyStringEnv("E2E_KAVA_GRPC_URL"),
|
||||
KavaEvmRpcUrl: nonemptyStringEnv("E2E_KAVA_EMV_RPC_URL"),
|
||||
KavaEvmRpcUrl: nonemptyStringEnv("E2E_KAVA_EVM_RPC_URL"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,8 @@ import (
|
||||
"math/big"
|
||||
|
||||
"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"
|
||||
"github.com/kava-labs/kava/x/earn/types"
|
||||
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
|
||||
)
|
||||
@ -41,6 +39,7 @@ func (suite *E2eTestSuite) InitKavaEvmData() {
|
||||
if !found {
|
||||
panic(fmt.Sprintf("erc20 %s must be enabled for conversion to cosmos coin", erc20Addr))
|
||||
}
|
||||
suite.Kava.RegisterErc20(suite.DeployedErc20.Address)
|
||||
|
||||
// expect the erc20's cosmos denom to be a supported earn vault
|
||||
_, err = suite.Kava.Earn.Vault(
|
||||
@ -65,15 +64,7 @@ func (suite *E2eTestSuite) InitKavaEvmData() {
|
||||
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(toAddress, amount)
|
||||
nonce, err := suite.Kava.EvmClient.PendingNonceAt(context.Background(), whale.EvmAddress)
|
||||
res, err := whale.TransferErc20(suite.DeployedErc20.Address, toAddress, amount)
|
||||
suite.NoError(err)
|
||||
|
||||
req := util.EvmTxRequest{
|
||||
Tx: ethtypes.NewTransaction(nonce, suite.DeployedErc20.Address, 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)
|
||||
return res
|
||||
}
|
||||
|
@ -8,8 +8,12 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/tests/e2e/runner"
|
||||
"github.com/kava-labs/kava/tests/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -48,6 +52,31 @@ type E2eTestSuite struct {
|
||||
|
||||
UpgradeHeight int64
|
||||
DeployedErc20 DeployedErc20
|
||||
|
||||
cost costSummary
|
||||
enableRefunds bool
|
||||
}
|
||||
|
||||
// costSummary wraps info about what funds get irrecoverably spent by the test suite run
|
||||
type costSummary struct {
|
||||
sdkAddress string
|
||||
evmAddress string
|
||||
|
||||
erc20BalanceBefore *big.Int
|
||||
erc20BalanceAfter *big.Int
|
||||
|
||||
sdkBalanceBefore sdk.Coins
|
||||
sdkBalanceAfter sdk.Coins
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer
|
||||
func (s costSummary) String() string {
|
||||
before := sdk.NewCoins(s.sdkBalanceBefore...).Add(sdk.NewCoin("erc20", sdkmath.NewIntFromBigInt(s.erc20BalanceBefore)))
|
||||
after := sdk.NewCoins(s.sdkBalanceAfter...).Add(sdk.NewCoin("erc20", sdkmath.NewIntFromBigInt(s.erc20BalanceAfter)))
|
||||
cost, _ := before.SafeSub(after...)
|
||||
return fmt.Sprintf("Cost Summary for %s (%s):\nbefore:\n%s\nafter:\n%s\ncost:\n%s\n",
|
||||
s.sdkAddress, s.evmAddress, util.PrettyPrintCoins(before), util.PrettyPrintCoins(after), util.PrettyPrintCoins(cost),
|
||||
)
|
||||
}
|
||||
|
||||
// SetupSuite is run before all tests. It initializes chain connections and sets up the
|
||||
@ -91,6 +120,14 @@ func (suite *E2eTestSuite) SetupSuite() {
|
||||
}
|
||||
|
||||
suite.InitKavaEvmData()
|
||||
|
||||
whale := suite.Kava.GetAccount(FundedAccountName)
|
||||
suite.cost = costSummary{
|
||||
sdkAddress: whale.SdkAddress.String(),
|
||||
evmAddress: whale.EvmAddress.Hex(),
|
||||
sdkBalanceBefore: suite.Kava.QuerySdkForBalances(whale.SdkAddress),
|
||||
erc20BalanceBefore: suite.Kava.GetErc20Balance(suite.DeployedErc20.Address, whale.EvmAddress),
|
||||
}
|
||||
}
|
||||
|
||||
// TearDownSuite is run after all tests have run.
|
||||
@ -98,6 +135,25 @@ func (suite *E2eTestSuite) SetupSuite() {
|
||||
func (suite *E2eTestSuite) TearDownSuite() {
|
||||
fmt.Println("tearing down test suite.")
|
||||
|
||||
whale := suite.Kava.GetAccount(FundedAccountName)
|
||||
|
||||
if suite.enableRefunds {
|
||||
suite.cost.sdkBalanceAfter = suite.Kava.QuerySdkForBalances(whale.SdkAddress)
|
||||
suite.cost.erc20BalanceAfter = suite.Kava.GetErc20Balance(suite.DeployedErc20.Address, whale.EvmAddress)
|
||||
fmt.Println("==BEFORE REFUNDS==")
|
||||
fmt.Println(suite.cost)
|
||||
|
||||
fmt.Println("attempting to return all unused funds")
|
||||
suite.Kava.ReturnAllFunds()
|
||||
|
||||
fmt.Println("==AFTER REFUNDS==")
|
||||
}
|
||||
|
||||
// calculate & output cost summary for funded account
|
||||
suite.cost.sdkBalanceAfter = suite.Kava.QuerySdkForBalances(whale.SdkAddress)
|
||||
suite.cost.erc20BalanceAfter = suite.Kava.GetErc20Balance(suite.DeployedErc20.Address, whale.EvmAddress)
|
||||
fmt.Println(suite.cost)
|
||||
|
||||
// TODO: track asset denoms & then return all funds to initial funding account.
|
||||
|
||||
// close all account request channels
|
||||
@ -113,6 +169,7 @@ func (suite *E2eTestSuite) TearDownSuite() {
|
||||
func (suite *E2eTestSuite) SetupKvtoolNodeRunner() *runner.KvtoolRunner {
|
||||
// upgrade tests are only supported on kvtool networks
|
||||
suite.UpgradeHeight = suite.config.Kvtool.KavaUpgradeHeight
|
||||
suite.enableRefunds = false
|
||||
|
||||
runnerConfig := runner.KvtoolRunnerConfig{
|
||||
KavaConfigTemplate: suite.config.Kvtool.KavaConfigTemplate,
|
||||
@ -137,6 +194,7 @@ func (suite *E2eTestSuite) SetupLiveNetworkNodeRunner() *runner.LiveNodeRunner {
|
||||
if suite.config.IncludeIbcTests {
|
||||
panic("ibc tests not supported for live network configuration")
|
||||
}
|
||||
suite.enableRefunds = true
|
||||
|
||||
runnerConfig := runner.LiveNodeRunnerConfig{
|
||||
KavaRpcUrl: suite.config.LiveNetwork.KavaRpcUrl,
|
||||
|
20
tests/util/strings.go
Normal file
20
tests/util/strings.go
Normal file
@ -0,0 +1,20 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func PrettyPrintCoins(coins sdk.Coins) string {
|
||||
if len(coins) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
out := make([]string, 0, len(coins))
|
||||
for _, coin := range coins {
|
||||
out = append(out, coin.String())
|
||||
}
|
||||
return fmt.Sprintf("- %s", strings.Join(out, "\n- "))
|
||||
}
|
Loading…
Reference in New Issue
Block a user