.. _vault_nomination: Vault Nomination ================ Overview ~~~~~~~~ Vault Nomination is a feature aimed at increasing `ONEBTC` issuance capacity which introduces two actors: Nominators and Operators. Vaults who opt in to this feature take on the additional role of nomination Operators. A Nominator is anyone who locks their free collateral so that Operators they trust can issue `ONEBTC` backed by the nominated collateral. Nominators are rewarded a fraction of the fees generated by their collateral, while the rest of the fees is given to the Operator. Operators are assumed to be trusted by their nominators not to steal Bitcoin backed by nominated collateral. Step-by-step ------------ #. Vaults opt in to the nomination feature, becoming Operators. #. The maximum nomination an Operator can receive is bounded by their own locked collateral. #. Nominators select one or more Operators and lock their collateral balance onto the BTC Bridge. #. Nominators can go offline and their nominated collateral will generate rewards passively. #. Operator and Nominator collateral cannot be withdrawn directly. Rather, withdrawals are subject to an unbonding period. #. In case of Operator failure, Nominators are returned any left-over collateral (after victim users are reimbursed). Protocol ~~~~~~~~ Security Assumptions and Considerations --------------------------------------- #. The operating Vault is trusted by its Nominators not to steal the ONEBTC issued with their collateral. #. There is no transitive trust. If a user trusts Vault A and Vault A trusts Vault B, the user does not trust Vault B. #. Nominators are mostly-offline agents, who are slow to respond to system changes. #. Vaults are always-online agents, who can promptly react to system updates. #. A Nominator may expose the Vault and the other Nominators to additional economic risk by withdrawing nominated collateral during an exchange rate spike. Similarly, the Vault may expose its Nominators to additional economic risk by withdrawing excess collateral. * Note: in the usual case, this should be handled by having the different collateral thresholds (secure, premium redeem, liquidation). But in extreme cases (very high exchange rate volatility), it might cause concern. Vault Nomination Protocol ------------------------- #. Vaults can choose to opt in and out of the Nomination protocol. If they opt-in they take on the additional role of an Operator. #. Nominators select an Operator to which they can delegate ONE balance as collateral. As a reward, they will earn a fraction of the ONEBTC and ONE fees generated by this collateral. The other fraction of these fees is received by the Operator. #. Vault replacement is disallowed for Operators with nominated collateral. Otherwise, Security Assumptions 1 and 2 would be violated. #. The nominated ONE: #. Is locked on the bridge #. Cannot be withdrawn by the operating Vault #. Is capped at a fraction of the Vault's deposited collateral (Max Nomination Ratio). This prevents the Operator from withdrawing its entire collateral and only exposing Nominators to economic risk, or stealing without liquidation consequences. This means that an Operator can only withdraw collateral as long as the fraction of nominated collateral does not exceed the threshold cap. Capping Nominator collateral also prevents Operators being “outnumbered” by Nominators and their relative fee earnings being marginalized. #. Liquidation slashing is handled as follows. #. In case the collateral managed by the Operator falls below the liquidation threshold, the Operator and Nominators are slashed proportionally to their collateral. #. In case the Operator steals Bitcoin deposited at its address, its collateral is used to cover as much of the slashed amount as possible. If the Operator's collateral was not enough to cover the entire amount, the Nominators are slashed proportionally for the remaining amount. #. Collateral withdrawals are first requested and then executed. A withdrawal request: #. Decreases the issuable ONEBTC capacity. #. May be cancelled if not executed. The amount in the cancelled withdrawal request becomes backing collateral again. #. Is subject to a window of delay (unbonding period) that allows Nominators and the Operator to react. #. Operator Unbonding Period. This window is longer, because Nominators are assumed to be mostly offline. #. Nominator Unbonding Period. This window is shorter, because the Vault Operator is assumed to always be online. #. Collateral withdrawals are subject to the following restrictions. #. The remaining collateralization of an operator must not be below the secure collateral threshold. #. Operator withdrawals must not cause nominated collateral to exceed the Max Nomination Ratio. #. Forced collateral withdrawal. If an operator's withdrawal would result in a violation of the Max Nomination Ratio, automatically refund excess nominated collateral to the nominators, proportionally. Both the operator withdrawal and the nominator refunds are subject to the unbonding period. #. If an Operator issued zero ONEBTC, it can deregister and automatically refund Nominators their collateral. #. When an Operator is banned, its collateralization is lowered to the secure collateral threshold by automatically refunding nominated ONE, proportionally. Data Model ~~~~~~~~~~ Scalars ------- NominationEnabled ................. Flag indicating whether this feature is enabled. As Operators may have issued ``ONEBTC`` with nominated collateral when this feature is turned off, a ``False`` value of this scalar only prevents the opting in of new Operators. MaxNominatorsPerOperator ........................ Maximum number of nominators a single operator can have. - Initial value: 100 OperatorUnbondingPeriod ....................... Unbonding period, measured in blocks, that Operator withdrawal requests are subject to. - Initial value: 14400 (24 hours) NominatorUnbondingPeriod ........................ Unbonding period, measured in blocks, that Nominator withdrawal requests are subject to. - Initial value: 7200 (12 hours) Maps ---- Operators ......... Mapping from accounts to Operator structs. Structs ------- Nominator ......... Stores the information of a Nominator. .. tabularcolumns:: |l|l|L| =========================== ================== ======================================================== Parameter Type Description =========================== ================== ======================================================== ``id`` AccountId The ID of the Nominator represented by this struct. ``collateral`` ONE Collateral amount nominated. ``pendingWithdrawals`` BTreeMap Mapping from the withdrawal request ID to the (maturityBlock, amount) tuple. ``collateralToBeWithdrawn`` ONE Collateral that is not backing any ONEBTC and has been requested for withdrawal. =========================== ================== ======================================================== Operator ........ Stores the information of an Operator. .. tabularcolumns:: |l|l|L| ============================ ================== ======================================================== Parameter Type Description ============================ ================== ======================================================== ``id`` AccountId The ID of the Nominator represented by this struct. ``nominators`` BTreeMap Mapping from the ID of a nominator to a Nominator struct. ``totalNominatedCollateral`` ONE Total amount of collateral received as nomination. ``pendingWithdrawals`` BTreeMap Mapping from the withdrawal request ID to the (maturityBlock, amount) tuple. ``collateralToBeWithdrawn`` ONE Collateral that is not backing any ONEBTC and has been requested for withdrawal. ============================ ================== ======================================================== Functions ~~~~~~~~~ .. _getMaxNominationRatio: getMaxNominationRatio ---------------------- Returns the maximum nomination ratio (as %), denoting the maximum ``totalNominatedCollateral:operatorCollateral`` value allowed. - Example (current parameterization): ``(1.5 / 1.2) - 1 = 25%`` Specification ............. *Function Signature* ``getMaxNominationRatio()`` Function Sequence ................. 1. Return ``(secureCollateralThreshold / auctionCollateralThreshold) - 1`` .. _setNominationEnabled: setNominationEnabled -------------------- Set the feature flag for vault nomination. Specification ............. *Function Signature* ``setNominationEnabled(enabled)`` *Parameters* * ``enabled``: ``True`` if nomination should be enabled, ``False`` if it should be disabled Function Sequence ................. 1. Ensure the calling account is root. 2. Set the NominationEnabled scalar to the value of the ``enabled`` parameter .. _optInToNomination: optInToNomination ----------------- Become an Operator in the Vault Nomination protocol Specification ............. *Function Signature* ``optInToNomination(operatorId)`` *Parameters* * ``operatorId``: the id of the vault to mark as Nomination Operator. *Events* * ``NominationOptIn(operatorId)`` *Errors* * ``VaultNominationDisabled``: the nomination feature is disabled. * ``NotAVault``: the caller of the function is not a vault. * ``VaultAlreadyOptedInToNomination``: the caller of the function is already opted in. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check if the nomination feature is enabled. If not, throw ``VaultNominationDisabled``. 2. Check if the caller is a vault. If not, throw ``NotAVault``. 3. Check if the caller is not already opted in to nomination. If not, throw ``VaultAlreadyOptedInToNomination``. 4. Instantiate an ``Operator`` struct. 5. Add the struct to the ``Operators`` mapping. .. _optOutOfNomination: optOutOfNomination ------------------ Deregister from being an Operator in the Vault Nomination protocol. Specification ............. *Function Signature* ``optOutOfNomination(operatorId)`` *Parameters* * ``operatorId``: the id of the vault to deregister from the nomination feature. *Events* * ``NominationOptOut(operatorId)`` *Errors* * ``VaultNotOptedInToNomination``: the caller is not an Operator. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check if the caller is a nomination Operator. If not, throw ``VaultNotOptedInToNomination``. 2. Immediately refund all nominated collateral, bypassing the unbonding period. 3. Remove caller from the ``Operators`` mapping. .. _depositNominatedCollateral: depositNominatedCollateral -------------------------- Nominate collateral to a selected Operator. Specification ............. *Function Signature* ``depositNominatedCollateral(nominatorId, operatorId, amount)`` *Parameters* * ``nominatorId``: the id of the user nominating collateral. * ``operatorId``: the id of the operator to receive the nomination. * ``amount``: the amount of collateral to nominate. *Events* * ``IncreaseNominatedCollateral(nominatorId, operatorId, amount)`` *Errors* * ``VaultNominationDisabled``: the nomination feature is disabled. * ``VaultNotOptedInToNomination``: the vault is not an Operator. * ``DepositViolatesMaxNominationRatio``: the `amount` of nomination would cause the Max Nomination Ratio to be exceeded for this `operatorId`. * ``OperatorHasTooManyNominators``: the number of Nominators to the current Operator has reached `MaxNominatorsPerOperator`. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check if the nomination feature is enabled. If not, throw ``VaultNominationDisabled``. 2. Check if ``operatorId`` represents an operator. If not, throw ``VaultNotOptedInToNomination``. 3. Check that the additional nominated ``amount`` does not cause the Max Nomination Ratio to be exceeded. If not, throw ``DepositViolatesMaxNominationRatio``. 4. If the caller had no nomination to this Operator, check that the ``MaxNominatorsPerOperator`` would not be exceeded by receiving this nomination. If ``MaxNominatorsPerOperator`` would be exceeded, throw ``OperatorHasTooManyNominators``. 5. Update the ``Operator`` object to create or update the ``Nominator`` entry of the caller. 6. Move collateral from ``nominatorId`` to the ``backing_collateral`` of ``operatorId`` in the :ref:`Vault-registry`. .. _requestOperatorCollateralWithdrawal: requestOperatorCollateralWithdrawal ----------------------------------- Request an operator collateral withdrawal, subject to an unbonding period. Specification ............. *Function Signature* ``requestOperatorCollateralWithdrawal(operatorId, amount)`` *Parameters* * ``operatorId``: the id of the caller. * ``amount``: the amount to withdraw. *Events* * ``RequestOperatorCollateralWithdrawal(requestId, operatorId, maturity, amount)`` *Errors* * ``VaultNotOptedInToNomination``: the caller is not an Operator. * ``InsufficientCollateral``: the caller has requested to withdraw more collateral than it owns. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check if ``operatorId`` is an operator. If not, throw ``VaultNotOptedInToNomination``. 2. Check if the operator has enough collateral of its own (excluding nominations). If not, throw ``InsufficientCollateral``. 3. Immediately refund, proportionally, nominated collateral that would cause the Max Nomination Ratio to be exceeded. 4. Add the withdrawal request to the ``pendingWithdrawals`` array in the ``Operator`` struct. 5. Decrease the ``backing_collateral`` of ``operatorId`` in the :ref:`Vault-registry`. .. _requestNominatorCollateralWithdrawal: requestNominatorCollateralWithdrawal ------------------------------------ Request a nominator collateral withdrawal, subject to an unbonding period. Specification ............. *Function Signature* ``requestNominatorCollateralWithdrawal(nominatorId, operatorId, amount)`` *Parameters* * ``nominatorId``: the id of the requester. * ``operatorId``: the id of the operator to withdraw from. * ``amount``: the amount to withdraw. *Events* * ``RequestNominatorCollateralWithdrawal(requestId, nominatorId, operatorId, maturity, amount)`` *Errors* * ``VaultNotOptedInToNomination``: the ``operatorId`` is not an Operator. * ``NominatorNotFound``: the ``nominatorId`` is not a Nominator. * ``TooLittleNominatedCollateral``: the caller has requested to withdraw more collateral than it owns. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check ``operatorId`` is an operator. If not, throw ``VaultNotOptedInToNomination``. 2. Check ``nominatorId`` is a nominator. If not, throw ``NominatorNotFound``. 3. Check if the caller has at least as much nominated collateral as ``amount``. If not, throw ``TooLittleNominatedCollateral``. 4. Add the withdrawal request to the ``pendingWithdrawals`` array in the ``Nominator`` struct for ``nominatorId``, inside the ``Operator`` struct of ``operatorId``. 5. Decrease the ``backing_collateral`` of ``operatorId`` in the :ref:`Vault-registry`. .. _executeOperatorWithdrawal: executeOperatorWithdrawal ------------------------- Execute all matured (unbonded) withdrawal requests of an operator. Specification ............. *Function Signature* ``executeOperatorWithdrawal(operatorId)`` *Parameters* * ``operatorId``: the id of the requester. *Events* * ``ExecuteOperatorCollateralWithdrawal(operatorId, unbondedCollateral)`` *Errors* * ``VaultNotOptedInToNomination``: the ``operatorId`` is not an Operator. * ``NoMaturedCollateral``: either no collateral withdrawal has been requested, or the requests have not matured yet. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check ``operatorId`` is an operator. If not, throw ``VaultNotOptedInToNomination``. 2. Iterate through the ``withdrawalRequests`` in the ``Operator`` struct to determine how much collateral was unbonded, removing matured requests. 3. If there is zero unbonded collateral, throw ``NoMaturedCollateral``. .. _executeNominatorWithdrawal: executeNominatorWithdrawal -------------------------- Execute all matured (unbonded) withdrawal requests of a nominator. Specification ............. *Function Signature* ``executeNominatorWithdrawal(nominatorId, operatorId)`` *Parameters* * ``nominatorId``: the id of the requester. * ``operatorId``: the id of the operator. *Events* * ``ExecuteNominatorCollateralWithdrawal(nominatorId, operatorId, unbondedCollateral)`` *Errors* * ``VaultNotOptedInToNomination``: the ``operatorId`` is not an Operator. * ``NoMaturedCollateral``: either no collateral withdrawal has been requested, or the requests have not matured yet. * ``NominatorNotFound``: the ``nominatorId`` is not a Nominator. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check ``operatorId`` is an operator. If not, throw ``VaultNotOptedInToNomination``. 2. Check ``nominatorId`` is a nominator. If not, throw ``NominatorNotFound``. 3. Iterate through the ``withdrawalRequests`` array in the ``Nominator`` struct inside the ``Operator`` struct for ``operatorId``. Determine how much collateral was unbonded, removing matured requests. 4. If there is zero unbonded collateral, throw ``NoMaturedCollateral``. .. _cancelOperatorWithdrawal: cancelOperatorWithdrawal ------------------------ Cancel an operator's withdrawal request. Specification ............. *Function Signature* ``cancelOperatorWithdrawal(operatorId, requestId)`` *Parameters* * ``operatorId``: the id of the operator. * ``requestId``: the id of the withdrawal request. *Events* * ``CancelOperatorCollateralWithdrawal(requestId, operatorId)`` *Errors* * ``VaultNotOptedInToNomination``: the ``operatorId`` is not an Operator. * ``WithdrawalRequestNotFound``: no withdrawal request found for the given id. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check ``operatorId`` is an operator. If not, throw ``VaultNotOptedInToNomination``. 2. Check ``requestId`` corresponds to an actual withdrawal request. If not, throw ``WithdrawalRequestNotFound``. 3. Remove the withdrawal request from the ``withdrawalRequests`` array in the ``Operator`` struct for ``operatorId``. 4. Increase the backing collateral of ``operatorId`` in the :ref:`Vault-registry` by the amount in the withdrawal request. .. _cancelNominatorWithdrawal: cancelNominatorWithdrawal ------------------------- Cancel a nominator's withdrawal request. Specification ............. *Function Signature* ``cancelNominatorWithdrawal(nominatorId, operatorId, requestId)`` *Parameters* * ``nominatorId``: the id of the nominator. * ``operatorId``: the id of the operator. * ``requestId``: the id of the withdrawal request. *Events* * ``CancelNominatorCollateralWithdrawal(requestId, nominatorId, operatorId)`` *Errors* * ``VaultNotOptedInToNomination``: the ``operatorId`` is not an Operator. * ``NominatorNotFound``: the ``nominatorId`` is not a Nominator. * ``WithdrawalRequestNotFound``: no withdrawal request found for the given id. Preconditions ............. * The BTC Bridge status in the :ref:`security` component must be set to ``RUNNING:0``. Function Sequence ................. 1. Check ``operatorId`` is an operator. If not, throw ``VaultNotOptedInToNomination``. 2. Check ``nominatorId`` is a nominator. If not, throw ``NominatorNotFound``. 3. Check ``requestId`` corresponds to an actual withdrawal request. If not, throw ``WithdrawalRequestNotFound``. 3. Remove the withdrawal request from the ``withdrawalRequests`` array in the ``Nominator`` struct inside the ``Operator`` struct for ``operatorId``. 4. Increase the backing collateral of ``operatorId`` in the :ref:`Vault-registry` by the amount in the withdrawal request. Events ~~~~~~ NominationOptIn --------------- *Event Signature* ``NominationOptIn(account)`` *Parameters* * ``account``: the id of the operator who opten in *Functions* * :ref:`optInToNomination` NominationOptOut ---------------- *Event Signature* ``NominationOptOut(account)`` *Parameters* * ``account``: the id of the operator who opten out *Functions* * :ref:`optOutOfNomination` IncreaseNominatedCollateral --------------------------- *Event Signature* ``IncreaseNominatedCollateral(nominatorId, operatorId, amount)`` *Parameters* * ``nominatorId``: the id of the nominator who is depositing collateral * ``operatorId``: the id of the operator who receives the nomination * ``amount``: the amount of nominated collateral *Functions* * :ref:`depositNominatedCollateral` RequestOperatorCollateralWithdrawal ----------------------------------- *Event Signature* ``RequestOperatorCollateralWithdrawal(requestId, operatorId, maturityBlock, amount)`` *Parameters* * ``requestId``: the id of the request * ``operatorId``: the id of the operator withdrawing collateral * ``maturityBlock``: the block when the request can be executed * ``amount``: the amount to withdraw *Functions* * :ref:`requestOperatorCollateralWithdrawal` ExecuteOperatorCollateralWithdrawal ----------------------------------- *Event Signature* ``ExecuteOperatorCollateralWithdrawal(operatorId, amount)`` *Parameters* * ``operatorId``: the id of the operator withdrawing collateral * ``amount``: the withdrawn amount *Functions* * :ref:`executeOperatorWithdrawal` CancelOperatorCollateralWithdrawal ---------------------------------- *Event Signature* ``CancelOperatorCollateralWithdrawal(requestId, operatorId)`` *Parameters* * ``requestId``: the id of the withdrawal request to cancel * ``operatorId``: the id of the operator who requested the withdrawal *Functions* * :ref:`cancelOperatorWithdrawal` RequestNominatorCollateralWithdrawal ------------------------------------ *Event Signature* ``RequestNominatorCollateralWithdrawal(requestId, nominatorId, operatorId, maturityBlock, amount)`` *Parameters* * ``requestId``: the id of the request * ``nominatorId``: the id of the operator withdrawing collateral * ``operatorId``: the id of the operator who nominated collateral is being withdrawn * ``maturityBlock``: the block when the request can be executed * ``amount``: the amount to withdraw *Functions* * :ref:`requestNominatorCollateralWithdrawal` ExecuteNominatorCollateralWithdrawal ------------------------------------ *Event Signature* ``ExecuteNominatorCollateralWithdrawal(nominatorId, operatorId, amount)`` *Parameters* * ``nominatorId``: the id of the operator withdrawing collateral * ``operatorId``: the id of the operator who nominated collateral is being withdrawn * ``amount``: the withdrawn amount *Functions* * :ref:`executeNominatorWithdrawal` CancelNominatorCollateralWithdrawal ----------------------------------- *Event Signature* ``CancelNominatorCollateralWithdrawal(requestId, nominatorId, operatorId)`` *Parameters* * ``requestId``: the id of the withdrawal request to cancel * ``nominatorId``: the id of the nominator who requested the withdrawal * ``operatorId``: the id of the operator who nominated collateral is being withdrawn *Functions* * :ref:`cancelNominatorWithdrawal`