Compare commits

...

4 Commits

Author SHA1 Message Date
MiniFrenchBread
6ed21ea3fb test: wrapped-a0gi-base precompile 2025-01-10 17:00:09 +08:00
MiniFrenchBread
8b43aa4064 feat: wrapped-a0gi-base precompile 2025-01-10 15:08:18 +08:00
MiniFrenchBread
2500f6cb31 test: wrapped-a0gi-base 2025-01-10 15:08:01 +08:00
MiniFrenchBread
88304562cc refactor: mint 2025-01-08 13:45:12 +08:00
23 changed files with 1232 additions and 158 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

@ -20,7 +20,7 @@ interface IWrappedA0GIBase {
/**
* @dev get the wA0GI address.
*/
function getWA0GI() external returns (address);
function getWA0GI() external view returns (address);
/**
* @dev set the cap for a minter.
@ -37,18 +37,17 @@ interface IWrappedA0GIBase {
function minterSupply(address minter) external view returns (Supply memory);
/**
* @dev mint a0gi to given address directly, add corresponding amount to minter's mint supply.
* @dev mint a0gi to this precompile, add corresponding amount to minter's mint supply.
* If sender's final mint supply exceeds its mint cap, the transaction will revert.
* Can only be called by
*
* Can only be called by WA0GI.
* @param minter minter address
* @param to recipient address
* @param amount amount to mint
*/
function mint(address minter, address to, uint256 amount) external;
function mint(address minter, uint256 amount) external;
/**
* @dev burn given amount of a0gi on behalf of minter, reduce corresponding amount from sender's mint supply.
* Can only be called by WA0GI.
* @param minter minter address
* @param amount amount to burn
*/

View File

@ -27,7 +27,7 @@
"type": "address"
}
],
"stateMutability": "nonpayable",
"stateMutability": "view",
"type": "function"
},
{
@ -37,11 +37,6 @@
"name": "minter",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",

View File

@ -30,7 +30,7 @@ var (
// Wrappeda0gibaseMetaData contains all meta data concerning the Wrappeda0gibase contract.
var Wrappeda0gibaseMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWA0GI\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"}],\"name\":\"minterSupply\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"internalType\":\"structSupply\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWA0GI\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"}],\"name\":\"minterSupply\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"total\",\"type\":\"uint256\"}],\"internalType\":\"structSupply\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
}
// Wrappeda0gibaseABI is the input ABI used to generate the binding from.
@ -179,6 +179,37 @@ func (_Wrappeda0gibase *Wrappeda0gibaseTransactorRaw) Transact(opts *bind.Transa
return _Wrappeda0gibase.Contract.contract.Transact(opts, method, params...)
}
// GetWA0GI is a free data retrieval call binding the contract method 0xa9283a7a.
//
// Solidity: function getWA0GI() view returns(address)
func (_Wrappeda0gibase *Wrappeda0gibaseCaller) GetWA0GI(opts *bind.CallOpts) (common.Address, error) {
var out []interface{}
err := _Wrappeda0gibase.contract.Call(opts, &out, "getWA0GI")
if err != nil {
return *new(common.Address), err
}
out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
return out0, err
}
// GetWA0GI is a free data retrieval call binding the contract method 0xa9283a7a.
//
// Solidity: function getWA0GI() view returns(address)
func (_Wrappeda0gibase *Wrappeda0gibaseSession) GetWA0GI() (common.Address, error) {
return _Wrappeda0gibase.Contract.GetWA0GI(&_Wrappeda0gibase.CallOpts)
}
// GetWA0GI is a free data retrieval call binding the contract method 0xa9283a7a.
//
// Solidity: function getWA0GI() view returns(address)
func (_Wrappeda0gibase *Wrappeda0gibaseCallerSession) GetWA0GI() (common.Address, error) {
return _Wrappeda0gibase.Contract.GetWA0GI(&_Wrappeda0gibase.CallOpts)
}
// MinterSupply is a free data retrieval call binding the contract method 0x95609212.
//
// Solidity: function minterSupply(address minter) view returns((uint256,uint256))
@ -231,44 +262,23 @@ func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) Burn(minter common.Add
return _Wrappeda0gibase.Contract.Burn(&_Wrappeda0gibase.TransactOpts, minter, amount)
}
// GetWA0GI is a paid mutator transaction binding the contract method 0xa9283a7a.
// Mint is a paid mutator transaction binding the contract method 0x40c10f19.
//
// Solidity: function getWA0GI() returns(address)
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) GetWA0GI(opts *bind.TransactOpts) (*types.Transaction, error) {
return _Wrappeda0gibase.contract.Transact(opts, "getWA0GI")
// Solidity: function mint(address minter, uint256 amount) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) Mint(opts *bind.TransactOpts, minter common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.contract.Transact(opts, "mint", minter, amount)
}
// GetWA0GI is a paid mutator transaction binding the contract method 0xa9283a7a.
// Mint is a paid mutator transaction binding the contract method 0x40c10f19.
//
// Solidity: function getWA0GI() returns(address)
func (_Wrappeda0gibase *Wrappeda0gibaseSession) GetWA0GI() (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.GetWA0GI(&_Wrappeda0gibase.TransactOpts)
// Solidity: function mint(address minter, uint256 amount) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseSession) Mint(minter common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, amount)
}
// GetWA0GI is a paid mutator transaction binding the contract method 0xa9283a7a.
// Mint is a paid mutator transaction binding the contract method 0x40c10f19.
//
// Solidity: function getWA0GI() returns(address)
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) GetWA0GI() (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.GetWA0GI(&_Wrappeda0gibase.TransactOpts)
}
// Mint is a paid mutator transaction binding the contract method 0xc6c3bbe6.
//
// Solidity: function mint(address minter, address to, uint256 amount) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) Mint(opts *bind.TransactOpts, minter common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.contract.Transact(opts, "mint", minter, to, amount)
}
// Mint is a paid mutator transaction binding the contract method 0xc6c3bbe6.
//
// Solidity: function mint(address minter, address to, uint256 amount) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseSession) Mint(minter common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, to, amount)
}
// Mint is a paid mutator transaction binding the contract method 0xc6c3bbe6.
//
// Solidity: function mint(address minter, address to, uint256 amount) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) Mint(minter common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, to, amount)
// Solidity: function mint(address minter, uint256 amount) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) Mint(minter common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, amount)
}

