Sovereign Chain Factory, Validators, Staking SC - MIP - 14

The idea is the projects will have to deploy a config smart contract for the sovereign chain (more specifically this will be deployed through a factory SC, so projects do not need to change the code of the sovereign chain SC). In this they write the configuration of the sovereign and the rules. Validators and users have to come and stake through a new staking contract written in RUST (we need a new staking contract in order to be able to slash), this staking contract will delegate the received tokens to the system delegation module or to lock liquid staked eGLD/approved assets which have underlying liquid staked eGLD. Thus, this staking contract will earn eGLD rewards, and these rewards will be given to those who deposited. These validators are not the same as the mainnet validators. A validators/users receives rewards only if he is a participant in at least one sidechain. This means validators/users on sovereignChain can utilize their eGLD funds, receive rewards in eGLD, and participate in sovereignChain processing for more rewards. One-time re-staking with non-custodial delegation to earn more yield.

1. Chain-factory-contract

Let’s start with the chain factory, as this will be needed to map all the contracts on the sovereign ecosystem, we might have chain factory SC in multiple shards, so it will have a special number, maybe enshrined features from the protocol.

The main job of the chain factory SC is to create new sovereign chains, keep the map of all contracts related to the sovereign chains and to validate ESDT prefixes on sovereign chains. This contract and the others from the sovereign chain stack list will not be owned by any address, upgrades will go through only after voting, and no admin keys have access to any funds. Completely permissionless start, setup and running, without the possibilities of manipulation or unintended upgrades.

This contract will give out a combination of deterministic+random chain IDs for each of the sovereign chains, roughly the same way we do with creation of ESDT Token ID (the project sends the ticker of 3-8 characters and the system attaches a randomness of 6 characters to those). We will use the created chain IDs as ESDT token prefix for the sovereign chains as well.

More on chainID and ESDT prefix here, we want both of those to be as short as possible, as it means adding less data on-chain for every transaction. //TODO - finish this

The chain-factory SC will be deployed by us, however we will renounce the ownership, making it self running. And upgrade/modification will be done only through another so called “controller” contract in which we implement a full DAO of voting. The “controller” will be owned by itself, so it needs to be forward compatible, super general. Will talk about that later.

Endpoint: addContractsToMap@list<contractName, address>

The initial setup of the contract will be made by a user account and finally it will give the ownership to the controller. On initial setup we will add the map of address to base contract and base contracts to address. This is needed in order to use deployContractFromSource/upgradeContractFromSource. The list of needed contracts are: chainFactorySC, controllerSC, sovereignHeaderVerifierSC, sovereignCrossChainOperationSC, chainConfigSC, slashingSC.

Endpoint: deploySovereignChainConfigContract@sovereignChainName@preferredChainID: Through this contract, a sovereign chain can be deployed. The user will send in the txData all the custom parameters through which he wants to deploy the config contract. The chainFactorySC will call deployFromSource@admin@parameters and set the user as the administrator on top of the chainConfigContract, this in order to make the initial setup easily, before actually starting to run the sovereign chains.

Endpoint: deploySovereignCrossChainOperation@chainID / deploysovereignHeaderVerifier@chainID

This can be called only by the address who called the chainConfig first. These endpoints will deploy the remaining necessary contracts and make connections of those contracts, one to each other.

Later on the line we might think about deploying SC modules which can be used as hooks for some of the customization features, and a hook first has to be accepted by the community before being registered. Community approved SCs as Hooks

This will also register the address of the sovereign SC into a new map of sovereignChainID - Struct of deployed contract addresses (chainConfigSC, cross chain operation, sovereignHeaderVerifierSC), also create the link in the other direction (every such contract to chain ID)

2. ChainConfigSC

This contract will contain the configuration, the rules of the sovereign chains and will read from the chainFactorySC the addresses of the cross chain operation and sovereignHeaderVerifierSCs. Each Sovereign chain will have a set of contract, all managed by the sovereignHeaderVerifierSC (which will be dependent on chainConfigSC and sovereignValidatorSC)

