Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(fungible): increase keeper code coverage #1128

Merged
merged 12 commits into from
Sep 21, 2023
3 changes: 3 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50785,6 +50785,9 @@ definitions:
type: boolean
fungibleMsgDeployFungibleCoinZRC20Response:
type: object
properties:
address:
type: string
fungibleMsgRemoveForeignCoinResponse:
type: object
fungibleMsgUpdateContractBytecodeResponse:
Expand Down
4 changes: 3 additions & 1 deletion proto/fungible/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ message MsgDeployFungibleCoinZRC20 {
int64 gas_limit = 8;
}

message MsgDeployFungibleCoinZRC20Response {}
message MsgDeployFungibleCoinZRC20Response {
string address = 1;
}

message MsgRemoveForeignCoin {
string creator = 1;
Expand Down
7 changes: 7 additions & 0 deletions testutil/sample/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"strconv"
"testing"

"github.com/zeta-chain/zetacore/cmd/zetacored/config"

"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -113,3 +115,8 @@ func StringRandom(r *rand.Rand, length int) string {
}
return string(result)
}

// Coins returns a sample sdk.Coins
func Coins() sdk.Coins {
return sdk.NewCoins(sdk.NewCoin(config.BaseDenom, sdk.NewInt(42)))
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (k Keeper) TestUpdateSystemContractAddress(goCtx context.Context) error {
return sdkerrors.Wrapf(err, "failed to DeploySystemContract")
}
creator := k.observerKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_deploy_fungible_coin)
msg := types.NewMessageUpdateSystemContract(creator, SystemContractAddress.Hex())
msg := types.NewMsgUpdateSystemContract(creator, SystemContractAddress.Hex())
_, err = k.UpdateSystemContract(ctx, msg)
k.Logger(ctx).Info("System contract updated", "new address", SystemContractAddress.String())
return err
Expand Down
15 changes: 8 additions & 7 deletions x/fungible/keeper/evm.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions x/fungible/keeper/gas_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/zeta-chain/zetacore/x/fungible/types"
)

// sets gas price on the system contract in zEVM; return the gasUsed and error code
// SetGasPrice sets gas price on the system contract in zEVM; return the gasUsed and error code
func (k Keeper) SetGasPrice(ctx sdk.Context, chainid *big.Int, gasPrice *big.Int) (uint64, error) {
system, found := k.GetSystemContract(ctx)
if !found {
Expand Down Expand Up @@ -66,9 +66,9 @@ func (k Keeper) SetGasZetaPool(ctx sdk.Context, chainid *big.Int, pool common.Ad
if err != nil {
return sdkerrors.Wrapf(types.ErrABIGet, "SystemContractMetaData")
}
res, err := k.CallEVM(ctx, *abi, types.ModuleAddressEVM, oracle, BigIntZero, nil, true, false, "SetGasZetaPool", chainid, pool)
res, err := k.CallEVM(ctx, *abi, types.ModuleAddressEVM, oracle, BigIntZero, nil, true, false, "setGasZetaPool", chainid, pool)
if err != nil || res.Failed() {
return sdkerrors.Wrapf(types.ErrContractCall, "SetGasZetaPool")
return sdkerrors.Wrapf(types.ErrContractCall, "setGasZetaPool")
}

return nil
Expand Down
75 changes: 75 additions & 0 deletions x/fungible/keeper/gas_price_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package keeper_test

import (
"math/big"
"testing"

ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/systemcontract.sol"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
"github.com/zeta-chain/zetacore/x/fungible/keeper"
"github.com/zeta-chain/zetacore/x/fungible/types"
)

func TestKeeper_SetGasPrice(t *testing.T) {
k, ctx, sdkk, _ := keepertest.FungibleKeeper(t)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)

_, _, _, _, system := deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)

queryGasPrice := func(chainID *big.Int) *big.Int {
abi, err := systemcontract.SystemContractMetaData.GetAbi()
require.NoError(t, err)
res, err := k.CallEVM(ctx, *abi, types.ModuleAddressEVM, system, keeper.BigIntZero, nil, false, false, "gasPriceByChainId", chainID)
require.NoError(t, err)
unpacked, err := abi.Unpack("gasPriceByChainId", res.Ret)
require.NoError(t, err)
gasPrice, ok := unpacked[0].(*big.Int)
require.True(t, ok)
return gasPrice
}

_, err := k.SetGasPrice(ctx, big.NewInt(1), big.NewInt(42))
require.NoError(t, err)
require.Equal(t, big.NewInt(42), queryGasPrice(big.NewInt(1)))
}

func TestKeeper_SetGasCoin(t *testing.T) {
k, ctx, sdkk, _ := keepertest.FungibleKeeper(t)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
gas := sample.EthAddress()

deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)
err := k.SetGasCoin(ctx, big.NewInt(1), gas)
require.NoError(t, err)

found, err := k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(1))
require.NoError(t, err)
require.Equal(t, gas.Hex(), found.Hex())
}

