function commitBlocks(
StoredBlockInfo memory _lastCommittedBlockData,
CommitBlockInfo[] memory _newBlocksData
)
external;
Validators commit blocks from L2 to L1 and the blocks will be stored on L1 for later validation. Commit one block includes the following steps:
- check
blockNumber
,timestamp
- check if priority operations from the committed block are same as the transactions in
priority queue
. All onchain operations as below:RegisterZNS
: register ZNS nameCreatePair
: create token pair for token swap on L2UpdatePairRate
: update fee rate of the token pairDeposit
: deposit tokens from L1 to L2DepositNft
: deposit NFT from L1 to L2Withdraw
: withdraw tokens from L2 to L1, sending request to L2WithdrawNft
: withdraw NFT from L2 to L1, sending request to L2FullExit
: request exit tokens from L2 to L1, sending request to L1FullExitNft
: request exit NFT from L2 to L1, sending request to L1
- create block commitment for verification proof
- store block hash on chain
struct CommitBlockInfo {
bytes32 newStateRoot;
bytes publicData;
uint256 timestamp;
uint32[] publicDataOffsets;
uint32 blockNumber;
uint16 blockSize;
}
CommitBlock
contains block information, transaction data and the state root after the transactions has been executed.
Block information contains timestamp
, blockNumber
and blockSize
.
L2 transactions are packed in CommitBlockInfo.publicData
function verifyAndExecuteBlocks(VerifyAndExecuteBlockInfo[] memory _blocks, uint256[] memory _proofs) external;
function verifyAndExecuteOneBlock(VerifyAndExecuteBlockInfo memory _block, uint32 _verifiedBlockIdx) internal;
verifyAndExecuteOneBlock
verifies and executes stored blocks from commitBlocks
,
including the following steps:
- check if the provided block was committed from
commitBlocks
before and in correct order - check if the pending onchain operations are correct
- execute onchain operations if needed.(
Withdraw
,WithdrawNft
,FullExit
,FullExitNft
)
function registerZNS(string calldata _name, address _owner, bytes32 _ZkBNBPubKeyX, bytes32 _ZkBNBPubKeyY) external payable;
Add request that registering a ZNS name into priority queue
.
function depositBNB(string calldata _accountName) external payable;
Deposit native asset to L2, _accountName
will receive the BNB on L2. This function including the following steps:
- transfer BNB from user into
ZkBNB
contract - add
Deposit
request intopriority queue
function depositBEP20(
IERC20 _token,
uint104 _amount,
string calldata _accountName
) external;
Deposit BEP20 token to L2, _accountName
will receive the token. This function including the following steps:
- transfer BEP20 token from user into
ZkBNB
contract - check if the token is allowed to deposit to L2
- add
Deposit
request intopriority queue
function getAddressByAccountNameHash(bytes32 accountNameHash) public view returns (address);
function isRegisteredZNSName(string memory name) external view returns (bool);
function getZNSNamePrice(string calldata name) external view returns (uint256);
function getNFTFactory(bytes32 _creatorAccountNameHash, uint32 _collectionId) public view returns (address);
function getPendingBalance(address _address, address _assetAddr) public view returns (uint128);
ZkBNB
provides some interfaces to query L1 and L2 status.
getAddressByAccountNameHash
:isRegisteredZNSName
: check if the provided ZNS name is registeredgetZNSNamePrice
: get the price of the provided ZNS namegetNFTFactory
: get a registered NFTFactory according to the creator accountNameHash and the collectionIdgetPendingBalance
: get pending balance that the user can withdraw
Due to a ceiling on the code size of ZkBNB
contract, AdditionalZkBNB
will store more logic code which could not be stored on ZkBNB
.
function createPair(address _tokenA, address _tokenB) external;
Create token pair for token swap on L2. This function including the following steps:
- check if the pair of provided tokens already exists and the provided tokens are allowed to create pair on L2
- If caller is not present in the
tokenLister
map, payment oflistingFee
inlistingFeeToken
should be made - record new token pair on chain
- add
CreatePair
request intopriority queue
function updatePairRate(PairInfo memory _pairInfo) external;
Update the fee rate of provided pair on L2. This function including the following steps:
- check if the pair exists and tokens are allowed to update fee rate
- update token pair fee rate on L1
- add
UpdatePairRate
request intopriority queue
AssetGovernance
contract is used to allow anyone to add new ERC20 tokens to ZkBNB given sufficient payment.
function addAsset(address _assetAddress) external;
This function allows anyone adds new ERC20 token to ZkBNB network.
If caller is not present in the tokenLister
map, payment of listingFee
in listingFeeToken
should be made.
before calling this function make sure to approve listingFeeToken
transfer for this contract.
ZkBNBVerifier
contract help ZkBNB
to verify the committed blocks and proofs.
function verifyBatchProofs(
uint256[] memory in_proof, // proof itself, length is 8 * num_proofs
uint256[] memory proof_inputs, // public inputs, length is num_inputs * num_proofs
uint256 num_proofs,
uint16 block_size
)
public
view
returns (bool success);
function verifyProof(
uint256[] memory in_proof,
uint256[] memory proof_inputs,
uint16 block_size
)
public
view
returns (bool);
This function allows verifying batch proofs for batch blocks.
ZkBNB Name Service(ZNS) is a name service between L1 and L2. Users should register name in L1 and set his L2 account address(Bytes32 public key) with this name. So that this user can use this name both in L1 and L2.
Names are stored as node in contracts. Each node is mapped by a byte32 name hash. The name hash can be calculated as below(a Javascript implementation is in ./test/zns-registry.js):
def namehash(name):
if name == '':
return '\0' * 32
else:
label, _, remainder = name.partition('.')
return sha3(namehash(remainder) + sha3(label))
Note that each legal name should only contain lower-case character and number with a length between 3-32(included).
Contracts of ZNS are consists of three parts: ZNSRegistry, ZNSRegistrarController and ZNSResolver.
A ZNSRegistry contains records of name node. It will be owned as a member variable by ZNSRegistrarController.
All ZNS lookups start by querying the registry. The registry contains records of ZkBNB short name, recording the owner, L2 owner and resolver of each name, and allows the owner of a domain to make changes to these data.
Interface of the ZNS Registry.
It defines events:
- NewOwner: Logged when the owner of a node assigns a new owner to a subnode.
- NewL2Owner: Logged when the L2 owner of a node transfers ownership to a new L2 account.
- NewResolver: Logged when the resolver for a node changes.
These events can be monitored by BlockMonitor service.
It also defines setter and getter function of member variables in ZNSRecord.
Implementation of ZNS.sol.
It defines a struct Record contains: owner, L2Owner(public key) and resolver of a name.
struct Record {
// The owner of a record may:
// 1. Transfer ownership of the name to another address
// 2. Change the ownership of sub account name
// 3. Change the L2 owner of this account name
// 4. Set the ttl and resolver of node
address owner;
bytes32 pubKey;
address resolver;
}
Setter and Getter methods of each field is defined in this registry.
All short names are maintained by this contract and each name is mapped to a Record.
It provides external functions for users to register (and transfer) ZkBNB names.
It also maintains a mapper from L2Account to node's name hash, which can be used to assure each L2 account can only own one name.
It defines external methods:
- register: register a not existed name for a specified address, which actually invokes safeMint to mint a name node nft.
A resolver is used to resolve detailed information of a name in L1, like a text, public key connected with this node.
An external contract should implement the Resolver.sol
and the owner of nodes can set this contract
as the resolver for his nodes. Then others can resolve this name for detailed information by calling this external contract.
Contracts deployed using DeployFactory
can be upgraded to modify their code, while preserving their address, state, and balance.
This allows you to iteratively add new features to your contracts, or fix any bugs after deployed.
DeployFactory
deploy a proxy to the implementation contract, which is the contract that you actually interact with.
Upgradeable contracts:
Governance
ZkBNBVerifier
ZNSController
PublicResolver
ZkBNB
There are several phases to the upgrade process:
-
startUpgrade
: start upgrade process, stored the new target implementations onnextTargets
and noticed the communityUpgradeStatus.Idle
=>UpgradeStatus.NoticePeriod
-
startPreparation
: activates preparation status to be ready for upgradeUpgradeStatus.NoticePeriod
=>UpgradeStatus.Preparation
-
finishUpgrade
: finishes the upgradeUpgradeStatus.Preparation
=>UpgradeStatus.Idle
function deployProxyContracts(
Governance _governanceTarget,
ZkBNBVerifier _verifierTarget,
ZkBNB _ZkBNBTarget,
ZNSController _znsControllerTarget,
PublicResolver _znsResolverTarget,
AdditionalParams memory _additionalParams
) internal;
This function deploy proxies for upgradeable contracts in ZkBNB
.
UpgradeGatekeeper
is the admin contract who will be the only one allowed to manage and upgrade these upgradeable contracts.
Upgradeable[] public managedContracts;
enum UpgradeStatus {
Idle,
NoticePeriod,
Preparation
}
UpgradeStatus public upgradeStatus;
managedContracts
stores upgradeable contracts managed by UpgradeGatekeeper
.
upgradeStatus
stores the status of all upgrades.
All upgradeable contracts can only remain in the same state if already started upgrade.
function addUpgradeable(address addr) external;
This function adds a new upgradeable contract to the list of contracts managed by the UpgradeGatekeeper
.
function startUpgrade(address[] calldata newTargets) external;
This function starts upgrade for the contracts corresponding to newTargets
(activates notice period)
function cancelUpgrade() external;
This function cancels upgrade process only at the period of UpgradeStatus.NoticePeriod
and UpgradeStatus.Preparation
.
function startPreparation() external;
This function activates preparation status only at the period of UpgradeStatus.NoticePeriod
.
function finishUpgrade() external;
This function finishes upgrades only at the period of UpgradeStatus.Preparation
, setting new target implementations stored before to proxies.
interface Upgradeable {
/// @notice Upgrades target of upgradeable contract
/// @param newTarget New target
/// @param newTargetInitializationParameters New target initialization parameters
function upgradeTarget(address newTarget, bytes calldata newTargetInitializationParameters) external;
}
interface UpgradeableMaster {
/// @notice Notice period before activation preparation status of upgrade mode
function getNoticePeriod() external returns (uint256);
/// @notice Notifies contract that notice period started
function upgradeNoticePeriodStarted() external;
/// @notice Notifies contract that upgrade preparation status is activated
function upgradePreparationStarted() external;
/// @notice Notifies contract that upgrade canceled
function upgradeCanceled() external;
/// @notice Notifies contract that upgrade finishes
function upgradeFinishes() external;
/// @notice Checks that contract is ready for upgrade
/// @return bool flag indicating that contract is ready for upgrade
function isReadyForUpgrade() external returns (bool);
}
All proxies of upgradeable contracts should implement Upgradeable
and UpgradeableMaster
interface for management of UpgradeGatekeeper
.