This contract contains the rules for:

  1. Minimum/maximum BLS keys.

  2. Number of validators (those who sign and create blocks every epoch), it cannot be higher than the minimum number of BLS keys.

  3. Slashable offenses

  4. Extra validator criteria:
    a. Minimum eGLD stake required. Not as high as 1250, but do not get lower than 10eGLD let’s say with the current market prices.
    b. Additional stake in other tokens
    c. Was previously slashed
    d. Accept shared stake or not. Meaning new stake is needed, or it is enough that the validator has a stake in the SovereignValidatorSC.
    e. Whitelist/Blacklist of user addresses and/or BLS keys

  5. Fee management:
    a. If fee’s are in WEGLD, validators must deposit wEGLD in this contract for genesis, as txs will need WeGLD for payment.
    b. If any other token, genesis has to contain that token for at least a set of validators, as you need to bootstrap the network.

  6. Native token definition - ESDT tokenID
    a. It can be a token launched on mainnet (like wEGLD)
    b. It can be sovereign specific, then it will receive the prefix received from chainFactorySC
    c. Define whether native token is distributed from the deposited assets in this chain config, or if they are minted in genesis time on the new sovereign chain.

  7. Additional rewards in other tokens

  8. Block time, size, epoch time.

  9. Enable/Disable staking after genesis.

  10. Genesis time, genesis setup. Distribution of initial funds.

All these configs can be set up initially by the admin wallet, after the deployment through the sovereign chain factory. But the sovereign chain can start only after setup is done and the admin wallet is changed to the sovereingMultiSigSC.

Endpoint: finishSetup - this will seal the setup and change the admin wallet. Can be called by the current admin wallet only.

In case of extra rewards which are given out on the mainchain, deposits have to be made of those tokens, and setup of startTime, endTime, rewardsPerBlock (same as we do in farms on DeFi).

Genesis information will be extracted into a genesis.json file, through which the sovereign chain will start.

Endpoint: register@publicBLSKeys@eGLDStakeValue

This endpoint can receive ESDT tokens for the extra staking criteria. The eGLD has to be staked separately directly in the SovereignValidatorStakingSC, or liquid staked eGLD (LSTEGLD positions) locked in that contract.

Register endpoint will be called by validators, the chain-config-contract will ask information about the validator from the sovereign validator staking contract (how much free stake this validator has) and verify all the criterias and accept the validator after.

The register endpoint will be open after the genesis as well as the chain-config SC is the entry point for any new user to become a validator on a given sovereign chain. But it will depend on the setup of the configuration.

This endpoint will generate a logEvent which will be used on the SovereignChains to register the current address and publicBLSKeys as eligible in the SovereignChain Staking ecosystem. This is needed in order to keep the funds on the L1 and to slash those funds in case of bad behavior. This will only have significance on the node selection criteria and the end of the epoch - more specifically, from the generated logEvent, a new SCR is generated which signals (executes on) the stakingSC on the sovereign chain that node X is eligible to be selected.

logEvent:

  • Identifier = register
  • Address = scAddress
  • Topics = address, blsKeys, eGLDStake, tokenStake

The generated SCR will be activateBLSKey@blsKeys toward the Staking System SC - this one contains the list of blsKeys.

Endpoint: unRegister@publicBLSKeys

This will only signal the sovereign chain System SC to deactivate the given BLSKeys. The rest of the node and staking management has to be done directly on the sovereign chains.

unRegister does not work if the number of nodes after unregistering is smaller than the given minimum. Register does not work if the resulting number of nodes is higher than the configured maximum.

logEvent:

  • Identifier = unRegister
  • Address = scAddress
  • Topics = address, blsKeys, eGLDStake, tokenStake

3. SovereignHeaderVerifierSC:

After creating the genesis.json we must create the sovereignHeaderVerifierSC for this sovereign chain. That will contain all the blsKeys which were registered and will have to contain the first nodes which are validating in the first epoch. The first nodes validating in the first epoch will be created through a random sorting process which will be copied to the sovereign chain. (just as we had the genesis process of sorting nodes to shards).

The sovereignHeaderVerifierSC will become the admin wallet of the chainConfigSC. Any execution on sovereignHeaderVerifierSC will be done with verification of BLS multiSig of all active validators and through SovereignHeader Verification.

Endpoint: updateConfig@BLSMultiSig@endpoint@params

First we verify if the current set of the BLS keys had created the signature and if the signature is correct or not. After, we call the chainConfigSC to make the changes.

Endpoint: changeValidatorSet@SovereignHeader@BLSMultiSig@NewListOfKeys

This endpoint is called when the validator set for the next blocks is changed. Current validator set is signing the next validator set, as it is done on the mainchain. The new list is verified if everyone was registered or not. If they are not registered, the call will fail. (it is impossible for such nodes to be selected, as this will be protected on sovereign chain level as well), so failure will not happen, but better to code it this way.

In genesis, the sovereign chain starts with a defined set of BLS keys, these are written into the sovereignHeaderVerifierContract as well. When there are changes of validator keys on the sovereign chain (at end of epoch) the current group of validators will create and sign an OutGoingTXData

The contract verifies the Header and the BLSMultiSig first, then makes the validator set change. These changes will go through after epoch changes, the contract verifies according to the chainConfigSC whether the epoch has passed or not.