View File

@ -0,0 +1,5 @@
package wrappeda0gibase
const (
ErrSenderNotWA0GI = "sender is not WA0GI"
)

View File

@ -0,0 +1,38 @@
package wrappeda0gibase
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)
func (w *WrappedA0giBasePrecompile) GetW0GI(ctx sdk.Context, _ *vm.EVM, method *abi.Method, args []interface{}) ([]byte, error) {
req, err := NewGetW0GIRequest(args)
if err != nil {
return nil, err
}
response, err := w.wrappeda0gibaseKeeper.GetWA0GI(ctx, req)
if err != nil {
return nil, err
}
return method.Outputs.Pack(common.BytesToAddress(response.Address))
}
func (w *WrappedA0giBasePrecompile) MinterSupply(ctx sdk.Context, _ *vm.EVM, method *abi.Method, args []interface{}) ([]byte, error) {
req, err := NewMinterSupplyRequest(args)
if err != nil {
return nil, err
}
response, err := w.wrappeda0gibaseKeeper.MinterSupply(ctx, req)
if err != nil {
return nil, err
}
supply := Supply{
Cap: new(big.Int).SetBytes(response.Cap),
Total: new(big.Int).SetBytes(response.Supply),
}
return method.Outputs.Pack(supply)
}

View File

@ -0,0 +1,147 @@
package wrappeda0gibase_test
import (
"math/big"
wrappeda0gibaseprecompile "github.com/0glabs/0g-chain/precompiles/wrapped-a0gi-base"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
)
func (s *WrappedA0giBaseTestSuite) TestGetW0GI() {
method := wrappeda0gibaseprecompile.WrappedA0GIBaseFunctionGetWA0GI
testCases := []struct {
name string
malleate func() []byte
postCheck func(bz []byte)
gas uint64
expErr bool
errContains string
}{
{
"success",
func() []byte {
input, err := s.abi.Pack(
method,
)
s.Assert().NoError(err)
return input
},
func(data []byte) {
out, err := s.abi.Methods[method].Outputs.Unpack(data)
s.Require().NoError(err, "failed to unpack output")
wa0gi := out[0].(common.Address)
s.Require().Equal(wa0gi, common.HexToAddress(types.DEFAULT_WRAPPED_A0GI))
// fmt.Println(wa0gi)
},
100000,
false,
"",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
bz, err := s.runTx(tc.malleate(), s.signerOne, 10000000)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errContains)
} else {
s.Require().NoError(err)
s.Require().NotNil(bz)
tc.postCheck(bz)
}
})
}
}
func (s *WrappedA0giBaseTestSuite) TestMinterSupply() {
method := wrappeda0gibaseprecompile.WrappedA0GIBaseFunctionMinterSupply
govAccAddr := s.App.GetGovKeeper().GetGovernanceAccount(s.Ctx).GetAddress().String()
testCases := []struct {
name string
malleate func() []byte
postCheck func(bz []byte)
gas uint64
expErr bool
errContains string
}{
{
"non-empty",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerOne.Addr,
)
s.Assert().NoError(err)
return input
},
func(data []byte) {
out, err := s.abi.Methods[method].Outputs.Unpack(data)
s.Require().NoError(err, "failed to unpack output")
wa0gi := out[0].(wrappeda0gibaseprecompile.Supply)
s.Require().Equal(wa0gi.Cap, big.NewInt(8e18))
s.Require().Equal(wa0gi.Total, big.NewInt(1e18))
// fmt.Println(wa0gi)
},
100000,
false,
"",
}, {
"empty",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerTwo.Addr,
)
s.Assert().NoError(err)
return input
},
func(data []byte) {
out, err := s.abi.Methods[method].Outputs.Unpack(data)
s.Require().NoError(err, "failed to unpack output")
supply := out[0].(wrappeda0gibaseprecompile.Supply)
s.Require().Equal(supply.Cap.Bytes(), big.NewInt(0).Bytes())
s.Require().Equal(supply.Total.Bytes(), big.NewInt(0).Bytes())
// fmt.Println(wa0gi)
},
100000,
false,
"",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
s.wa0gibasekeeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: govAccAddr,
Minter: s.signerOne.Addr.Bytes(),
Cap: big.NewInt(8e18).Bytes(),
})
s.wa0gibasekeeper.Mint(sdk.WrapSDKContext(s.Ctx), &types.MsgMint{
Minter: s.signerOne.Addr.Bytes(),
Amount: big.NewInt(1e18).Bytes(),
})
bz, err := s.runTx(tc.malleate(), s.signerOne, 10000000)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errContains)
} else {
s.Require().NoError(err)
s.Require().NotNil(bz)
tc.postCheck(bz)
}
})
}
}

