0g-chain/app/ante/eip712_test.go
2024-08-02 19:26:50 +08:00

673 lines
22 KiB
Go

package ante_test
import (
"math/big"
"testing"
"time"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/sims"
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"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/crypto/tmhash"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
tmversion "github.com/cometbft/cometbft/proto/tendermint/version"
"github.com/cometbft/cometbft/version"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/evmos/ethermint/ethereum/eip712"
"github.com/evmos/ethermint/tests"
etherminttypes "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
"github.com/stretchr/testify/suite"
"github.com/0glabs/0g-chain/app"
"github.com/0glabs/0g-chain/chaincfg"
evmutilkeeper "github.com/0glabs/0g-chain/x/evmutil/keeper"
evmutiltestutil "github.com/0glabs/0g-chain/x/evmutil/testutil"
evmutiltypes "github.com/0glabs/0g-chain/x/evmutil/types"
pricefeedtypes "github.com/0glabs/0g-chain/x/pricefeed/types"
)
const (
ChainID = app.TestChainId
USDCCoinDenom = "erc20/usdc"
USDCCDPType = "erc20-usdc"
)
type EIP712TestSuite struct {
suite.Suite
tApp app.TestApp
ctx sdk.Context
evmutilKeeper evmutilkeeper.Keeper
clientCtx client.Context
ethSigner ethtypes.Signer
testAddr sdk.AccAddress
testAddr2 sdk.AccAddress
testPrivKey cryptotypes.PrivKey
testPrivKey2 cryptotypes.PrivKey
testEVMAddr evmutiltypes.InternalEVMAddress
testEVMAddr2 evmutiltypes.InternalEVMAddress
usdcEVMAddr evmutiltypes.InternalEVMAddress
}
func (suite *EIP712TestSuite) getEVMAmount(amount int64) sdkmath.Int {
incr := sdkmath.RelativePow(sdkmath.NewUint(10), sdkmath.NewUint(18), sdkmath.OneUint())
return sdkmath.NewInt(amount).Mul(sdkmath.NewIntFromUint64(incr.Uint64()))
}
func (suite *EIP712TestSuite) createTestEIP712CosmosTxBuilder(
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg,
) client.TxBuilder {
var err error
nonce, err := suite.tApp.GetAccountKeeper().GetSequence(suite.ctx, from)
suite.Require().NoError(err)
pc, err := etherminttypes.ParseChainID(chainId)
suite.Require().NoError(err)
ethChainId := pc.Uint64()
// GenerateTypedData TypedData
fee := legacytx.NewStdFee(gas, gasAmount)
accNumber := suite.tApp.GetAccountKeeper().GetAccount(suite.ctx, from).GetAccountNumber()
data := eip712.ConstructUntypedEIP712Data(chainId, accNumber, nonce, 0, fee, msgs, "", nil)
typedData, err := eip712.WrapTxToTypedData(ethChainId, msgs, data, &eip712.FeeDelegationOptions{
FeePayer: from,
}, suite.tApp.GetEvmKeeper().GetParams(suite.ctx))
suite.Require().NoError(err)
sigHash, err := eip712.ComputeTypedDataHash(typedData)
suite.Require().NoError(err)
// Sign typedData
keyringSigner := tests.NewSigner(priv)
signature, pubKey, err := keyringSigner.SignByAddress(from, sigHash)
suite.Require().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(&etherminttypes.ExtensionOptionsWeb3Tx{
FeePayer: from.String(),
TypedDataChainID: ethChainId,
FeePayerSig: signature,
})
suite.Require().NoError(err)
suite.clientCtx.TxConfig.SignModeHandler()
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
suite.Require().True(ok)
builder.SetExtensionOptions(option)
builder.SetFeeAmount(gasAmount)
builder.SetGasLimit(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)
return builder
}
func (suite *EIP712TestSuite) SetupTest() {
tApp := app.NewTestApp()
suite.tApp = tApp
cdc := tApp.AppCodec()
suite.evmutilKeeper = tApp.GetEvmutilKeeper()
addr, privkey := tests.NewAddrKey()
suite.testAddr = sdk.AccAddress(addr.Bytes())
suite.testPrivKey = privkey
suite.testEVMAddr = evmutiltestutil.MustNewInternalEVMAddressFromString(addr.String())
addr2, privKey2 := tests.NewAddrKey()
suite.testPrivKey2 = privKey2
suite.testAddr2 = sdk.AccAddress(addr2.Bytes())
suite.testEVMAddr2 = evmutiltestutil.MustNewInternalEVMAddressFromString(addr2.String())
encodingConfig := app.MakeEncodingConfig()
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
suite.ethSigner = ethtypes.LatestSignerForChainID(tApp.GetEvmKeeper().ChainID())
// Genesis states
evmGs := evmtypes.NewGenesisState(
evmtypes.NewParams(
chaincfg.EvmDenom, // evmDenom
false, // allowedUnprotectedTxs
true, // enableCreate
true, // enableCall
evmtypes.DefaultChainConfig(), // ChainConfig
nil, // extraEIPs
nil, // eip712AllowedMsgs
),
nil,
)
feemarketGenesis := feemarkettypes.DefaultGenesisState()
feemarketGenesis.Params.EnableHeight = 1
feemarketGenesis.Params.NoBaseFee = false
pricefeedGenState := pricefeedtypes.DefaultGenesisState()
pricefeedGenState.Params.Markets = []pricefeedtypes.Market{
{
MarketID: "usdx:usd",
BaseAsset: "usdx",
QuoteAsset: "usd",
Oracles: []sdk.AccAddress{},
Active: true,
},
{
MarketID: "usdc:usd",
BaseAsset: "usdc",
QuoteAsset: "usd",
Oracles: []sdk.AccAddress{},
Active: true,
},
{
MarketID: "usdc:usd:30",
BaseAsset: "usdc",
QuoteAsset: "usd",
Oracles: []sdk.AccAddress{},
Active: true,
},
}
pricefeedGenState.PostedPrices = []pricefeedtypes.PostedPrice{
{
MarketID: "usdx:usd",
OracleAddress: sdk.AccAddress{},
Price: sdk.MustNewDecFromStr("1.00"),
Expiry: time.Now().Add(1 * time.Hour),
},
{
MarketID: "usdc:usd",
OracleAddress: sdk.AccAddress{},
Price: sdk.MustNewDecFromStr("1.00"),
Expiry: time.Now().Add(1 * time.Hour),
},
{
MarketID: "usdc:usd:30",
OracleAddress: sdk.AccAddress{},
Price: sdk.MustNewDecFromStr("1.00"),
Expiry: time.Now().Add(1 * time.Hour),
},
}
genState := app.GenesisState{
evmtypes.ModuleName: cdc.MustMarshalJSON(evmGs),
feemarkettypes.ModuleName: cdc.MustMarshalJSON(feemarketGenesis),
pricefeedtypes.ModuleName: cdc.MustMarshalJSON(&pricefeedGenState),
}
// funds our test accounts with some gas denom
coinsGenState := app.NewFundedGenStateWithSameCoins(
tApp.AppCodec(),
sdk.NewCoins(chaincfg.MakeCoinForGasDenom(1e9)),
[]sdk.AccAddress{suite.testAddr, suite.testAddr2},
)
tApp.InitializeFromGenesisStatesWithTimeAndChainID(
time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC),
ChainID,
genState,
coinsGenState,
)
// consensus key
consPriv, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
consAddress := sdk.ConsAddress(consPriv.PubKey().Address())
ctx := tApp.NewContext(false, tmproto.Header{
Height: tApp.LastBlockHeight() + 1,
ChainID: ChainID,
Time: time.Now().UTC(),
ProposerAddress: consAddress.Bytes(),
Version: tmversion.Consensus{
Block: version.BlockProtocol,
},
LastBlockId: tmproto.BlockID{
Hash: tmhash.Sum([]byte("block_id")),
PartSetHeader: tmproto.PartSetHeader{
Total: 11,
Hash: tmhash.Sum([]byte("partset_header")),
},
},
AppHash: tmhash.Sum([]byte("app")),
DataHash: tmhash.Sum([]byte("data")),
EvidenceHash: tmhash.Sum([]byte("evidence")),
ValidatorsHash: tmhash.Sum([]byte("validators")),
NextValidatorsHash: tmhash.Sum([]byte("next_validators")),
ConsensusHash: tmhash.Sum([]byte("consensus")),
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
suite.ctx = ctx
// We need to set the validator as calling the EVM looks up the validator address
// https://github.com/evmos/ethermint/blob/f21592ebfe74da7590eb42ed926dae970b2a9a3f/x/evm/keeper/state_transition.go#L487
// evmkeeper.EVMConfig() will return error "failed to load evm config" if not set
valAcc := &etherminttypes.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(consAddress.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}
tApp.GetAccountKeeper().SetAccount(ctx, valAcc)
_, testAddresses := app.GeneratePrivKeyAddressPairs(1)
valAddr := sdk.ValAddress(testAddresses[0].Bytes())
validator, err := stakingtypes.NewValidator(valAddr, consPriv.PubKey(), stakingtypes.Description{})
suite.Require().NoError(err)
err = tApp.GetStakingKeeper().SetValidatorByConsAddr(ctx, validator)
suite.Require().NoError(err)
tApp.GetStakingKeeper().SetValidator(ctx, validator)
// Deploy an ERC20 contract for USDC
contractAddr := suite.deployUSDCERC20(tApp, ctx)
pair := evmutiltypes.NewConversionPair(
contractAddr,
USDCCoinDenom,
)
suite.usdcEVMAddr = pair.GetAddress()
// update consensus params
cParams := tApp.GetConsensusParams(suite.ctx)
cParams.Block.MaxGas = sims.DefaultGenTxGas * 20
tApp.StoreConsensusParams(suite.ctx, cParams)
// Add a contract to evmutil conversion pair
evmutilParams := suite.evmutilKeeper.GetParams(suite.ctx)
evmutilParams.EnabledConversionPairs =
evmutiltypes.NewConversionPairs(
evmutiltypes.NewConversionPair(
// First contract evmutil module deploys
evmutiltestutil.MustNewInternalEVMAddressFromString("0x15932E26f5BD4923d46a2b205191C4b5d5f43FE3"),
"erc20/usdc",
),
)
suite.evmutilKeeper.SetParams(suite.ctx, evmutilParams)
// allow msgs through evm eip712
evmKeeper := suite.tApp.GetEvmKeeper()
params := evmKeeper.GetParams(suite.ctx)
params.EIP712AllowedMsgs = []evmtypes.EIP712AllowedMsg{
{
MsgTypeUrl: "/zgc.evmutil.v1beta1.MsgConvertERC20ToCoin",
MsgValueTypeName: "MsgValueEVMConvertERC20ToCoin",
ValueTypes: []evmtypes.EIP712MsgAttrType{
{Name: "initiator", Type: "string"},
{Name: "receiver", Type: "string"},
{Name: "zgchain_erc20_address", Type: "string"},
{Name: "amount", Type: "string"},
},
},
{
MsgTypeUrl: "/zgc.evmutil.v1beta1.MsgConvertCoinToERC20",
MsgValueTypeName: "MsgValueEVMConvertCoinToERC20",
ValueTypes: []evmtypes.EIP712MsgAttrType{
{Name: "initiator", Type: "string"},
{Name: "receiver", Type: "string"},
{Name: "amount", Type: "Coin"},
},
},
}
evmKeeper.SetParams(suite.ctx, params)
// give test address 50k erc20 usdc to begin with
initBal := suite.getEVMAmount(50_000)
err = suite.evmutilKeeper.MintERC20(
ctx,
pair.GetAddress(), // contractAddr
suite.testEVMAddr, //receiver
initBal.BigInt(),
)
suite.Require().NoError(err)
err = suite.evmutilKeeper.MintERC20(
ctx,
pair.GetAddress(), // contractAddr
suite.testEVMAddr2, //receiver
initBal.BigInt(),
)
suite.Require().NoError(err)
// We need to commit so that the ethermint feemarket beginblock runs to set the minfee
// feeMarketKeeper.GetBaseFee() will return nil otherwise
suite.Commit()
// set base fee
suite.tApp.GetFeeMarketKeeper().SetBaseFee(suite.ctx, big.NewInt(100))
}
func (suite *EIP712TestSuite) Commit() {
_ = suite.tApp.Commit()
header := suite.ctx.BlockHeader()
header.Height += 1
suite.tApp.BeginBlock(abci.RequestBeginBlock{
Header: header,
})
// update ctx
suite.ctx = suite.tApp.NewContext(false, header)
}
func (suite *EIP712TestSuite) deployUSDCERC20(app app.TestApp, ctx sdk.Context) evmutiltypes.InternalEVMAddress {
// make sure module account is created
suite.tApp.FundModuleAccount(
suite.ctx,
evmutiltypes.ModuleName,
sdk.NewCoins(chaincfg.MakeCoinForGasDenom(0)),
)
contractAddr, err := suite.evmutilKeeper.DeployTestMintableERC20Contract(suite.ctx, "USDC", "USDC", uint8(18))
suite.Require().NoError(err)
suite.Require().Greater(len(contractAddr.Address), 0)
return contractAddr
}
func (suite *EIP712TestSuite) TestEIP712Tx() {
encodingConfig := app.MakeEncodingConfig()
testcases := []struct {
name string
usdcDepositAmt int64
usdxToMintAmt int64
updateTx func(txBuilder client.TxBuilder, msgs []sdk.Msg) client.TxBuilder
updateMsgs func(msgs []sdk.Msg) []sdk.Msg
expectedCode uint32
failCheckTx bool
errMsg string
}{
// TODO: need fix
// {
// name: "processes deposit eip712 messages successfully",
// usdcDepositAmt: 100,
// usdxToMintAmt: 99,
// },
{
name: "fails when convertion more erc20 usdc than balance",
usdcDepositAmt: 51_000,
usdxToMintAmt: 100,
errMsg: "transfer amount exceeds balance",
},
// TODO: need fix
// {
// name: "fails when minting more usdx than allowed",
// usdcDepositAmt: 100,
// usdxToMintAmt: 100,
// errMsg: "proposed collateral ratio is below liquidation ratio",
// },
// TODO: need fix
// {
// name: "fails when trying to convert usdc for another address",
// usdcDepositAmt: 100,
// usdxToMintAmt: 90,
// errMsg: "unauthorized",
// failCheckTx: true,
// updateMsgs: func(msgs []sdk.Msg) []sdk.Msg {
// convertMsg := evmutiltypes.NewMsgConvertERC20ToCoin(
// suite.testEVMAddr2,
// suite.testAddr,
// suite.usdcEVMAddr,
// suite.getEVMAmount(100),
// )
// msgs[0] = &convertMsg
// return msgs
// },
// },
{
name: "fails when trying to convert erc20 for non-whitelisted contract",
usdcDepositAmt: 100,
usdxToMintAmt: 90,
errMsg: "ERC20 token not enabled to convert to sdk.Coin",
updateMsgs: func(msgs []sdk.Msg) []sdk.Msg {
convertMsg := evmutiltypes.NewMsgConvertERC20ToCoin(
suite.testEVMAddr,
suite.testAddr,
suite.testEVMAddr2,
suite.getEVMAmount(100),
)
msgs[0] = &convertMsg
return msgs
},
},
{
name: "fails when signer tries to send messages with invalid signature",
usdcDepositAmt: 100,
usdxToMintAmt: 90,
failCheckTx: true,
errMsg: "tx intended signer does not match the given signer",
updateTx: func(txBuilder client.TxBuilder, msgs []sdk.Msg) client.TxBuilder {
var option *codectypes.Any
option, _ = codectypes.NewAnyWithValue(&etherminttypes.ExtensionOptionsWeb3Tx{
FeePayer: suite.testAddr.String(),
TypedDataChainID: 2221,
FeePayerSig: []byte("sig"),
})
builder, _ := txBuilder.(authtx.ExtensionOptionsTxBuilder)
builder.SetExtensionOptions(option)
return txBuilder
},
},
{
name: "fails when insufficient gas fees are provided",
usdcDepositAmt: 100,
usdxToMintAmt: 90,
errMsg: "insufficient funds",
updateTx: func(txBuilder client.TxBuilder, msgs []sdk.Msg) client.TxBuilder {
bk := suite.tApp.GetBankKeeper()
gasCoins := bk.GetBalance(suite.ctx, suite.testAddr, chaincfg.GasDenom)
suite.tApp.GetBankKeeper().SendCoins(suite.ctx, suite.testAddr, suite.testAddr2, sdk.NewCoins(gasCoins))
return txBuilder
},
},
{
name: "fails when invalid chain id is provided",
usdcDepositAmt: 100,
usdxToMintAmt: 90,
failCheckTx: true,
errMsg: "invalid chain-id",
updateTx: func(txBuilder client.TxBuilder, msgs []sdk.Msg) client.TxBuilder {
gasAmt := sdk.NewCoins(chaincfg.MakeCoinForGasDenom(20))
return suite.createTestEIP712CosmosTxBuilder(
suite.testAddr, suite.testPrivKey, "kavatest_12-1", uint64(sims.DefaultGenTxGas*10), gasAmt, msgs,
)
},
},
{
name: "fails when invalid fee payer is provided",
usdcDepositAmt: 100,
usdxToMintAmt: 90,
failCheckTx: true,
errMsg: "invalid pubkey",
updateTx: func(txBuilder client.TxBuilder, msgs []sdk.Msg) client.TxBuilder {
gasAmt := sdk.NewCoins(chaincfg.MakeCoinForGasDenom(20))
return suite.createTestEIP712CosmosTxBuilder(
suite.testAddr2, suite.testPrivKey2, ChainID, uint64(sims.DefaultGenTxGas*10), gasAmt, msgs,
)
},
},
}
for _, tc := range testcases {
suite.Run(tc.name, func() {
suite.SetupTest()
// create messages to convert, mint, and deposit to lend
usdcAmt := suite.getEVMAmount(tc.usdcDepositAmt)
convertMsg := evmutiltypes.NewMsgConvertERC20ToCoin(
suite.testEVMAddr,
suite.testAddr,
suite.usdcEVMAddr,
usdcAmt,
)
msgs := []sdk.Msg{
&convertMsg,
}
if tc.updateMsgs != nil {
msgs = tc.updateMsgs(msgs)
}
gasAmt := sdk.NewCoins(chaincfg.MakeCoinForGasDenom(20))
txBuilder := suite.createTestEIP712CosmosTxBuilder(
suite.testAddr, suite.testPrivKey, ChainID, uint64(sims.DefaultGenTxGas*10), gasAmt, msgs,
)
if tc.updateTx != nil {
txBuilder = tc.updateTx(txBuilder, msgs)
}
txBytes, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
suite.Require().NoError(err)
resCheckTx := suite.tApp.CheckTx(
abci.RequestCheckTx{
Tx: txBytes,
Type: abci.CheckTxType_New,
},
)
if !tc.failCheckTx {
suite.Require().Equal(resCheckTx.Code, uint32(0), resCheckTx.Log)
} else {
suite.Require().NotEqual(resCheckTx.Code, uint32(0), resCheckTx.Log)
suite.Require().Contains(resCheckTx.Log, tc.errMsg)
}
resDeliverTx := suite.tApp.DeliverTx(
abci.RequestDeliverTx{
Tx: txBytes,
},
)
if tc.errMsg == "" {
suite.Require().Equal(resDeliverTx.Code, uint32(0), resDeliverTx.Log)
// validate user cosmos erc20/usd balance
bk := suite.tApp.GetBankKeeper()
amt := bk.GetBalance(suite.ctx, suite.testAddr, USDCCoinDenom)
suite.Require().Equal(sdk.ZeroInt(), amt.Amount)
// validate cdp
// cdp, found := suite.tApp.GetCDPKeeper().GetCdpByOwnerAndCollateralType(suite.ctx, suite.testAddr, USDCCDPType)
// suite.Require().True(found)
// suite.Require().Equal(suite.testAddr, cdp.Owner)
// suite.Require().Equal(sdk.NewCoin(USDCCoinDenom, suite.getEVMAmount(100)), cdp.Collateral)
// suite.Require().Equal(sdk.NewCoin("usdx", sdkmath.NewInt(99_000_000)), cdp.Principal)
// validate hard
// hardDeposit, found := suite.tApp.GetHardKeeper().GetDeposit(suite.ctx, suite.testAddr)
// suite.Require().True(found)
// suite.Require().Equal(suite.testAddr, hardDeposit.Depositor)
// suite.Require().Equal(sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99_000_000))), hardDeposit.Amount)
} else {
suite.Require().NotEqual(resDeliverTx.Code, uint32(0), resCheckTx.Log)
suite.Require().Contains(resDeliverTx.Log, tc.errMsg)
}
})
}
}
func (suite *EIP712TestSuite) TestEIP712Tx_DepositAndWithdraw() {
encodingConfig := app.MakeEncodingConfig()
// create deposit msgs
usdcAmt := suite.getEVMAmount(100)
convertMsg := evmutiltypes.NewMsgConvertERC20ToCoin(
suite.testEVMAddr,
suite.testAddr,
suite.usdcEVMAddr,
usdcAmt,
)
depositMsgs := []sdk.Msg{
&convertMsg,
}
// deliver deposit msg
gasAmt := sdk.NewCoins(chaincfg.MakeCoinForGasDenom(20))
txBuilder := suite.createTestEIP712CosmosTxBuilder(
suite.testAddr, suite.testPrivKey, ChainID, uint64(sims.DefaultGenTxGas*10), gasAmt, depositMsgs,
)
txBytes, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
suite.Require().NoError(err)
resDeliverTx := suite.tApp.DeliverTx(
abci.RequestDeliverTx{
Tx: txBytes,
},
)
suite.Require().Equal(resDeliverTx.Code, uint32(0), resDeliverTx.Log)
// validate hard
// hardDeposit, found := suite.tApp.GetHardKeeper().GetDeposit(suite.ctx, suite.testAddr)
// suite.Require().True(found)
// suite.Require().Equal(suite.testAddr, hardDeposit.Depositor)
// suite.Require().Equal(sdk.NewCoins(sdk.NewCoin("usdx", sdkmath.NewInt(99_000_000))), hardDeposit.Amount)
// validate erc20 balance
coinBal, err := suite.evmutilKeeper.QueryERC20BalanceOf(suite.ctx, suite.usdcEVMAddr, suite.testEVMAddr)
suite.Require().NoError(err)
suite.Require().Equal(suite.getEVMAmount(49_900).BigInt(), coinBal)
// withdraw msgs
withdrawConvertMsg := evmutiltypes.NewMsgConvertCoinToERC20(
suite.testAddr.String(),
suite.testEVMAddr.String(),
sdk.NewCoin(USDCCoinDenom, usdcAmt),
)
withdrawMsgs := []sdk.Msg{
&withdrawConvertMsg,
}
// deliver withdraw msg
txBuilder = suite.createTestEIP712CosmosTxBuilder(
suite.testAddr, suite.testPrivKey, ChainID, uint64(sims.DefaultGenTxGas*10), gasAmt, withdrawMsgs,
)
txBytes, err = encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
suite.Require().NoError(err)
resDeliverTx = suite.tApp.DeliverTx(
abci.RequestDeliverTx{
Tx: txBytes,
},
)
suite.Require().Equal(resDeliverTx.Code, uint32(0), resDeliverTx.Log)
// validate hard & cdp should be repayed
// _, found = suite.tApp.GetHardKeeper().GetDeposit(suite.ctx, suite.testAddr)
// suite.Require().False(found)
// _, found = suite.tApp.GetCDPKeeper().GetCdpByOwnerAndCollateralType(suite.ctx, suite.testAddr, USDCCDPType)
// suite.Require().False(found)
// validate user cosmos erc20/usd balance
bk := suite.tApp.GetBankKeeper()
amt := bk.GetBalance(suite.ctx, suite.testAddr, USDCCoinDenom)
suite.Require().Equal(sdk.ZeroInt(), amt.Amount)
// validate erc20 balance
coinBal, err = suite.evmutilKeeper.QueryERC20BalanceOf(suite.ctx, suite.usdcEVMAddr, suite.testEVMAddr)
suite.Require().NoError(err)
suite.Require().Equal(suite.getEVMAmount(50_000).BigInt(), coinBal)
}
func TestEIP712Suite(t *testing.T) {
suite.Run(t, new(EIP712TestSuite))
}