feat: set mint cap

This commit is contained in:
MiniFrenchBread 2025-04-02 18:26:10 +08:00
parent 18fbd2a814
commit d5275fa798
15 changed files with 116 additions and 685 deletions

1
.gitignore vendored
View file

@ -46,3 +46,4 @@ tests/spec-tests/
# Precompiles
core/vm/Precompiles/interfaces/node_modules
core/vm/Precompiles/interfaces/build

View file

@ -83,5 +83,28 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "minter",
"type": "address"
},
{
"internalType": "uint256",
"name": "cap",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "initialSupply",
"type": "uint256"
}
],
"name": "setMinterCap",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

View file

@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/377589efa765dec208356377872d3755.json"
}

View file

@ -1,10 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "BN254",
"sourceName": "contracts/IDASigners.sol",
"abi": [],
"bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220abc43d74fec9de74f3b7a60ee2e0337c23369163d8fb7a1e1cb0037a16d8abfb64736f6c63430008140033",
"deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220abc43d74fec9de74f3b7a60ee2e0337c23369163d8fb7a1e1cb0037a16d8abfb64736f6c63430008140033",
"linkReferences": {},
"deployedLinkReferences": {}
}

View file

@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/377589efa765dec208356377872d3755.json"
}

View file

@ -1,484 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IDASigners",
"sourceName": "contracts/IDASigners.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"components": [
{
"internalType": "uint256",
"name": "X",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "Y",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct BN254.G1Point",
"name": "pkG1",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256[2]",
"name": "X",
"type": "uint256[2]"
},
{
"internalType": "uint256[2]",
"name": "Y",
"type": "uint256[2]"
}
],
"indexed": false,
"internalType": "struct BN254.G2Point",
"name": "pkG2",
"type": "tuple"
}
],
"name": "NewSigner",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"indexed": false,
"internalType": "string",
"name": "socket",
"type": "string"
}
],
"name": "SocketUpdated",
"type": "event"
},
{
"inputs": [],
"name": "epochNumber",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_epoch",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_quorumId",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_quorumBitmap",
"type": "bytes"
}
],
"name": "getAggPkG1",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "X",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "Y",
"type": "uint256"
}
],
"internalType": "struct BN254.G1Point",
"name": "aggPkG1",
"type": "tuple"
},
{
"internalType": "uint256",
"name": "total",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "hit",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_epoch",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_quorumId",
"type": "uint256"
}
],
"name": "getQuorum",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_epoch",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_quorumId",
"type": "uint256"
},
{
"internalType": "uint32",
"name": "_rowIndex",
"type": "uint32"
}
],
"name": "getQuorumRow",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "_account",
"type": "address[]"
}
],
"name": "getSigner",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"internalType": "string",
"name": "socket",
"type": "string"
},
{
"components": [
{
"internalType": "uint256",
"name": "X",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "Y",
"type": "uint256"
}
],
"internalType": "struct BN254.G1Point",
"name": "pkG1",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256[2]",
"name": "X",
"type": "uint256[2]"
},
{
"internalType": "uint256[2]",
"name": "Y",
"type": "uint256[2]"
}
],
"internalType": "struct BN254.G2Point",
"name": "pkG2",
"type": "tuple"
}
],
"internalType": "struct IDASigners.SignerDetail[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_account",
"type": "address"
}
],
"name": "isSigner",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "makeEpoch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "params",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "tokensPerVote",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxVotesPerSigner",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxQuorums",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "epochBlocks",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "encodedSlices",
"type": "uint256"
}
],
"internalType": "struct IDASigners.Params",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_epoch",
"type": "uint256"
}
],
"name": "quorumCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "X",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "Y",
"type": "uint256"
}
],
"internalType": "struct BN254.G1Point",
"name": "_signature",
"type": "tuple"
}
],
"name": "registerNextEpoch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "signer",
"type": "address"
},
{
"internalType": "string",
"name": "socket",
"type": "string"
},
{
"components": [
{
"internalType": "uint256",
"name": "X",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "Y",
"type": "uint256"
}
],
"internalType": "struct BN254.G1Point",
"name": "pkG1",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256[2]",
"name": "X",
"type": "uint256[2]"
},
{
"internalType": "uint256[2]",
"name": "Y",
"type": "uint256[2]"
}
],
"internalType": "struct BN254.G2Point",
"name": "pkG2",
"type": "tuple"
}
],
"internalType": "struct IDASigners.SignerDetail",
"name": "_signer",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "X",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "Y",
"type": "uint256"
}
],
"internalType": "struct BN254.G1Point",
"name": "_signature",
"type": "tuple"
}
],
"name": "registerSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_account",
"type": "address"
},
{
"internalType": "uint256",
"name": "_epoch",
"type": "uint256"
}
],
"name": "registeredEpoch",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_socket",
"type": "string"
}
],
"name": "updateSocket",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View file

