test: wrapped-a0gi-base

This commit is contained in:
MiniFrenchBread 2025-01-10 15:08:01 +08:00
parent 88304562cc
commit 2500f6cb31
10 changed files with 508 additions and 16 deletions

View File

@ -49,6 +49,7 @@ import (
issuancekeeper "github.com/0glabs/0g-chain/x/issuance/keeper"
precisebankkeeper "github.com/0glabs/0g-chain/x/precisebank/keeper"
pricefeedkeeper "github.com/0glabs/0g-chain/x/pricefeed/keeper"
wrappeda0gibasekeeper "github.com/0glabs/0g-chain/x/wrapped-a0gi-base/keeper"
)
var (
@ -118,6 +119,9 @@ func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper { return tAp
func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper { return tApp.feeMarketKeeper }
func (tApp TestApp) GetDASignersKeeper() dasignerskeeper.Keeper { return tApp.dasignersKeeper }
func (tApp TestApp) GetPrecisebankKeeper() precisebankkeeper.Keeper { return tApp.precisebankKeeper }
func (tApp TestApp) GetWrappedA0GIBaseKeeper() wrappeda0gibasekeeper.Keeper {
return tApp.wrappeda0gibaseKeeper
}
func (tApp TestApp) GetKVStoreKey(key string) *storetypes.KVStoreKey {
return tApp.keys[key]

View File

@ -11,7 +11,7 @@ import (
func GetQueryCmd() *cobra.Command {
cmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the dasigners module",
Short: "Querying commands for the wrapped a0gi base module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,

View File

@ -0,0 +1,67 @@
package wrappeda0gibase_test
import (
"testing"
"github.com/stretchr/testify/suite"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/0glabs/0g-chain/app"
wrappeda0gibase "github.com/0glabs/0g-chain/x/wrapped-a0gi-base"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/testutil"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
)
type GenesisTestSuite struct {
testutil.Suite
}
func (suite *GenesisTestSuite) TestInitGenesis() {
// Most genesis validation tests are located in the types directory. The 'invalid' test cases are
// randomly selected subset of those tests.
testCases := []struct {
name string
genState *types.GenesisState
expectPass bool
}{
{
name: "default genesis",
genState: types.DefaultGenesisState(),
expectPass: true,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
// Setup (note: suite.SetupTest is not run before every suite.Run)
suite.App = app.NewTestApp()
suite.Keeper = suite.App.GetWrappedA0GIBaseKeeper()
suite.Ctx = suite.App.NewContext(true, tmproto.Header{})
// Run
var exportedGenState *types.GenesisState
run := func() {
wrappeda0gibase.InitGenesis(suite.Ctx, suite.Keeper, *tc.genState)
exportedGenState = wrappeda0gibase.ExportGenesis(suite.Ctx, suite.Keeper)
}
if tc.expectPass {
suite.Require().NotPanics(run)
} else {
suite.Require().Panics(run)
}
// Check
if tc.expectPass {
expectedJson, err := suite.App.AppCodec().MarshalJSON(tc.genState)
suite.Require().NoError(err)
actualJson, err := suite.App.AppCodec().MarshalJSON(exportedGenState)
suite.Require().NoError(err)
suite.Equal(expectedJson, actualJson)
}
})
}
}
func TestGenesisTestSuite(t *testing.T) {
suite.Run(t, new(GenesisTestSuite))
}

View File

@ -0,0 +1,40 @@
package keeper_test
import (
"testing"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/testutil"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/suite"
)
type KeeperTestSuite struct {
testutil.Suite
}
func (s *KeeperTestSuite) TestSetWA0GIAddress() {
testCases := []struct {
name string
wa0gi common.Address
}{
{
name: "zero address",
wa0gi: common.HexToAddress("0x0000000000000000000000000000000000000000"),
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
s.Keeper.SetWA0GIAddress(s.Ctx, tc.wa0gi)
response, err := s.Keeper.GetWA0GI(s.Ctx, &types.GetWA0GIRequest{})
s.Require().NoError(err)
s.Require().Equal(common.BytesToAddress(response.Address), tc.wa0gi)
})
}
}
func TestKeeperSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -18,10 +18,6 @@ var _ types.MsgServer = &Keeper{}
func (k Keeper) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBurnResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
minter := common.BytesToAddress(msg.Minter)
cap, err := k.getMinterCap(ctx, minter)
if err != nil {
return nil, err
}
supply, err := k.getMinterSupply(ctx, minter)
if err != nil {
return nil, err
@ -29,17 +25,17 @@ func (k Keeper) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBurnR
amount := new(big.Int).SetBytes(msg.Amount)
// check & update mint supply
supply.Sub(supply, amount)
if supply.Cmp(cap) > 0 {
return nil, types.ErrInsufficientMintCap
}
if err = k.setMinterSupply(ctx, minter, supply); err != nil {
return nil, err
if supply.Cmp(big.NewInt(0)) < 0 {
return nil, types.ErrInsufficientMintSupply
}
// burn
c := sdk.NewCoin(precisebanktypes.ExtendedCoinDenom, sdk.NewIntFromBigInt(amount))
if err = k.pbkeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(c)); err != nil {
return nil, err
}
if err = k.setMinterSupply(ctx, minter, supply); err != nil {
return nil, err
}
return &types.MsgBurnResponse{}, nil
}
@ -61,14 +57,14 @@ func (k Keeper) Mint(goCtx context.Context, msg *types.MsgMint) (*types.MsgMintR
if supply.Cmp(cap) > 0 {
return nil, types.ErrInsufficientMintCap
}
if err = k.setMinterSupply(ctx, minter, supply); err != nil {
return nil, err
}
// mint
c := sdk.NewCoin(precisebanktypes.ExtendedCoinDenom, sdk.NewIntFromBigInt(amount))
if err = k.pbkeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(c)); err != nil {
return nil, err
}
if err = k.setMinterSupply(ctx, minter, supply); err != nil {
return nil, err
}
return &types.MsgMintResponse{}, nil
}

View File

@ -0,0 +1,284 @@
package keeper_test
import (
"fmt"
"math/big"
"testing"
precisebanktypes "github.com/0glabs/0g-chain/x/precisebank/types"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/testutil"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/suite"
)
type MsgServerTestSuite struct {
testutil.Suite
}
func (s *MsgServerTestSuite) TestSetWA0GI() {
govAccAddr := s.GovKeeper.GetGovernanceAccount(s.Ctx).GetAddress().String()
testCases := []struct {
name string
req *types.MsgSetWA0GI
expectErr bool
errMsg string
}{
{
name: "invalid signer",
req: &types.MsgSetWA0GI{
Authority: s.Addresses[0].String(),
Address: common.HexToAddress("0x0000000000000000000000000000000000000001").Bytes(),
},
expectErr: true,
errMsg: "expected gov account as only signer for proposal message",
},
{
name: "success",
req: &types.MsgSetWA0GI{
Authority: govAccAddr,
Address: common.HexToAddress("0x0000000000000000000000000000000000000001").Bytes(),
},
expectErr: false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
_, err := s.Keeper.SetWA0GI(sdk.WrapSDKContext(s.Ctx), tc.req)
if tc.expectErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errMsg)
} else {
s.Require().NoError(err)
response, err := s.Keeper.GetWA0GI(s.Ctx, &types.GetWA0GIRequest{})
s.Require().NoError(err)
s.Require().Equal(response.Address, tc.req.Address)
}
})
}
}
func (s *MsgServerTestSuite) TestSetMinterCap() {
testCases := []struct {
name string
caps []struct {
account common.Address
cap *big.Int
}
}{
{
name: "success",
caps: []struct {
account common.Address
cap *big.Int
}{
{
account: common.HexToAddress("0x0000000000000000000000000000000000000000"),
cap: big.NewInt(100000),
},
{
account: common.HexToAddress("0x0000000000000000000000000000000000000001"),
cap: big.NewInt(200000),
},
{
account: common.HexToAddress("0x0000000000000000000000000000000000000002"),
cap: big.NewInt(300000),
},
{
account: common.HexToAddress("0x0000000000000000000000000000000000000003"),
cap: big.NewInt(400000),
},
{
account: common.HexToAddress("0x0000000000000000000000000000000000000002"),
cap: big.NewInt(500000),
},
{
account: common.HexToAddress("0x0000000000000000000000000000000000000001"),
cap: big.NewInt(600000),
},
{
account: common.HexToAddress("0x0000000000000000000000000000000000000000"),
cap: big.NewInt(700000),
},
},
},
}
s.Run("invalid authority", func() {
s.SetupTest()
_, err := s.Keeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: s.Addresses[0].String(),
Minter: common.HexToAddress("0x0000000000000000000000000000000000000000").Bytes(),
Cap: big.NewInt(600000).Bytes(),
})
s.Require().Error(err)
s.Require().Contains(err.Error(), "expected gov account as only signer for proposal message")
})
govAccAddr := s.GovKeeper.GetGovernanceAccount(s.Ctx).GetAddress().String()
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
c := make(map[common.Address]*big.Int)
for _, cap := range tc.caps {
_, err := s.Keeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: govAccAddr,
Minter: cap.account.Bytes(),
Cap: cap.cap.Bytes(),
})
s.Require().NoError(err)
response, err := s.Keeper.MinterSupply(s.Ctx, &types.MinterSupplyRequest{
Address: cap.account.Bytes(),
})
s.Require().NoError(err)
s.Require().Equal(new(big.Int).SetBytes(response.Cap), cap.cap)
c[cap.account] = cap.cap
}
for account, cap := range c {
response, err := s.Keeper.MinterSupply(s.Ctx, &types.MinterSupplyRequest{
Address: account.Bytes(),
})
s.Require().NoError(err)
s.Require().Equal(new(big.Int).SetBytes(response.Cap), cap)
}
})
}
}
type MintBurn struct {
IsMint bool
Minter common.Address
Amount *big.Int
Success bool
}
func (s *MsgServerTestSuite) TestSetMintBurn() {
precisebankKeeper := s.App.GetPrecisebankKeeper()
accountKeeper := s.App.GetAccountKeeper()
moduleAcc := accountKeeper.GetModuleAccount(s.Ctx, types.ModuleName).GetAddress()
govAccAddr := s.GovKeeper.GetGovernanceAccount(s.Ctx).GetAddress().String()
minter1 := common.HexToAddress("0x0000000000000000000000000000000000000001")
minter2 := common.HexToAddress("0x0000000000000000000000000000000000000002")
// set mint cap of minter 1 to 8 a0gi
_, err := s.Keeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: govAccAddr,
Minter: minter1.Bytes(),
Cap: big.NewInt(8e18).Bytes(),
})
s.Require().NoError(err)
// set mint cap of minter 2 to 5 a0gi
_, err = s.Keeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: govAccAddr,
Minter: minter2.Bytes(),
Cap: big.NewInt(5e18).Bytes(),
})
s.Require().NoError(err)
testCases := []MintBurn{
// #0, failed burn
{
IsMint: false,
Minter: minter1,
Amount: big.NewInt(1e18),
Success: false,
},
// #1, mint 5 a0gi by minter 1
{
IsMint: true,
Minter: minter1,
Amount: big.NewInt(5e18),
Success: true,
},
// #2, burn 0.5 a0gi by minter 1
{
IsMint: false,
Minter: minter1,
Amount: big.NewInt(5e17),
Success: true,
},
// #3, mint 0.7 a0gi by minter 2
{
IsMint: true,
Minter: minter2,
Amount: big.NewInt(7e17),
Success: true,
},
// #4, mint 2 a0gi by minter 2
{
IsMint: true,
Minter: minter2,
Amount: big.NewInt(2e18),
Success: true,
},
// #5, burn 0.3 a0gi by minter 2
{
IsMint: false,
Minter: minter1,
Amount: big.NewInt(3e17),
Success: true,
},
// #6, failed to mint 4 a0gi by minter 1
{
IsMint: true,
Minter: minter1,
Amount: big.NewInt(4e18),
Success: false,
},
// #7, mint 3.5 a0gi by minter 1
{
IsMint: true,
Minter: minter1,
Amount: big.NewInt(3e18 + 5e17),
Success: true,
},
}
minted := big.NewInt(0)
supplied := make(map[common.Address]*big.Int)
for id, c := range testCases {
fmt.Println(id)
if c.IsMint {
_, err = s.Keeper.Mint(sdk.WrapSDKContext(s.Ctx), &types.MsgMint{
Minter: c.Minter.Bytes(),
Amount: c.Amount.Bytes(),
})
} else {
_, err = s.Keeper.Burn(sdk.WrapSDKContext(s.Ctx), &types.MsgBurn{
Minter: c.Minter.Bytes(),
Amount: c.Amount.Bytes(),
})
}
if c.Success {
if c.IsMint {
minted.Add(minted, c.Amount)
if amt, ok := supplied[c.Minter]; ok {
amt.Add(amt, c.Amount)
} else {
supplied[c.Minter] = new(big.Int).Set(c.Amount)
}
} else {
minted.Sub(minted, c.Amount)
if amt, ok := supplied[c.Minter]; ok {
amt.Sub(amt, c.Amount)
} else {
supplied[c.Minter] = new(big.Int).Set(c.Amount)
}
}
s.Require().NoError(err)
response, err := s.Keeper.MinterSupply(s.Ctx, &types.MinterSupplyRequest{
Address: c.Minter.Bytes(),
})
s.Require().NoError(err)
s.Require().Equal(supplied[c.Minter].Bytes(), response.Supply)
} else {
s.Require().Error(err)
}
coins := precisebankKeeper.GetBalance(s.Ctx, moduleAcc, precisebanktypes.ExtendedCoinDenom)
s.Require().Equal(coins.Amount.BigInt(), minted)
}
}
func TestMsgServerSuite(t *testing.T) {
suite.Run(t, new(MsgServerTestSuite))
}