View File

@ -0,0 +1,62 @@
package wrappeda0gibase
import (
"errors"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/evmos/ethermint/x/evm/statedb"
)
func (w *WrappedA0giBasePrecompile) Mint(
ctx sdk.Context,
evm *vm.EVM,
stateDB *statedb.StateDB,
contract *vm.Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
msg, err := NewMsgMint(args)
if err != nil {
return nil, err
}
// validation
wa0gi := common.BytesToAddress(w.wrappeda0gibaseKeeper.GetWA0GIAddress(ctx))
if contract.CallerAddress != wa0gi {
return nil, errors.New(ErrSenderNotWA0GI)
}
// execute
_, err = w.wrappeda0gibaseKeeper.Mint(sdk.WrapSDKContext(ctx), msg)
if err != nil {
return nil, err
}
return method.Outputs.Pack()
}
func (w *WrappedA0giBasePrecompile) Burn(
ctx sdk.Context,
evm *vm.EVM,
stateDB *statedb.StateDB,
contract *vm.Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
msg, err := NewMsgBurn(args)
if err != nil {
return nil, err
}
// validation
wa0gi := common.BytesToAddress(w.wrappeda0gibaseKeeper.GetWA0GIAddress(ctx))
if contract.CallerAddress != wa0gi {
return nil, errors.New(ErrSenderNotWA0GI)
}
// execute
_, err = w.wrappeda0gibaseKeeper.Burn(sdk.WrapSDKContext(ctx), msg)
if err != nil {
return nil, err
}
return method.Outputs.Pack()
}

View File

@ -0,0 +1,218 @@
package wrappeda0gibase_test
import (
"fmt"
"math/big"
wrappeda0gibaseprecompile "github.com/0glabs/0g-chain/precompiles/wrapped-a0gi-base"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func (s *WrappedA0giBaseTestSuite) TestMint() {
method := wrappeda0gibaseprecompile.WrappedA0GIBaseFunctionMint
govAccAddr := s.App.GetGovKeeper().GetGovernanceAccount(s.Ctx).GetAddress().String()
testCases := []struct {
name string
malleate func() []byte
postCheck func()
gas uint64
expErr bool
errContains string
isSignerOne bool
}{
{
"success",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerOne.Addr,
big.NewInt(1e18),
)
s.Assert().NoError(err)
return input
},
func() {
supply, err := s.wa0gibasekeeper.MinterSupply(s.Ctx, &types.MinterSupplyRequest{
Address: s.signerOne.Addr.Bytes(),
})
s.Assert().NoError(err)
s.Require().Equal(supply.Cap, big.NewInt(8e18).Bytes())
s.Require().Equal(supply.Supply, big.NewInt(1e18).Bytes())
// fmt.Println(wa0gi)
},
100000,
false,
"",
true,
}, {
"fail",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerOne.Addr,
big.NewInt(9e18),
)
s.Assert().NoError(err)
return input
},
func() {},
100000,
true,
"insufficient mint cap",
true,
}, {
"invalid sender",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerTwo.Addr,
big.NewInt(9e18),
)
s.Assert().NoError(err)
return input
},
func() {},
100000,
true,
"sender is not WA0GI",
false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
fmt.Println(s.signerOne.Addr)
s.wa0gibasekeeper.SetWA0GIAddress(s.Ctx, s.signerOne.Addr)
s.wa0gibasekeeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: govAccAddr,
Minter: s.signerOne.Addr.Bytes(),
Cap: big.NewInt(8e18).Bytes(),
})
var err error
if tc.isSignerOne {
_, err = s.runTx(tc.malleate(), s.signerOne, 10000000)
} else {
_, err = s.runTx(tc.malleate(), s.signerTwo, 10000000)
}
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errContains)
} else {
s.Require().NoError(err)
tc.postCheck()
}
})
}
}
func (s *WrappedA0giBaseTestSuite) TestBurn() {
method := wrappeda0gibaseprecompile.WrappedA0GIBaseFunctionBurn
govAccAddr := s.App.GetGovKeeper().GetGovernanceAccount(s.Ctx).GetAddress().String()
testCases := []struct {
name string
malleate func() []byte
postCheck func()
gas uint64
expErr bool
errContains string
isSignerOne bool
}{
{
"success",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerOne.Addr,
big.NewInt(1e18),
)
s.Assert().NoError(err)
return input
},
func() {
supply, err := s.wa0gibasekeeper.MinterSupply(s.Ctx, &types.MinterSupplyRequest{
Address: s.signerOne.Addr.Bytes(),
})
s.Assert().NoError(err)
s.Require().Equal(supply.Cap, big.NewInt(8e18).Bytes())
s.Require().Equal(supply.Supply, big.NewInt(3e18).Bytes())
// fmt.Println(wa0gi)
},
100000,
false,
"",
true,
}, {
"fail",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerOne.Addr,
big.NewInt(9e18),
)
s.Assert().NoError(err)
return input
},
func() {},
100000,
true,
"insufficient mint supply",
true,
}, {
"invalid sender",
func() []byte {
input, err := s.abi.Pack(
method,
s.signerTwo.Addr,
big.NewInt(9e18),
)
s.Assert().NoError(err)
return input
},
func() {},
100000,
true,
"sender is not WA0GI",
false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
fmt.Println(s.signerOne.Addr)
s.wa0gibasekeeper.SetWA0GIAddress(s.Ctx, s.signerOne.Addr)
s.wa0gibasekeeper.SetMinterCap(sdk.WrapSDKContext(s.Ctx), &types.MsgSetMintCap{
Authority: govAccAddr,
Minter: s.signerOne.Addr.Bytes(),
Cap: big.NewInt(8e18).Bytes(),
})
s.wa0gibasekeeper.Mint(sdk.WrapSDKContext(s.Ctx), &types.MsgMint{
Minter: s.signerOne.Addr.Bytes(),
Amount: big.NewInt(4e18).Bytes(),
})
var err error
if tc.isSignerOne {
_, err = s.runTx(tc.malleate(), s.signerOne, 10000000)
} else {
_, err = s.runTx(tc.malleate(), s.signerTwo, 10000000)
}
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errContains)
} else {
s.Require().NoError(err)
tc.postCheck()
}
})
}
}