@ -1,4 +0,0 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/c79ff14473359160d0c7a65892d5cb52.json"
}

View file

@ -1,96 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IWrappedA0GIBase",
"sourceName": "contracts/IWrappedA0GIBase.sol",
"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": "initialSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "supply",
"type": "uint256"
}
],
"internalType": "struct Supply",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View file

@ -1,78 +0,0 @@
{
"_format": "hh-sol-cache-2",
"files": {
"/Users/wangfan/Project/0g-geth/core/vm/precompiles/interfaces/contracts/IDASigners.sol": {
"lastModificationDate": 1743021984706,
"contentHash": "dbe903452c6de71caa950fdb306027b3",
"sourceName": "contracts/IDASigners.sol",
"solcConfig": {
"version": "0.8.20",
"settings": {
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
">=0.8.0"
],
"artifacts": [
"BN254",
"IDASigners"
]
},
"/Users/wangfan/Project/0g-geth/core/vm/precompiles/interfaces/contracts/IWrappedA0GIBase.sol": {
"lastModificationDate": 1743006728499,
"contentHash": "1d44f536ff2a527d2afe8a4ef85adc7b",
"sourceName": "contracts/IWrappedA0GIBase.sol",
"solcConfig": {
"version": "0.8.20",
"settings": {
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
">=0.8.0"
],
"artifacts": [
"IWrappedA0GIBase"
]
}
}
}

View file

@ -54,4 +54,17 @@ interface IWrappedA0GIBase {
* @param amount amount to burn
*/
function burn(address minter, uint256 amount) external;
/**
* @dev Modify the mint and burn cap of given account.
* Can only be called by multi-sig admin.
* @param minter minter address
* @param cap new mint cap
* @param initialSupply new initial supply / burn cap
*/
function setMinterCap(
address minter,
uint256 cap,
uint256 initialSupply
) external;
}

View file

@ -37,7 +37,7 @@ type Supply struct {
// 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\":\"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\":\"initialSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"supply\",\"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\":\"initialSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"supply\",\"type\":\"uint256\"}],\"internalType\":\"structSupply\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"cap\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"initialSupply\",\"type\":\"uint256\"}],\"name\":\"setMinterCap\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
}
// Wrappeda0gibaseABI is the input ABI used to generate the binding from.
@ -289,3 +289,24 @@ func (_Wrappeda0gibase *Wrappeda0gibaseSession) Mint(minter common.Address, amou
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) Mint(minter common.Address, amount *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.Mint(&_Wrappeda0gibase.TransactOpts, minter, amount)
}
// SetMinterCap is a paid mutator transaction binding the contract method 0xdddba6c8.
//
// Solidity: function setMinterCap(address minter, uint256 cap, uint256 initialSupply) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseTransactor) SetMinterCap(opts *bind.TransactOpts, minter common.Address, cap *big.Int, initialSupply *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.contract.Transact(opts, "setMinterCap", minter, cap, initialSupply)
}
// SetMinterCap is a paid mutator transaction binding the contract method 0xdddba6c8.
//
// Solidity: function setMinterCap(address minter, uint256 cap, uint256 initialSupply) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseSession) SetMinterCap(minter common.Address, cap *big.Int, initialSupply *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.SetMinterCap(&_Wrappeda0gibase.TransactOpts, minter, cap, initialSupply)
}
// SetMinterCap is a paid mutator transaction binding the contract method 0xdddba6c8.
//
// Solidity: function setMinterCap(address minter, uint256 cap, uint256 initialSupply) returns()
func (_Wrappeda0gibase *Wrappeda0gibaseTransactorSession) SetMinterCap(minter common.Address, cap *big.Int, initialSupply *big.Int) (*types.Transaction, error) {
return _Wrappeda0gibase.Contract.SetMinterCap(&_Wrappeda0gibase.TransactOpts, minter, cap, initialSupply)
}

