Skip to content

Commit

Permalink
test(fungible): increase keeper code coverage (#1128)
Browse files Browse the repository at this point in the history
* initialize system contract

* system contract tests

* update_system_contract_test

* remove foreign coin

* add res and fix event emit

* deploy fungible coin

* gas price

* format imports

* make generate

---------

Co-authored-by: brewmaster012 <[email protected]>
  • Loading branch information
lumtis and brewmaster012 authored Sep 21, 2023
1 parent bc0e26d commit 2765dc4
Show file tree
Hide file tree
Showing 16 changed files with 666 additions and 110 deletions.
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

0 comments on commit 2765dc4

Please sign in to comment.