This contract provides an anchor for an appchain of Octopus Network. It is in charge of managing the necessary data of an appchain in NEAR protocol, , providing security and interoperability for the appchain.
Each appchain of Octopus Network will be bonded to an instance of this contract, which is deployed to a subaccount of octopus-appchain-registry.
Contents
- Terminology
- Function specification
- Manage appchain settings
- Manage anchor settings
- Manage protocol settings
- Manage NEAR fungible token
- Manage wrapped appchain token
- Manage wrapped appchain NFT
- Manage staking
- Manage beefy light client
- Process appchain messages
- Switch validator set
- Distribute reward of era
- Withdraw reward
- Withdraw unbonded stake
- Manage appchain lifecycle
- Pause or resume asset transfer
- Pause or resume rewards withdrawal
- Stage appchain challenges
- Initial deployment
- Auditing
- Testing
owner
: The owner of this contract, that is the Octopus Network.appchain registry
: A NEAR contract which manage the lifecycle of appchains of Octopus Network, controlled by Octopus Network.appchain owner
: The owner of an appchain.appchain state
: The state of an appchain, the statestaging
,booting
,active
,frozen
,broken
anddead
will be managed in this contract.account id in appchain
: The account id in the appchain, which is usually the public key of an account in the appchain. The id is bonded to an account id in NEAR protocol in this contract.validator
: A person who wants to act as a validator on the appchain corresponding to this contract. The person has to deposit a certain amount of OCT token in this contract.delegator
: A person who wants to act as a delegator in the corresponding appchain. The person has to deposit a certain amount of OCT token in this contract, to indicate that he/she wants to delegate his/her voting rights to a certainvalidator
of the appchain.validator set
: A set of validators and delegators of the corresponding appchain. This set may change in every era of appchain, based on the actions happened in this contract during the period of last era of corresponding appchain.era
: A certain period in the corresponding appchain that the reward distribution and validator set switching need to be performed.OCT token
: The OCT token is used to stake for the validators of corresponding appchain.NEAR fungible token
: A token which is lived in NEAR protocol. It should be a NEP-141 compatible contract. This contract can bridge the token to the corresponding appchain.wrapped appchain token
: The wrapped token of the appchain native token, which is managed by a contract in NEAR protocol.wrapped appchain NFT
: The wrapped appchain native non-fungible token asset, which is managed by a contract in NEAR protocol.appchain notification
: The appchain notification generated in this contract. Appchain will query these data to complete cross-chain asset transfer. It has the following types:- Near fungible token is locked in appchain anchor contract.
- Wrapped appchain token is burnt in NEAR protocol.
staking history
: The staking history happens in this contract. These data will be used to recover the status ofvalidator set
at a certain time.appchain message
: The message which is relayed to this contract byoctopus relayer
.octopus relayer
: A standalone service which will relay theappchain message
to this contract.appchain settings
: A set of settings for booting corresponding appchain, which includeschain_spec
,raw_chain_spec
,boot_nodes
,rpc_endpoint
,era_reward
and other necessary field(s).anchor settings
: A set of settings for current appchain anchor, which includestoken_price_maintainer_account
and other necessary field(s).protocol settings
: A set of settings for Octopus Network protocol, maintained by theowner
, which includes the following fields:minimum_validator_deposit
: The minimum deposit amount for a validator to register itself to this contract.minimum_delegator_deposit
: The minimum deposit amount for a delegator to delegate his voting weight to a certain validator.minimum_total_stake_for_booting
: The minimum value of total stake in this contract for booting corresponding appchain.maximum_market_value_percent_of_near_fungible_tokens
: The maximum percentage of the total market value of all NEAR fungible tokens to the total market value of OCT token staked in this contractmaximum_market_value_percent_of_wrapped_appchain_token
: The maximum percentage of the total market value of wrapped appchain token to the total market value of OCT token staked in this contract.minimum_validator_count
: The minimum number of validator(s) registered in this contract for booting the corresponding appchain and keep it alive.maximum_validators_per_delegator
: The maximum number of validator(s) which a delegator can delegate to.unlock_period_of_validator_deposit
: The unlock period (in days) for validator(s) can withdraw their deposit after they are removed from the corresponding appchain.unlock_period_of_delegator_deposit
: The unlock period (in days) for delegator(s) can withdraw their deposit after they no longer delegates their stake to a certain validator on the corresponding appchain.maximum_era_count_of_unwithdrawn_reward
: The maximum number of historical eras that the validators or delegators are allowed to withdraw their rewards.
sender
: A NEAR transaction sender, that is the account which perform actions (call functions) in this contract.
Generally speaking, this contract has the following responsibilities:
- Manage the settings data related to corresponding appchain, this contract itself and the predefined protocol of Octopus Network.
- Manage the lifecycle of corresponding appchain.
- Manage the cross-chain assets for corresponding appchain. Including the NEAR fungible token(s) and wrapped appchain token.
- Handle the staking actions happened in NEAR protocol.
- Manage the validator set for corresponding appchain.
- Manage the rewards of validators and delegators of corresponding appchain.
This contract provides a set of view functions for querying the status of the contract and necessary history data related to the above business.
This contract has a set of functions to manage the value of each field of appchain settings
.
This contract has a set of functions to manage the value of each field of anchor settings
.
This contract has a set of functions to manage the value of each field of protocol settings
.
This contract can bridge multiple NEAR fungible tokens to the corresponding appchain. The limitation is: the total market value of all NEAR fungible token
bridged to the corresponding appchain, cannot exceed the market value of a certain percent of all OCT token staked in this contract. The percentage is managed by maximum_market_value_percent_of_near_fungible_tokens
of protocol settings
.
This contract should provide the following public interfaces related to NEAR fungible token management:
- Register NEAR fungible token.
- Set price of a NEAR fungible token. This action can only be performed by
token_price_maintainer_account
which is managed inanchor settings
. - Open bridging for a NEAR fungible token.
- Close bridging for a NEAR fungible token.
When this contract receives a deposit of a certain amount of a registered NEAR fungible token
, this contract should check the limitation and then generate appchain notification
for corresponding appchain to mint equivalent amount of the NEAR fungible token
.
When this contract receives an appchain message
which indicates that the appchain has burnt a certain amount of a registered NEAR fungible token
, this contract should unlock equivalent amount of the NEAR fungible token and transfer them to the proper account in NEAR protocol.
The contract of wrapped appchain token
in NEAR protocol should be deployed before the appchain go active
. The owner of the token contract should be set to this contract. The initial total supply of wrapped appchain token
should be minted to an account belongs to the appchain team.
The limitation of wrapped appchain token
is: the market value of wrapped appchain token
in NEAR contract cannot exceed the market value of a certain percent of all OCT token staked in this contract. The percentage is managed by maximum_market_value_percent_of_wrapped_appchain_token
of protocol settings
.
This contract should provide the following public interfaces related to wrapped appchain token management:
- Set metadata of wrapped appchain token.
- Set contract account of wrapped appchain token.
- Set initial balance of wrapped appchain token.
- Set price of wrapped appchain token. This action can only be performed by
token_price_maintainer_account
which is managed inanchor settings
. - Burn wrapped appchain token. Which will generate an
appchain notification
for corresponding appchain to mint equivalent amount of native token.
When this contract receives an appchain message
which indicates that the appchain has locked a certain amount of wrapped appchain token
, this contract should mint equivalent amount of wrapped appchain token
in the corresponding NEAR fungible token contract.
Like the wrapped appchain token
, this contract can also manage the wrapped appchain NFT
asset(s) for the corresponding appchain.
The contract of wrapped appchain NFT
in NEAR protocol should be deployed before the appchain go active
. The owner of the token contract should be set to this contract. (Only this contract has rights to mint
NFT asset in the contract of wrapped appchain NFT
.)
This contract should provide the following public interfaces related to wrapped appchain token management:
- Register a NFT class. Each class of NFT will be mapping to a
wrapped appchain NFT
contract in NEAR protocol. The metadata of the NFT class should be set when register it in this contract. This must be done, before users can transfer NFT asset of the certain class. - Change the metadata of a NFT class.
- Open bridging for a NFT class. (Allow transferring NFTs of a certain class of appchain native NFT tokens from appchain to NEAR protocol, and allow transferring them back to appchain.)
- Close bridging for a NFT class. (Refuse transferring NFTs of a certain class of appchain native NFT tokens between appchain and NEAR protocol.)
When this contract receives an appchain message
which indicates that the appchain has locked a certain NFT, this contract should mint a new one in the corresponding wrapped appchain NFT
contract in NEAR protocol. The processing sequence is similar to transfer appchain native token to NEAR protocol
, which is mentioned in Manage wrapped appchain token.
When transfer a certain wrapped appchain NFT
back to the corresponding appchain, the owner of the wrapped appchain NFT
can transfer it to this contract with a particular message attached to the calling of funtion nft_transfer_call
of the contract of the corresponding wrapped appchain NFT
class. Then this contract will generate an appchain notification
for corresponding appchain to unlock it. The processing sequence is similar to transfer NEAR fungible token to appchain
, which is mentioned in Manage NEAR fungible token.
Any user in NEAR protocol can deposit a certain amount (not less than minimum_validator_deposit
of protocol settings
) of OCT token to this contract to register his/her account as a validator
of next era
of corresponding appchain. The user should also specify the validator account id which will be used in the corresponding appchain, and specify the flag which indicates that 'whether the validator wants to be delegated to'.
Any user in NEAR protocol can deposit a certain amount of OCT token to this contract to increase his/her stake as a validator
in next era
of corresponding appchain. The user must be already a registered validator
and the validator
must not be unbonded.
Any user in NEAR protocol can deposit a certain amount (not less than minimum_delegator_deposit
of protocol settings
) of OCT token to this contract to register his/her account as a delegator
of next era
of corresponding appchain. The user should also specify the validator account id (in the corresponding appchain) that he/she want to delegate to.
Any user in NEAR protocol can deposit a certain amount of OCT token to this contract to increase his/her delegation as a delegator
in next era
of corresponding appchain. The user must be already a registered delegator
of a certain validator
and the delegator
must not be unbonded.
A registered validator
can unbond himself/herself from corresponding appchain. The contract will mark this validator
as unbonding
, and apply this action while generating validator set for the next era.
A registered delegator
can unbond himself/herself from a specific validator
of corresponding appchain. At this case, this contract should remove the delegator
from the validator set
of next era
of corresponding appchain. The lock period of the unbonded delegation will start from the start time of next era
and last for the duration of unlock_period_of_delegator_deposit
of protocol settings
, before the delegator can withdraw the unbonded delegation.
A validator can decrease his/her stake while the validator is still active (not unbonded) in corresponding appchain. The deposit of the validator after the reduction cannot be less than minimum_validator_deposit
of protocol settings
, and the total stake of the validator set
of next era
after the reduction cannot be less than 2/3 of the total stake of the validator set
of last era
. The lock period of the decreased stake will start from the start time of next era
and last for the duration of unlock_period_of_validator_deposit
of protocol settings
, before the validator can withdraw the decreased stake.
A delegator can decrease his/her delegation while the delegator is still active (not unbonded) in corresponding appchain. The deposit of the delegator after the reduction cannot be less than minimum_delegator_deposit
of protocol settings
, and the total stake of the validator set
of next era
after the reduction cannot be less than 2/3 of the total stake of the validator set
of last era
. The lock period of the decreased delegation will start from the start time of next era
and last for the duration of unlock_period_of_delegator_deposit
of protocol settings
, before the delegator can withdraw the decreased delegation.
Each of the above actions will generate a corresponding staking history
that is stored in this contract. These staking histories are used to restore the validator set
of a certain era
.
A validator can also change the flag which is set at registering time and stored in this contract, the flag indicates that 'whether he/she wants to be delegated to'. After this flag is set to false
, delegators cannot delegate to this validator any more. But those delegators already delegated to this validator will be kept.
The staking actions also depend on the state of corresponding appchain:
Staking action | AppchainState: Staging | AppchainState: Booting | AppchainState: Active | AppchainState: Frozen | AppchainState: Broken |
---|---|---|---|---|---|
register_validator | allowed | allowed | |||
increase_stake | allowed | allowed | |||
register_delegator | allowed | allowed | |||
increase_delegation | allowed | allowed | |||
decrease_stake | allowed | ||||
decrease_delegation | allowed | ||||
unbond_stake | allowed | allowed | |||
unbond_delegation | allowed | allowed |
This contract manages a stateful beefy light client for the verification of appchain message
. The state of the light client is periodically synced by octopus relayer
(the state data relayed must be verified first, of course). All appchain message
s relayed by octopus relayer
must be verified by the light client before they are applied in this contract.
Refer to the implementation of octopus beefy light client.
This contract can verify (by using beefy light client) and stage appchain message
s relayed by octopus relayer
. As the gas consumption of a appchain message
may exceed the gas limitation in NEAR protocol, the processing of staged appchain message
s may cost multiple transactions to finish. This contract has a permissionless function to process staged appchain message
s. This function will be called repeatedly by octopus relayer
until all staged messages are applied in this contract.
The appchain message
s which can be applied in this contract have the following types:
- Fungible token burnt in appchain - refer to Manage NEAR fungible token
- Appchain native token locked in appchain - refer to Manage wrapped appchain token
- New era is planed in appchain - refer to Switch validator set
- Reward of era can be distributed - refer to Distribute reward of era
When this contract receives an appchain message
which indicates that the corresponding appchain has switched to a new era
, this contract should:
- Create a new (empty)
validator set
for the givenera
. - Copy the whole state of the
validator set
of the previousera
of the givenera
. - Unbond the validators who are marked as
unbonding
:- Remove all delegators of the
validator
from thevalidator set
. The lock period of the decreased delegation will start from the start time of nextera
and last for the duration ofunlock_period_of_delegator_deposit
ofprotocol settings
, before the delegator can withdraw the unbonded delegation. - Remove the
validator
from thevalidator set
. The lock period of the unbonded stake will start from the start time of nextera
and last for the duration ofunlock_period_of_validator_deposit
ofprotocol settings
, before the validator can withdraw the unbonded stake.
- Remove all delegators of the
- Unbond the validators who are marked as
auto_unbonding
(refer to Distribute reward of era):- Remove all delegators of the
validator
from thevalidator set
. The lock period of the decreased delegation will start from the start time of nextera
and last for the duration ofunlock_period_of_delegator_deposit
ofprotocol settings
, before the delegator can withdraw the unbonded delegation. - Remove the
validator
from thevalidator set
. The lock period of the unbonded stake will start from the start time of nextera
and last for the duration ofunlock_period_of_validator_deposit
ofprotocol settings
, before the validator can withdraw the unbonded stake.
- Remove all delegators of the
- Restore the state of the
validator set
by sequentially applying all staking histories happened by the time of thisappchain message
is received (that is the staking histories happened from the lastera
was switched).
During this process:
- Generate a copy of the status of all
validator
(s) in thevalidator set
of the givenera
. It is for the query of appchain nodes. (Because the data struct for query of appchain nodes may be defferent with the internal storage of this contract.) - Generate the history of
unbonded stake
ifstake decreased
,delegation decreased
,validator unbonded
ordelegator unbonded
happened in last era of the given era. The rule is described in Manage staking.
The validator and delegator need to withdraw the unbonded stakes manually.
Notice that, due to the gas limit of a transaction, the whole process may cost more than one transaction to complete.
When this contract receives an appchain message
which indicates that the corresponding appchain has finished an era
and needs to distribute the reward of the era
, this contract should:
- Store the
unprofitable validator id list
carried by theappchain message
in thevalidator set
of the givenera
. - Mint a certain amount of
wrapped appchain token
in the corresponding token contract. The amount isera_reward
ofappchain settings
. - Distribute the
era_reward
proportionally to all profitable validators and delegators, and store the results in this contract. - Mark validators who should be
auto_unbond
:- If a validator did not receive reward in a certain amount of consecutive
era
s, it will be marked asauto_unbonding
. The count of consecutiveera
s ismaximum_allowed_unprofitable_era_count
ofprotocol_settings
.
- If a validator did not receive reward in a certain amount of consecutive
The validator and delegator need to withdraw the rewards manually.
Notice that, due to the gas limit of a transaction, the whole process may cost more than one transaction to complete.
A validator or deleagtor can withdraw their reward in latest eras at any time. The earliest era in which they can withdraw is limited by maximum_era_count_of_unwithdrawn_benefit
of protocol settings
.
A validator or delegator can withdraw the unbonded stake which is belonged them. Each unbond action will be recorded in this contract, and the unlock period of these unbonded stakes is calculated separatly (as described in Manage staking).
The owner of appchain anchor can manually change the state of corresponding appchain. These actions need to check necessary conditions before changing the state of corresponding appchain. And after changing the state, this contract will call function sync_state_of
of appchain registry
contract to synchronize the state to appchain registry
. (The appchain registry
will ensure the caller account of this function is <appchain_id>.<appchain registry account>
.)
The owner account of this contract can pause or resume asset transfer in this contract. The actions that will be limited should be:
- Transfer OCT token into this contract by function
ft_transfer_call
of OCT token contract, with a certain message attached (to register a validator). - Transfer registered NEAR fungible token into this contract by function
ft_transfer_call
of the registered NEAR fungible token contract, with a certain message attached (to transfer to a certain account in appchain). - Burn wrapped appchain token (to transfer back to a certain account in appchain).
- Mint wrapped appchain token (by a verified cross-chain message to transfer native appchain token to a certain account in NEAR protocol).
- Withdraw unbonded stake (of a validator or a delegator) with OCT token.
- Withdraw rewards of a validator with wrapped appchain token.
- Withdraw rewards of a delegator with wrapped appchain token.
The owner account of this contract can pause or resume rewards withdrawal in this contract. The actions that will be limited should be:
- Withdraw rewards of a validator with wrapped appchain token.
- Withdraw rewards of a delegator with wrapped appchain token.
This contract can stage 2 kinds of appchain challenges on chain for further process (automatically or manually).
- Equivocation challenge - A certain validator of appchain signed 2 versions of voting data for a block with the same height in appchain. The implementation in this contract refers to the pallet
finality-grandpa
of Substrate primitives. - Conspiracy MMR - A certain amount of validators of appchain conspired to forge a new version of MMR. This contract only stage the submitter account and the block height for further manully checking in appchain.
We should take the following steps to initialize this contract and all related contract:
- Prepare the OCT token contract. (Deploy a new one in testnet or use the one created by Aurora Rainbow Bridge in mainnet.)
- Prepare the appchain registry contract. Refer to Octopus Appchain Registry.
- Conclude an appchain in Appchain Registry. After this, the anchor account, that is the account for this contract will be created automatically. The first full access key of anchor account will also be created in this action, with the public key of the owner account of Appchain Registry contract.
- To deploy the contract code to anchor account by near-cli, we need to do the following actions:
- Copy the key pair file of the owner of Appchain Registry contract, which is used to call the function
new
to initialize the Appchain Registry contract. (The public key of owner can be queried by view funcionget_owner_pk
of Appchain Registry contract.) The key pair file can be found in folder~/.near-credentials/testnet
. - Change name of the key pair file copy to
<appchain id>.<contract account of appchain registry>.json
, and change the value ofaccount_id
inside the json file to<appchain id>.<contract account of appchain registry>
.
- Copy the key pair file of the owner of Appchain Registry contract, which is used to call the function
- Deploy this contract on account
<appchain id>.<contract account of appchain registry>
with parametersappchain id
,contract account of OCT token
andcontract account of appchain registry
bynear-cli
. - Determine the account id of wrapped appchain token contract, and store it in this contract. (By calling function
set_account_of_wrapped_appchain_token
.) - Determine the
premined beneficiary
andpremined balance
. (Normally decided by the appchain team.) - Deploy the wrapped appchain token contract with parameters
premined beneficiary
,premined balance
,contract account of appchain anchor (this contract)
andFungibleTokenMetadata
. (These initial parameters will be synced to this contract by calling functionsync_basedata_of_wrapped_appchain_token
at construction time of wrapped appchain token contract. Refer to Octopus Wrapped Appchain Token.)
This contract has completed auditing by:
To run all tests:
./build.sh test
To run a certain test:
./build.sh test <test name>
And for running all tests, the following wasm files are needed in folder res
(the folder will be created automatically after running build.sh
):
appchain_anchor.wasm
- Automatically generated by runningbuild.sh
.wat_faucet.wasm
- Automatically generated by runningbuild.sh
.mock_appchain_registry.wasm
- Automatically generated by runningbuild.sh
.mock_oct_token.wasm
- Automatically generated by runningbuild.sh
.wrapped_appchain_nft.wasm
- This wasm can be built from Octopus wrapped appchain NFT template.wrapped_appchain_token.wasm
- This wasm can be built from Octopus wrapped appchain token template.appchain_anchor_<version>.wasm
- The history version of this contract. The testing of current version may need its previous version. Also refer to the code of functioninitialize_contracts_and_users
in testing moduletests/simulator/common/basic_actions.rs
.