View File

@ -1,8 +1,51 @@
package wrappeda0gibase
import "math/big"
import (
"fmt"
"math/big"
precompiles_common "github.com/0glabs/0g-chain/precompiles/common"
"github.com/0glabs/0g-chain/x/wrapped-a0gi-base/types"
"github.com/ethereum/go-ethereum/common"
)
type Supply = struct {
Cap *big.Int "json:\"cap\""
Total *big.Int "json:\"total\""
}
func NewGetW0GIRequest(args []interface{}) (*types.GetWA0GIRequest, error) {
if len(args) != 0 {
return nil, fmt.Errorf(precompiles_common.ErrInvalidNumberOfArgs, 0, len(args))
}
return &types.GetWA0GIRequest{}, nil
}
func NewMinterSupplyRequest(args []interface{}) (*types.MinterSupplyRequest, error) {
if len(args) != 1 {
return nil, fmt.Errorf(precompiles_common.ErrInvalidNumberOfArgs, 1, len(args))
}
return &types.MinterSupplyRequest{
Address: args[0].(common.Address).Bytes(),
}, nil
}
func NewMsgMint(args []interface{}) (*types.MsgMint, error) {
if len(args) != 2 {
return nil, fmt.Errorf(precompiles_common.ErrInvalidNumberOfArgs, 1, len(args))
}
return &types.MsgMint{
Minter: args[0].(common.Address).Bytes(),
Amount: args[1].(*big.Int).Bytes(),
}, nil
}
func NewMsgBurn(args []interface{}) (*types.MsgBurn, error) {
if len(args) != 2 {
return nil, fmt.Errorf(precompiles_common.ErrInvalidNumberOfArgs, 1, len(args))
}
return &types.MsgBurn{
Minter: args[0].(common.Address).Bytes(),
Amount: args[1].(*big.Int).Bytes(),
}, nil
}

View File