View file

@ -4,6 +4,7 @@ import "errors"
var (
ErrSenderNotWA0GI = errors.New("sender is not WA0GI")
ErrSenderNotAgency = errors.New("sender is not agency")
ErrInsufficientMintCap = errors.New("insufficient mint cap")
ErrInsufficientMintSupply = errors.New("insufficient mint supply")
)

View file

@ -16,8 +16,9 @@ const (
WrappedA0GIBaseRequiredGasMax uint64 = 1000_000_000
// txs
WrappedA0GIBaseFunctionMint = "mint"
WrappedA0GIBaseFunctionBurn = "burn"
WrappedA0GIBaseFunctionMint = "mint"
WrappedA0GIBaseFunctionBurn = "burn"
WrappedA0GIBaseFunctionSetMinterCap = "setMinterCap"
// queries
WrappedA0GIBaseFunctionGetWA0GI = "getWA0GI"
WrappedA0GIBaseFunctionMinterSupply = "minterSupply"
@ -26,6 +27,7 @@ const (
var WrappedA0GIBaseRequiredGasBasic = map[string]uint64{
WrappedA0GIBaseFunctionMint: 100_000,
WrappedA0GIBaseFunctionBurn: 100_000,
WrappedA0GIBaseFunctionSetMinterCap: 100_000,
WrappedA0GIBaseFunctionGetWA0GI: 5_000,
WrappedA0GIBaseFunctionMinterSupply: 10_000,
}
@ -97,6 +99,8 @@ func (w *WrappedA0giBasePrecompile) Run(evm *EVM, contract *Contract, readonly b
bz, err = w.Mint(evm, contract, method, args)
case WrappedA0GIBaseFunctionBurn:
bz, err = w.Burn(evm, contract, method, args)
case WrappedA0GIBaseFunctionSetMinterCap:
bz, err = w.SetMinterCap(evm, contract, method, args)
}
if err != nil {
@ -235,3 +239,53 @@ func (w *WrappedA0giBasePrecompile) Burn(
}
return method.Outputs.Pack()
}
func (w *WrappedA0giBasePrecompile) getAgency() common.Address {
// This is a Wrapped A0GI Agency contract deployed by a raw transaction:
// raw tx params:
// from:
// nonce: 0
// gasPrice: 100 Gwei
// gasLimit: 1000000
// The sender is an ephemeral account, nobody holds its private key and this is the only transaction it signed.
// This transaction is a legacy transaction without chain ID so it can be deployed at any EVM chain which supports pre-EIP155 transactions.
// raw tx:
return common.HexToAddress("0x0000000000000000000000000000000000000000")
}
func (w *WrappedA0giBasePrecompile) SetMinterCap(
evm *EVM,
contract *Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
if len(args) != 3 {
return nil, ErrExecutionReverted
}
minter := args[0].(common.Address)
cap := args[1].(*big.Int)
initialSupply := args[2].(*big.Int)
// validation
agency := w.getAgency()
if contract.caller != agency {
return nil, wrappeda0gibase.ErrSenderNotWA0GI
}
// execute
supply, err := w.getMinterSupply(evm, minter)
if err != nil {
return nil, err
}
difference := new(big.Int).Sub(initialSupply, supply.InitialSupply)
supply.Supply.Add(supply.Supply, difference)
if supply.Supply.Cmp(big.NewInt(0)) < 0 {
supply.Supply = big.NewInt(0)
}
supply.Cap = cap
supply.InitialSupply = initialSupply
// update minter supply
if err = w.setMinterSupply(evm, minter, supply); err != nil {
return nil, err
}
return method.Outputs.Pack()
}