func TestKeeper_SetGasZetaPool(t *testing.T) {
k, ctx, sdkk, _ := keepertest.FungibleKeeper(t)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
zrc20 := sample.EthAddress()

_, _, _, _, system := deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)

queryZetaPool := func(chainID *big.Int) ethcommon.Address {
abi, err := systemcontract.SystemContractMetaData.GetAbi()
require.NoError(t, err)
res, err := k.CallEVM(ctx, *abi, types.ModuleAddressEVM, system, keeper.BigIntZero, nil, false, false, "gasZetaPoolByChainId", chainID)
require.NoError(t, err)
unpacked, err := abi.Unpack("gasZetaPoolByChainId", res.Ret)
require.NoError(t, err)
pool, ok := unpacked[0].(ethcommon.Address)
require.True(t, ok)
return pool
}

err := k.SetGasZetaPool(ctx, big.NewInt(1), zrc20)
require.NoError(t, err)
require.NotEqual(t, ethcommon.Address{}, queryZetaPool(big.NewInt(1)))
}
47 changes: 27 additions & 20 deletions x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"math/big"

"github.com/ethereum/go-ethereum/common"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
zetacommon "github.com/zeta-chain/zetacore/common"
Expand Down Expand Up @@ -31,41 +33,46 @@ import (
// Only the admin policy account is authorized to broadcast this message.
func (k msgServer) DeployFungibleCoinZRC20(goCtx context.Context, msg *types.MsgDeployFungibleCoinZRC20) (*types.MsgDeployFungibleCoinZRC20Response, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

var address common.Address
var err error

if msg.Creator != k.observerKeeper.GetParams(ctx).GetAdminPolicyAccount(zetaObserverTypes.Policy_Type_deploy_fungible_coin) {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Deploy can only be executed by the correct policy account")
}
if msg.Decimals > 255 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "decimals must be less than 256")
}
if msg.CoinType == zetacommon.CoinType_Gas {
_, err := k.SetupChainGasCoinAndPool(ctx, msg.ForeignChainId, msg.Name, msg.Symbol, uint8(msg.Decimals))
address, err = k.SetupChainGasCoinAndPool(ctx, msg.ForeignChainId, msg.Name, msg.Symbol, uint8(msg.Decimals))
if err != nil {
return nil, sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool")
}
} else {
addr, err := k.DeployZRC20Contract(ctx, msg.Name, msg.Symbol, uint8(msg.Decimals), msg.ForeignChainId, msg.CoinType, msg.ERC20, big.NewInt(msg.GasLimit))
address, err = k.DeployZRC20Contract(ctx, msg.Name, msg.Symbol, uint8(msg.Decimals), msg.ForeignChainId, msg.CoinType, msg.ERC20, big.NewInt(msg.GasLimit))
if err != nil {
return nil, err
}
}

err = ctx.EventManager().EmitTypedEvent(
&types.EventZRC20Deployed{
MsgTypeUrl: sdk.MsgTypeURL(&types.MsgDeployFungibleCoinZRC20{}),
ChainId: msg.ForeignChainId,
Contract: addr.String(),
Name: msg.Name,
Symbol: msg.Symbol,
Decimals: int64(msg.Decimals),
CoinType: msg.CoinType,
Erc20: msg.ERC20,
GasLimit: msg.GasLimit,
},
)
if err != nil {
return nil, sdkerrors.Wrapf(err, "failed to emit event")
}

err = ctx.EventManager().EmitTypedEvent(
&types.EventZRC20Deployed{
MsgTypeUrl: sdk.MsgTypeURL(&types.MsgDeployFungibleCoinZRC20{}),
ChainId: msg.ForeignChainId,
Contract: address.String(),
Name: msg.Name,
Symbol: msg.Symbol,
Decimals: int64(msg.Decimals),
CoinType: msg.CoinType,
Erc20: msg.ERC20,
GasLimit: msg.GasLimit,
},
)
if err != nil {
return nil, sdkerrors.Wrapf(err, "failed to emit event")
}