@ -5,7 +5,7 @@ import (
precompiles_common "github.com/0glabs/0g-chain/precompiles/common"
wrappeda0gibasekeeper "github.com/0glabs/0g-chain/x/wrapped-a0gi-base/keeper"
"github.com/cosmos/cosmos-sdk/store/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
@ -13,6 +13,13 @@ import (
const (
PrecompileAddress = "0x0000000000000000000000000000000000001002"
// txs
WrappedA0GIBaseFunctionMint = "mint"
WrappedA0GIBaseFunctionBurn = "burn"
// queries
WrappedA0GIBaseFunctionGetWA0GI = "getWA0GI"
WrappedA0GIBaseFunctionMinterSupply = "minterSupply"
)
var _ vm.PrecompiledContract = &WrappedA0giBasePrecompile{}
@ -25,17 +32,23 @@ type WrappedA0giBasePrecompile struct {
// Abi implements common.PrecompileCommon.
func (w *WrappedA0giBasePrecompile) Abi() *abi.ABI {
panic("unimplemented")
return &w.abi
}
// IsTx implements common.PrecompileCommon.
func (w *WrappedA0giBasePrecompile) IsTx(string) bool {
panic("unimplemented")
func (w *WrappedA0giBasePrecompile) IsTx(method string) bool {
switch method {
case WrappedA0GIBaseFunctionMint,
WrappedA0GIBaseFunctionBurn:
return true
default:
return false
}
}
// KVGasConfig implements common.PrecompileCommon.
func (w *WrappedA0giBasePrecompile) KVGasConfig() types.GasConfig {
panic("unimplemented")
func (w *WrappedA0giBasePrecompile) KVGasConfig() storetypes.GasConfig {
return storetypes.KVGasConfig()
}
// Address implements vm.PrecompiledContract.
@ -45,7 +58,7 @@ func (w *WrappedA0giBasePrecompile) Address() common.Address {
// RequiredGas implements vm.PrecompiledContract.
func (w *WrappedA0giBasePrecompile) RequiredGas(input []byte) uint64 {
panic("unimplemented")
return 0
}
func NewWrappedA0giBasePrecompile(wrappeda0gibaseKeeper wrappeda0gibasekeeper.Keeper) (*WrappedA0giBasePrecompile, error) {
@ -61,5 +74,33 @@ func NewWrappedA0giBasePrecompile(wrappeda0gibaseKeeper wrappeda0gibasekeeper.Ke
// Run implements vm.PrecompiledContract.
func (w *WrappedA0giBasePrecompile) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) {
panic("unimplemented")
ctx, stateDB, method, initialGas, args, err := precompiles_common.InitializePrecompileCall(w, evm, contract, readonly)
if err != nil {
return nil, err
}
var bz []byte
switch method.Name {
// queries
case WrappedA0GIBaseFunctionGetWA0GI:
bz, err = w.GetW0GI(ctx, evm, method, args)
case WrappedA0GIBaseFunctionMinterSupply:
bz, err = w.MinterSupply(ctx, evm, method, args)
// txs
case WrappedA0GIBaseFunctionMint:
bz, err = w.Mint(ctx, evm, stateDB, contract, method, args)
case WrappedA0GIBaseFunctionBurn:
bz, err = w.Burn(ctx, evm, stateDB, contract, method, args)
}
if err != nil {
return nil, err
}
cost := ctx.GasMeter().GasConsumed() - initialGas
if !contract.UseGas(cost) {
return nil, vm.ErrOutOfGas
}
return bz, nil
}

View File

@ -0,0 +1,80 @@
package wrappeda0gibase_test
import (
"math/big"
"strings"
"testing"
"github.com/0glabs/0g-chain/precompiles/testutil"
wrappeda0gibaseprecompile "github.com/0glabs/0g-chain/precompiles/wrapped-a0gi-base"
wrappeda0gibasekeeper "github.com/0glabs/0g-chain/x/wrapped-a0gi-base/keeper"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/evmos/ethermint/x/evm/statedb"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/stretchr/testify/suite"
)
type WrappedA0giBaseTestSuite struct {
testutil.PrecompileTestSuite
abi abi.ABI
addr common.Address
wa0gibasekeeper wrappeda0gibasekeeper.Keeper
wa0gibase *wrappeda0gibaseprecompile.WrappedA0giBasePrecompile
signerOne *testutil.TestSigner
signerTwo *testutil.TestSigner
}
func (suite *WrappedA0giBaseTestSuite) SetupTest() {
suite.PrecompileTestSuite.SetupTest()
suite.wa0gibasekeeper = suite.App.GetWrappedA0GIBaseKeeper()
suite.addr = common.HexToAddress(wrappeda0gibaseprecompile.PrecompileAddress)
precompiles := suite.EvmKeeper.GetPrecompiles()
precompile, ok := precompiles[suite.addr]
suite.Assert().EqualValues(ok, true)
suite.wa0gibase = precompile.(*wrappeda0gibaseprecompile.WrappedA0giBasePrecompile)
suite.signerOne = suite.GenSigner()
suite.signerTwo = suite.GenSigner()
abi, err := abi.JSON(strings.NewReader(wrappeda0gibaseprecompile.Wrappeda0gibaseABI))
suite.Assert().NoError(err)
suite.abi = abi
}
func (suite *WrappedA0giBaseTestSuite) runTx(input []byte, signer *testutil.TestSigner, gas uint64) ([]byte, error) {
contract := vm.NewPrecompile(vm.AccountRef(signer.Addr), vm.AccountRef(suite.addr), big.NewInt(0), gas)
contract.Input = input
msgEthereumTx := evmtypes.NewTx(suite.EvmKeeper.ChainID(), 0, &suite.addr, big.NewInt(0), gas, big.NewInt(0), big.NewInt(0), big.NewInt(0), input, nil)
msgEthereumTx.From = signer.HexAddr
err := msgEthereumTx.Sign(suite.EthSigner, signer.Signer)
suite.Assert().NoError(err, "failed to sign Ethereum message")
proposerAddress := suite.Ctx.BlockHeader().ProposerAddress
cfg, err := suite.EvmKeeper.EVMConfig(suite.Ctx, proposerAddress, suite.EvmKeeper.ChainID())
suite.Assert().NoError(err, "failed to instantiate EVM config")
msg, err := msgEthereumTx.AsMessage(suite.EthSigner, big.NewInt(0))
suite.Assert().NoError(err, "failed to instantiate Ethereum message")
evm := suite.EvmKeeper.NewEVM(suite.Ctx, msg, cfg, nil, suite.Statedb)
precompiles := suite.EvmKeeper.GetPrecompiles()
evm.WithPrecompiles(precompiles, []common.Address{suite.addr})
bz, err := suite.wa0gibase.Run(evm, contract, false)
if err == nil {
evm.StateDB.(*statedb.StateDB).Commit()
}
return bz, err
}
func TestWrappedA0giBaseTestSuite(t *testing.T) {
suite.Run(t, new(WrappedA0giBaseTestSuite))
}

View File

@ -33,8 +33,7 @@ message MsgSetMintCapResponse {}
message MsgMint {
bytes minter = 1;
bytes to = 2;
bytes amount = 3; // big endian
bytes amount = 2; // big endian
}
message MsgMintResponse {}

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,21 +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 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
}
// transfer & burn
c := sdk.NewCoin(precisebanktypes.ExtendedCoinDenom, sdk.NewIntFromBigInt(amount))
burner := sdk.AccAddress(minter.Bytes())
if err = k.pbkeeper.SendCoinsFromAccountToModule(ctx, burner, types.ModuleName, sdk.NewCoins(c)); err != nil {
return nil, err
}
if err = k.pbkeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(c)); err != nil {
return nil, err
}
return &types.MsgBurnResponse{}, nil
}
@ -65,16 +57,12 @@ 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 & transfer
// 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
}
recipient := sdk.AccAddress(common.BytesToAddress(msg.To).Bytes())
if err = k.pbkeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, sdk.NewCoins(c)); err != nil {
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

@ -3,6 +3,7 @@ package types
import errorsmod "cosmossdk.io/errors"
var (
ErrTxForbidden = errorsmod.Register(ModuleName, 1, "cosmos tx forbidden")
ErrInsufficientMintCap = errorsmod.Register(ModuleName, 2, "insufficient mint cap")
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

View File

@ -181,8 +181,7 @@ var xxx_messageInfo_MsgSetMintCapResponse proto.InternalMessageInfo
type MsgMint struct {
Minter []byte `protobuf:"bytes,1,opt,name=minter,proto3" json:"minter,omitempty"`
To []byte `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"`
Amount []byte `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount,omitempty"`
Amount []byte `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"`
}
func (m *MsgMint) Reset() { *m = MsgMint{} }
@ -342,35 +341,34 @@ func init() {
func init() { proto.RegisterFile("zgc/wrappeda0gibase/tx.proto", fileDescriptor_f80bf93a1fc022d3) }
var fileDescriptor_f80bf93a1fc022d3 = []byte{
// 436 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xcf, 0x8b, 0xd3, 0x40,
0x14, 0xc7, 0x93, 0x54, 0x76, 0xdd, 0xe7, 0xfa, 0x2b, 0xeb, 0x6a, 0x36, 0x94, 0x50, 0x82, 0x87,
0x22, 0x34, 0x13, 0xd4, 0x8b, 0x47, 0x57, 0x44, 0x56, 0xc8, 0x25, 0x82, 0x0b, 0x1e, 0x94, 0x49,
0x3a, 0x4e, 0x03, 0x9b, 0x4c, 0xc8, 0x4c, 0x70, 0xbb, 0x7f, 0x85, 0x7f, 0xd6, 0x1e, 0x7b, 0x11,
0x3c, 0x6a, 0xfb, 0x8f, 0xc8, 0x24, 0x93, 0x34, 0x95, 0xa6, 0xbd, 0xcd, 0xfb, 0xbe, 0xef, 0xfb,
0x3c, 0xf8, 0x0e, 0x0f, 0x86, 0x37, 0x34, 0x46, 0x3f, 0x0a, 0x9c, 0xe7, 0x64, 0x8a, 0x7d, 0x9a,
0x44, 0x98, 0x13, 0x24, 0xae, 0xbd, 0xbc, 0x60, 0x82, 0x99, 0x27, 0x37, 0x34, 0xf6, 0xfe, 0xeb,
0xda, 0x67, 0x31, 0xe3, 0x29, 0xe3, 0xdf, 0x2a, 0x0b, 0xaa, 0x8b, 0xda, 0x6f, 0x3f, 0xa1, 0x8c,
0xb2, 0x5a, 0x97, 0x2f, 0xa5, 0x9e, 0x51, 0xc6, 0xe8, 0x15, 0x41, 0x55, 0x15, 0x95, 0xdf, 0x11,
0xce, 0xe6, 0x75, 0xcb, 0x7d, 0x0f, 0xf7, 0x02, 0x4e, 0x3f, 0x11, 0x71, 0xf9, 0xd6, 0xff, 0x70,
0x61, 0x0e, 0xe1, 0x08, 0x97, 0x62, 0xc6, 0x8a, 0x44, 0xcc, 0x2d, 0x7d, 0xa4, 0x8f, 0x8f, 0xc2,
0xb5, 0x60, 0x5a, 0x70, 0x88, 0xa7, 0xd3, 0x82, 0x70, 0x6e, 0x19, 0x23, 0x7d, 0x7c, 0x1c, 0x36,
0xa5, 0x7b, 0x0a, 0x27, 0x1d, 0x4c, 0x48, 0x78, 0xce, 0x32, 0x4e, 0xdc, 0x4b, 0xb8, 0x5f, 0xcb,
0x41, 0x92, 0x89, 0x77, 0x38, 0xdf, 0xc3, 0x7f, 0x0a, 0x07, 0x69, 0x92, 0x09, 0x52, 0x28, 0xbc,
0xaa, 0xcc, 0x47, 0x30, 0x88, 0x71, 0x6e, 0x0d, 0x2a, 0x51, 0x3e, 0xdd, 0x67, 0x70, 0xba, 0x01,
0x6e, 0x37, 0x5e, 0xc0, 0x61, 0xc0, 0xa9, 0x54, 0x3b, 0x34, 0x7d, 0x83, 0xf6, 0x00, 0x0c, 0xc1,
0xd4, 0x06, 0x43, 0x30, 0xe9, 0xc3, 0x29, 0x2b, 0x33, 0xa1, 0x16, 0xa8, 0xca, 0x7d, 0x0c, 0x0f,
0x15, 0xaa, 0xa5, 0xbf, 0xa9, 0xe8, 0xe7, 0x65, 0x91, 0xf5, 0xd2, 0xd7, 0x34, 0x63, 0x0b, 0x4d,
0x8e, 0x36, 0xb4, 0x97, 0xbf, 0x0c, 0x18, 0x04, 0x9c, 0x9a, 0x9f, 0xe1, 0x6e, 0xfb, 0x01, 0x23,
0x6f, 0xcb, 0x8f, 0x7b, 0x9d, 0x6c, 0xed, 0xf1, 0x3e, 0x47, 0xc3, 0x37, 0xbf, 0xc2, 0xb1, 0x4a,
0x88, 0x14, 0x32, 0x7c, 0x77, 0xc7, 0xa4, 0xca, 0xd1, 0x7e, 0xb1, 0xdf, 0xd3, 0xf2, 0x3f, 0xc2,
0x9d, 0x2a, 0xe8, 0x61, 0xdf, 0x8c, 0xec, 0xda, 0xcf, 0x77, 0x75, 0xbb, 0xac, 0x2a, 0xd6, 0x5e,
0x96, 0xec, 0xf6, 0xb3, 0xba, 0xb9, 0x9e, 0x87, 0xb7, 0x7f, 0x1d, 0xed, 0x76, 0xe9, 0xe8, 0x8b,
0xa5, 0xa3, 0xff, 0x59, 0x3a, 0xfa, 0xcf, 0x95, 0xa3, 0x2d, 0x56, 0x8e, 0xf6, 0x7b, 0xe5, 0x68,
0x5f, 0x5e, 0xd3, 0x44, 0xcc, 0xca, 0xc8, 0x8b, 0x59, 0x8a, 0x7c, 0x7a, 0x85, 0x23, 0x8e, 0x7c,
0x3a, 0x89, 0x67, 0x38, 0xc9, 0xd0, 0x75, 0x73, 0x89, 0x13, 0x09, 0x9f, 0xd4, 0xb7, 0x38, 0xcf,
0x09, 0x8f, 0x0e, 0xaa, 0x73, 0x79, 0xf5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x19, 0x0a, 0x77,
0xaf, 0x03, 0x00, 0x00,
// 421 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x4f, 0xab, 0xd3, 0x40,
0x14, 0xc5, 0x93, 0x57, 0xe9, 0xf3, 0x5d, 0x2b, 0x6a, 0x6a, 0x6b, 0x1a, 0x4a, 0x28, 0xc1, 0x45,
0x11, 0x9a, 0x09, 0xea, 0xc6, 0xa5, 0x15, 0x11, 0x85, 0x6c, 0x22, 0x58, 0x70, 0xa1, 0x4c, 0xd2,
0x71, 0x1a, 0x68, 0x32, 0x21, 0x33, 0xc1, 0xb6, 0x9f, 0xc2, 0x8f, 0xd5, 0x65, 0x37, 0x82, 0x4b,
0x6d, 0xbf, 0x88, 0x4c, 0xfe, 0xd4, 0xb4, 0xd8, 0x16, 0xde, 0x2e, 0xe7, 0x9c, 0x7b, 0x7f, 0x03,
0x27, 0x5c, 0xe8, 0xaf, 0x68, 0x80, 0xbe, 0xa7, 0x38, 0x49, 0xc8, 0x14, 0x3b, 0x34, 0xf4, 0x31,
0x27, 0x48, 0x2c, 0xec, 0x24, 0x65, 0x82, 0x69, 0xed, 0x15, 0x0d, 0xec, 0xa3, 0xd4, 0xe8, 0x05,
0x8c, 0x47, 0x8c, 0x7f, 0xcd, 0x47, 0x50, 0x21, 0x8a, 0x79, 0xe3, 0x31, 0x65, 0x94, 0x15, 0xbe,
0xfc, 0x2a, 0xdd, 0x1e, 0x65, 0x8c, 0xce, 0x09, 0xca, 0x95, 0x9f, 0x7d, 0x43, 0x38, 0x5e, 0x16,
0x91, 0xf5, 0x16, 0xee, 0xb9, 0x9c, 0x7e, 0x24, 0x62, 0xf2, 0xda, 0x79, 0xf7, 0x5e, 0xeb, 0xc3,
0x0d, 0xce, 0xc4, 0x8c, 0xa5, 0xa1, 0x58, 0xea, 0xea, 0x40, 0x1d, 0xde, 0x78, 0xff, 0x0c, 0x4d,
0x87, 0x6b, 0x3c, 0x9d, 0xa6, 0x84, 0x73, 0xfd, 0x6a, 0xa0, 0x0e, 0x5b, 0x5e, 0x25, 0xad, 0x0e,
0xb4, 0x6b, 0x18, 0x8f, 0xf0, 0x84, 0xc5, 0x9c, 0x58, 0x13, 0xb8, 0x5f, 0xd8, 0x6e, 0x18, 0x8b,
0x37, 0x38, 0xb9, 0xc0, 0xef, 0x42, 0x33, 0x0a, 0x63, 0x41, 0xd2, 0x12, 0x5f, 0x2a, 0xed, 0x21,
0x34, 0x02, 0x9c, 0xe8, 0x8d, 0xdc, 0x94, 0x9f, 0xd6, 0x13, 0xe8, 0x1c, 0x80, 0xf7, 0x2f, 0xbe,
0x82, 0x6b, 0x97, 0x53, 0xe9, 0xd6, 0x68, 0xea, 0x01, 0xad, 0x0b, 0x4d, 0x1c, 0xb1, 0x2c, 0x16,
0xd5, 0x2b, 0x85, 0xb2, 0x1e, 0xc1, 0x83, 0x72, 0xf5, 0x88, 0x36, 0xce, 0xd2, 0xf8, 0x96, 0x34,
0xb9, 0x5a, 0xd1, 0x9e, 0xff, 0xbc, 0x82, 0x86, 0xcb, 0xa9, 0xf6, 0x09, 0xee, 0xee, 0x0b, 0x1f,
0xd8, 0xff, 0xf9, 0xc3, 0x76, 0xad, 0x4b, 0x63, 0x78, 0x69, 0xa2, 0xe2, 0x6b, 0x5f, 0xa0, 0x55,
0x36, 0x42, 0x52, 0x59, 0xb6, 0x75, 0x66, 0xb3, 0xec, 0xcd, 0x78, 0x76, 0x79, 0x66, 0xcf, 0xff,
0x00, 0x77, 0xf2, 0x62, 0xfb, 0xa7, 0x76, 0x64, 0x6a, 0x3c, 0x3d, 0x97, 0xd6, 0x59, 0x79, 0xad,
0x27, 0x59, 0x32, 0x3d, 0xcd, 0xaa, 0xf7, 0x3a, 0xf6, 0xd6, 0x7f, 0x4c, 0x65, 0xbd, 0x35, 0xd5,
0xcd, 0xd6, 0x54, 0x7f, 0x6f, 0x4d, 0xf5, 0xc7, 0xce, 0x54, 0x36, 0x3b, 0x53, 0xf9, 0xb5, 0x33,
0x95, 0xcf, 0x2f, 0x69, 0x28, 0x66, 0x99, 0x6f, 0x07, 0x2c, 0x42, 0x0e, 0x9d, 0x63, 0x9f, 0x23,
0x87, 0x8e, 0x82, 0x19, 0x0e, 0x63, 0xb4, 0xa8, 0x2e, 0x6f, 0x24, 0xe1, 0xa3, 0xe2, 0xf6, 0x96,
0x09, 0xe1, 0x7e, 0x33, 0x3f, 0x8f, 0x17, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x6f, 0x43, 0x23,
0x4d, 0x9f, 0x03, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -713,13 +711,6 @@ func (m *MsgMint) MarshalToSizedBuffer(dAtA []byte) (int, error) {
copy(dAtA[i:], m.Amount)
i = encodeVarintTx(dAtA, i, uint64(len(m.Amount)))
i--
dAtA[i] = 0x1a
}
if len(m.To) > 0 {
i -= len(m.To)
copy(dAtA[i:], m.To)
i = encodeVarintTx(dAtA, i, uint64(len(m.To)))
i--
dAtA[i] = 0x12
}
if len(m.Minter) > 0 {
@ -892,10 +883,6 @@ func (m *MsgMint) Size() (n int) {
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
l = len(m.To)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
l = len(m.Amount)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
@ -1374,40 +1361,6 @@ func (m *MsgMint) Unmarshal(dAtA []byte) error {
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field To", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.To = append(m.To[:0], dAtA[iNdEx:postIndex]...)
if m.To == nil {
m.To = []byte{}
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
}