Endpoint: slash@validator@value@BLSMultiSig: After BLSMultiSig verification, this will further call the slash function on the sovereign validators staking contract. The slashed amount is unStaked, and will be distributed later to given addresses by another endpoint.

Endpoint: unBondSlashed: this will further call the sovereign validator staking contract and get the unbonded slashed tokens which later will be distributed.

Endpoint: distrubteSlashed@list(address, value)@BLSMultiSig: the same as slash endpoint.

4. Sovereign Validators staking contract:

Starting from the liquid staking contract (GitHub - multiversx/mx-liquid-staking-sc) a new contract is built but without giving out the liquid staked positions. In the new staking contract all the delegation contracts from the mainnet which have open delegation spaces are registered, all which have under X% fee and which have at least Y% of APR. This list can be updated manually every day/week by using on-chain and oracle data. The sovereign validator sends eGLD into the sovereign validators staking contract. The contract will register its stake and make an asyncCall of delegate with all the given amount. This will delegate the amount to one of the prelisted delegation smart contracts.

This contract can receive liquid staked eGLD or DeFi positions which have staked eGLD underlying. All these tokenIDs will be whitelisted and ruled through governance.

Important aspect of this design:

Projects will easily launch any sovereign chain, new validators can join the chains easily (without the need of minimum 1250eGLD and validating on mainnet). Validators on sovereign will still earn eGLD, as they stake eGLD on mainnet, and we will have even more eGLD staked. The sovereign validator SC might be called from a liquid staking derivative contract as well, which gives out those positions in a liquid form. Fees on sovereign can be set as eGLD or other tokens. Other rewards can be given to sovereign chain validators, customizable by each chain.

Endpoint: stake will simply delegate the given stake to a delegation contract address.

Endpoint: unStaking/unBonding will follow the same way. The sovereign validators’ staking contract will forward the calls to the delegation contracts and resolve the requests.

Endpoint: claimRewardsFromDelegationContract - will call all delegation contracts where the sovereign validators staking contract has stake and claim rewards from there and deposit it as eGLD in the contract.

Endpoint: claimRewards - validators can call this endpoint and will receive rewards according to their stake in the contract. We can borrow the implementation from the legacy Delegation smart contract for this. Another approach/module which can be selected at deploy time by sovereign deployers is to compound rewards every day, and validators will be able to receive rewards only by unStake/unBond. In this case, we would use the liquid staking token formula and register the computed amount as share in the sovereign validators staking contract.

Endpoint: registerBLSKeys@BLSKeys / unregisterBLSKeys@BLSKeys - will register/unregister the bls keys for the validator, this is needed for slashing and verification purposes. This can be called by a sovereignHeaderVerifierSC only. Also the same BLS key cannot be registered twice.

Endpoint: slash@validator@BLSKey@value - this endpoint can be called by one of the sovereignHeaderVerifierSC, will basically slash a certain amount of eGLD from the validators account. The Sovereign Validator SC will read from the chain factory SC the list of official addresses and validate according to that. Slash will actually unStake the said eGLD and put it into a new basket of unStaked eGLD for sovereignHeaderVerifierSC_X.

Endpoint: unBondSlashed - called by the sovereignHeaderVerifierSC will call unBond for the unStakedEGLD to the given SovereignChainValidatorSC.

Endpoint: lockStakedEGLDForNodes@BLSKey@amount

User can lock his staked eGLD to a preferred staking provider who is running nodes for a sovereingChain. This means delegation of the needed eGLD/LsEGLD. Yield of eGLD goes to the user. The staking provider or the SovereinChain can add more rewards for the user. This stakedEGLD is slashable according to the rules of the SovereignChain. Validators can offer extra benefits for these users.

This endpoint will call the chainConfigSC and verify if locking stakedEGLD is allowed, plus register the user there with the locked stakedEGLD. The SovereignChain can choose to reward these users with dual yield.

Endpoint: lockForSovereignChain@SovereignChain@amount

Users can sponsor the SovereignChain to gather the necessary minimum 1000+100*nrNodes staked eGLD in order to launch the SovereignChain. This will call the chainConfigSC and lock the amount to that contract. This amount can be considered the economic security fund for the sovereignChain, together with the funds locked at the previous endpoint.

Regarding the SovereignHeaderVerifierSC:

I am guessing that this means that only staked EGLD will be slashable on the mainchain, but shouldn’t configured additional stake in other tokens be able to be slashed as well?
I see this endpoint also needing a tokenId besides the value, seems like something that should be possible to do.

We are thinking here that the additional stake is moved to the SovereignChain, and the slashing is resolved there. But this is an open topic.