return &types.MsgDeployFungibleCoinZRC20Response{}, nil
return &types.MsgDeployFungibleCoinZRC20Response{
Address: address.Hex(),
}, nil
}
147 changes: 147 additions & 0 deletions x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package keeper_test

import (
"math/big"
"testing"

sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/common"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
"github.com/zeta-chain/zetacore/x/fungible/keeper"
"github.com/zeta-chain/zetacore/x/fungible/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) {
t.Run("can deploy a new zrc20", func(t *testing.T) {
k, ctx, sdkk, zk := keepertest.FungibleKeeper(t)
msgServer := keeper.NewMsgServerImpl(*k)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
admin := sample.AccAddress()
setAdminDeployFungibleCoin(ctx, zk, admin)
chainID := getValidChainID(t)

deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)

res, err := msgServer.DeployFungibleCoinZRC20(ctx, types.NewMsgDeployFungibleCoinZRC20(
admin,
sample.EthAddress().Hex(),
chainID,
8,
"foo",
"foo",
common.CoinType_Gas,
1000000,
))
require.NoError(t, err)
gasAddress := res.Address
assertContractDeployment(t, sdkk.EvmKeeper, ctx, ethcommon.HexToAddress(gasAddress))

// can retrieve the gas coin
foreignCoin, found := k.GetForeignCoins(ctx, gasAddress)
require.True(t, found)
require.Equal(t, foreignCoin.CoinType, common.CoinType_Gas)
require.Contains(t, foreignCoin.Name, "foo")

gas, err := k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID))
require.NoError(t, err)
require.Equal(t, gasAddress, gas.Hex())

// can deploy non-gas zrc20
res, err = msgServer.DeployFungibleCoinZRC20(ctx, types.NewMsgDeployFungibleCoinZRC20(
admin,
sample.EthAddress().Hex(),
chainID,
8,
"bar",
"bar",
common.CoinType_ERC20,
1000000,
))
require.NoError(t, err)
assertContractDeployment(t, sdkk.EvmKeeper, ctx, ethcommon.HexToAddress(res.Address))

foreignCoin, found = k.GetForeignCoins(ctx, res.Address)
require.True(t, found)
require.Equal(t, foreignCoin.CoinType, common.CoinType_ERC20)
require.Contains(t, foreignCoin.Name, "bar")

// gas should remain the same
gas, err = k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID))
require.NoError(t, err)
require.NotEqual(t, res.Address, gas.Hex())
require.Equal(t, gasAddress, gas.Hex())
})

t.Run("should not deploy a new zrc20 if not admin", func(t *testing.T) {
k, ctx, sdkk, _ := keepertest.FungibleKeeper(t)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
chainID := getValidChainID(t)

deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)

// should not deploy a new zrc20 if not admin
_, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, types.NewMsgDeployFungibleCoinZRC20(
sample.AccAddress(),
sample.EthAddress().Hex(),
chainID,
8,
"foo",
"foo",
common.CoinType_Gas,
1000000,
))
require.Error(t, err)
require.ErrorIs(t, err, sdkerrors.ErrUnauthorized)
})

t.Run("should not deploy a new zrc20 with wrong decimal", func(t *testing.T) {
k, ctx, sdkk, zk := keepertest.FungibleKeeper(t)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
admin := sample.AccAddress()
setAdminDeployFungibleCoin(ctx, zk, admin)
chainID := getValidChainID(t)

deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)

// should not deploy a new zrc20 if not admin
_, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, types.NewMsgDeployFungibleCoinZRC20(
admin,
sample.EthAddress().Hex(),
chainID,
256,
"foo",
"foo",
common.CoinType_Gas,
1000000,
))
require.Error(t, err)
require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest)
})

t.Run("should not deploy a new zrc20 with invalid chain ID", func(t *testing.T) {
k, ctx, sdkk, zk := keepertest.FungibleKeeper(t)
k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
admin := sample.AccAddress()
setAdminDeployFungibleCoin(ctx, zk, admin)

deploySystemContracts(t, ctx, k, sdkk.EvmKeeper)

// should not deploy a new zrc20 if not admin
_, err := keeper.NewMsgServerImpl(*k).DeployFungibleCoinZRC20(ctx, types.NewMsgDeployFungibleCoinZRC20(
admin,
sample.EthAddress().Hex(),
9999999,
8,
"foo",
"foo",
common.CoinType_Gas,
1000000,
))
require.Error(t, err)
require.ErrorIs(t, err, observertypes.ErrSupportedChains)
})
}
Loading
Loading