View File

@ -0,0 +1,66 @@
package testutil
import (
"strings"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/suite"
"github.com/0glabs/0g-chain/app"
"github.com/0glabs/0g-chain/chaincfg"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/keeper"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
)
// Suite implements a test suite for the module integration tests
type Suite struct {
suite.Suite
Keeper keeper.Keeper
StakingKeeper *stakingkeeper.Keeper
GovKeeper govkeeper.Keeper
App app.TestApp
Ctx sdk.Context
QueryClient types.QueryClient
Addresses []sdk.AccAddress
}
// SetupTest instantiates a new app, keepers, and sets suite state
func (suite *Suite) SetupTest() {
chaincfg.SetSDKConfig()
suite.App = app.NewTestApp()
suite.App.InitializeFromGenesisStates()
suite.Keeper = suite.App.GetWrappedA0GIBaseKeeper()
suite.GovKeeper = suite.App.GetGovKeeper()
suite.StakingKeeper = suite.App.GetStakingKeeper()
// make block header
privkey, _ := ethsecp256k1.GenerateKey()
consAddress := sdk.ConsAddress(privkey.PubKey().Address())
key, err := privkey.ToECDSA()
suite.Assert().NoError(err)
hexAddr := strings.ToLower(crypto.PubkeyToAddress(key.PublicKey).Hex()[2:])
valAddr, err := sdk.ValAddressFromHex(hexAddr)
suite.Assert().NoError(err)
suite.Ctx = suite.App.NewContext(true, tmproto.Header{Height: 1, ChainID: app.TestChainId, ProposerAddress: consAddress})
newValidator, err := stakingtypes.NewValidator(valAddr, privkey.PubKey(), stakingtypes.Description{})
suite.Assert().NoError(err)
err = suite.StakingKeeper.SetValidatorByConsAddr(suite.Ctx, newValidator)
suite.Assert().NoError(err)
suite.StakingKeeper.SetValidator(suite.Ctx, newValidator)
_, accAddresses := app.GeneratePrivKeyAddressPairs(10)
suite.Addresses = accAddresses
// Set query client
queryHelper := suite.App.NewQueryServerTestHelper(suite.Ctx)
queryHandler := suite.Keeper
types.RegisterQueryServer(queryHelper, queryHandler)
suite.QueryClient = types.NewQueryClient(queryHelper)
}

View File

@ -0,0 +1,25 @@
package testutil
import (
"testing"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/assert"
)
// Avoid cluttering test cases with long function names
func I(in int64) sdkmath.Int { return sdkmath.NewInt(in) }
func D(str string) sdk.Dec { return sdk.MustNewDecFromStr(str) }
func C(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
func Cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
func AssertProtoMessageJSON(t *testing.T, cdc codec.Codec, expected proto.Message, actual proto.Message) {
expectedJson, err := cdc.MarshalJSON(expected)
assert.NoError(t, err)
actualJson, err := cdc.MarshalJSON(actual)
assert.NoError(t, err)
assert.Equal(t, string(expectedJson), string(actualJson))
}

View File

@ -5,4 +5,5 @@ import errorsmod "cosmossdk.io/errors"
var (
ErrTxForbidden = errorsmod.Register(ModuleName, 1, "cosmos tx forbidden")
ErrInsufficientMintCap = errorsmod.Register(ModuleName, 2, "insufficient mint cap")
ErrInsufficientMintSupply = errorsmod.Register(ModuleName, 3, "insufficient mint supply")
)

File diff suppressed because one or more lines are too long