Replace
Overview
The Replace module allows a Vault (oldVault) to be replaced by transferring the BTC it is holding locked to another Vault (newVault) which provides the necessary DOT collateral. The DOT collateral of the oldVault, corresponding to the amount of replaced BTC, is then unlocked. The oldVault must provide griefing collateral for spam protection which is paid to newVault on failure.
The oldVault is responsible for ensuring that it has sufficient BTC to pay for the transaction fees.
Conceptually, the Replace protocol resembles a SPV atomic cross-chain swap.
Step-by-Step
Precondition: a Vault (oldVault) has locked DOT collateral in the Vault Registry and has issued interBTC tokens - i.e., holds BTC on Bitcoin.
oldVault submits a replace request, indicating how much BTC is to be migrated by calling the requestReplace function.
oldVault is required to lock some amount of DOT collateral (ReplaceGriefingCollateral) as griefing protection, to prevent oldVault from holding newVault’s DOT collateral locked in the BTC Parachain without ever finalizing the redeem protocol (transfer of BTC).
Optional: oldVault can withdraw the request by calling the withdrawReplace function with a specified amount. For example, if oldVault requested a replacement for 10 tokens, and 2 tokens have been accepted by some newVault, then it can withdraw up to 8 tokens from being replaced.
A new candidate Vault (newVault), commits to accepting the replacement by locking up the necessary DOT collateral to back the to-be-transferred BTC (according to the SecureCollateralThreshold) by calling the acceptReplace function.
Note: from the oldVault’s perspective a redeem is very similar to an accepted replace. That is, its goal is to get rid of tokens, and it is not important if this is achieved by a user redeeming, or by a Vault accepting the replace request. As such, when a user requests a redeem with a Vault that has requested a replacement, the oldVault’s
toBeReplacedTokensis decreased by the amount of tokens redeemed by the user.
Within a pre-defined delay, oldVault must release the BTC on Bitcoin to newVault’s BTC address, and submit a valid transaction inclusion proof by calling the executeReplace function (call to
verifyTransactionInclusionin BTC-Relay). If oldVault releases the BTC to newVault correctly and submits the transaction inclusion proof to Replace module on time, oldVault’s DOT collateral is released - newVault has now replaced oldVault.Note: as with redeems, to prevent oldVault from trying to re-use old transactions (or other payments to newVaults on Bitcoin) as fake proofs, we require oldVault to include a
noncein an OP_RETURN output of the transfer transaction on Bitcoin.
Optional: If oldVault fails to provide the correct transaction inclusion proof on time, the newVault’s
collateralis unlocked and oldVault’sgriefingCollateralis sent to the newVault as reimbursement for the opportunity costs of locking up DOT collateral via the cancelReplace.
Security
Unique identification of Bitcoin payments: OP_RETURN
Vault Registry
The data access and state changes to the Vault Registry are documented in Fig. 17 below.
Fig. 17 The replace module interacts with functions in the Vault-Registry to handle updating token balances of vaults. The green lines indicate an increase, the red lines a decrease.
Fee Model
If a replace request is cancelled, the griefing collateral is transferred to the newVault.
If a replace request is executed, the griefing collateral is transferred to the oldVault.
Data Model
Scalars
ReplaceBtcDustValue
The minimum amount a newVault can accept - this is to ensure the oldVault is able to make the Bitcoin transfer. Furthermore, it puts a limit on the transaction fees that the oldVault needs to pay.
ReplacePeriod
The time difference between a replace request is accepted by another Vault and the transfer of BTC (and submission of the transaction inclusion proof) by the to-be-replaced Vault. Concretely, this period is the amount by which ActiveBlockCount is allowed to increase before the redeem is considered to be expired. The replace period has an upper limit to prevent griefing of Vault collateral. Each accepted replace request records the value of this field upon creation, and when checking the expiry, the maximum of the current ReplacePeriod and the value as recorded in the ReplaceRequest is used. This way, vaults are not negatively impacted by a change in the value.
Maps
ReplaceRequests
Vaults create replace requests if they want to have (a part of) their DOT collateral to be replaced by other Vaults. This mapping provides access from a unique hash ReplaceId to a ReplaceRequest struct. <ReplaceId, Replace>.
Structs
Replace
Stores the status and information about a single replace request.
Parameter |
Type |
Description |
|---|---|---|
|
AccountId |
Account of the oldVault that is to be replaced. |
|
AccountId |
Account of the newVault, which accepts the replace request. |
|
interBTC |
Amount of BTC / interBTC to be replaced. |
|
DOT |
Griefing protection collateral locked by oldVault. |
|
DOT |
Collateral locked by the new Vault. |
|
BlockNumber |
The ActiveBlockCount when the replace request was accepted by a new Vault. Serves as start for the countdown until when the old Vault must transfer the BTC. |
|
BlockNumber |
Value of ReplacePeriod when the redeem request was made, in case that value changes while this replace is pending. |
|
BtcAddress |
Vault’s Bitcoin payment address. |
|
u32 |
Height of newest bitcoin block in the relay at the time the request is accepted. This is used by the clients upon startup, to determine how many blocks of the bitcoin chain they need to inspect to know if a payment has been made already. |
|
Enum |
Status of the request: Pending, Completed or Cancelled |
Functions
requestReplace
The oldVault (to-be-replaced) submits a request to be (partially) replaced. If it requests more than it can fulfill (i.e. the sum of toBeReplacedTokens and toBeRedeemedTokens exceeds its issuedTokens), then the request amount is reduced such that the sum of toBeReplacedTokens and toBeRedeemedTokens is exactly equal to issuedTokens.
Specification
Function Signature
requestReplace(oldVault, btcAmount, griefingCollateral)
Parameters
oldVault: Account identifier of the Vault to be replaced (as tracked inVaultsin Vault Registry).btcAmount: Integer amount of BTC / interBTC to be replaced.griefingCollateral: collateral locked by the oldVault as griefing protection.
Events
Preconditions
The function call MUST be signed by oldVault.
The BTC Parachain status in the Security component MUST be set to
RUNNING:0.The oldVault MUST be registered.
The oldVault MUST NOT be banned.
The oldVault MUST NOT be nominated (if Vault Nomination is enabled).
If the
btcAmountis greater than the Vault’sreplacableTokens = issuedTokens - toBeRedeemTokens - toBeReplaceTokens, set thebtcAmountto thereplaceableTokensamount.The oldVault MUST provide sufficient
griefingCollateralsuch that the ratio of all of itstoBeReplacedTokensandreplaceCollateralis above ReplaceGriefingCollateral.The oldVault MUST request sufficient
btcAmountto be replaced such that its total is aboveReplaceBtcDustValue.
Postconditions
The oldVault’s
toBeReplacedTokensMUST be increased bytokenIncrease = min(btcAmount, vault.toBeIssuedTokens - vault.toBeRedeemedTokens).An amount of
griefingCollateral * (tokenIncrease / btcAmount)MUST be locked in the Griefing Collateral Currency by the oldVault in this transaction.The oldVault’s
replaceCollateralMUST be increased by the amount of collateral locked in this transaction.
withdrawReplace
The oldVault decreases its toBeReplacedTokens.
Specification
Function Signature
withdrawReplace(oldVault, tokens)
Parameters
oldVault: Account identifier of the Vault withdrawing it’s replace request (as tracked inVaultsin Vault Registry)tokens: The amount oftoBeReplacedTokensto withdraw.
Events
Preconditions
The function call MUST be signed by oldVault.
The BTC Parachain status in the Security component MUST NOT be set to
SHUTDOWN: 2.The oldVault MUST be registered.
The oldVault MUST have a non-zero amount of
toBeReplacedTokens.
Postconditions
The oldVault’s
toBeReplacedTokensMUST decrease by an amount oftokenDecrease = min(toBeReplacedTokens, tokens)The oldVault’s
replaceCollateralMUST decreased by the amountreleasedCollateral = replaceCollateral * (tokenDecrease / toBeReplacedTokens).The oldVault’s
releasedCollateralMUST be unlocked.
acceptReplace
A newVault accepts an existing replace request. It can optionally lock additional DOT collateral specifically for this replace. If the replace is cancelled, this amount will be unlocked again.
Specification
Function Signature
acceptReplace(oldVault, newVault, btcAmount, collateral, btcAddress)
Parameters
oldVault: Account identifier of the oldVault who requested replacement (as tracked inVaultsin Vault Registry).newVault: Account identifier of the newVault accepting the replace request (as tracked inVaultsin Vault Registry).replaceId: The identifier of the replace request inReplaceRequests.collateral: DOT collateral provided to match the replace request (i.e., for backing the locked BTC). Can be more than the necessary amount.btcAddress: The newVault’s Bitcoin payment address for transaction verification.
Events
Preconditions
The function call MUST be signed by newVault.
The BTC Parachain status in the Security component MUST NOT be set to
SHUTDOWN: 2.The oldVault and newVault MUST be registered.
The oldVault MUST NOT be equal to newVault.
The newVault MUST NOT be banned.
The newVault’s free balance MUST be enough to lock
collateral.The newVault MUST have lock sufficient collateral to remain above the SecureCollateralThreshold after accepting
btcAmount.The newVault’s
btcAddressMUST NOT be registered.The replaced tokens MUST be at least``ReplaceBtcDustValue``.
Postconditions
The actual amount of replaced tokens is calculated to be redeemableTokens = min(oldVault.toBeReplacedTokens, btcAmount).
The amount of griefingCollateral used is consumedGriefingCollateral = oldVault.replaceCollateral * (redeemableTokens / oldVault.toBeReplacedTokens).
The oldVault’s
replaceCollateralMUST be decreased byconsumedGriefingCollateral.The oldVault’s
toBeReplacedTokensMUST be decreased byredeemableTokens.The oldVault’s
toBeRedeemedTokensMUST be increased byredeemableTokens.The newVault’s
toBeIssuedTokensMUST be increased byredeemableTokens.The newVault locks additional collateral; its
backingCollateralMUST be increased bycollateral * (redeemableTokens / oldVault.toBeReplacedTokens).A unique replaceId must be generated from generateSecureId.
A new
ReplaceRequestMUST be added to the replace request mapping at the replaceId key.oldVault: MUST be theoldVault.newVault: MUST be thenewVault.amount: MUST beredeemableTokens.griefingCollateral: MUST beconsumedGriefingCollateralcollateral: MUST becollateral.accept_time: MUST be the current active block number.period: MUST be the currentReplacePeriod.btcAddress: MUST be thebtcAddressargument.btcHeight: UST be the current height of the btc-relay.status: MUST bepending.
executeReplace
The to-be-replaced Vault finalizes the replace process by submitting a proof that it transferred the correct amount of BTC to the BTC address of the new Vault, as specified in the ReplaceRequest. This function calls verifyAndValidateTransaction in BTC-Relay.
Specification
Function Signature
executeReplace(replaceId, rawMerkleProof, rawTx)
Parameters
replaceId: The identifier of the replace request inReplaceRequests.rawMerkleProof: Raw Merkle tree path (concatenated LE SHA256 hashes).rawTx: Raw Bitcoin transaction including the transaction inputs and outputs.
Events
Preconditions
The BTC Parachain status in the Security component MUST NOT be set to
SHUTDOWN:2.Both oldVault and newVault (as specified in the request) MUST be registered in the Vault Registry.
A pending
ReplaceRequestMUST exist with idreplaceId.The request MUST NOT have expired.
The
rawTxMUST decode to a valid transaction that transfers at least the amount specified in theReplaceRequeststruct. It MUST be a transaction to the correct address, and provide the expected OP_RETURN, based on thereplaceId.The
rawMerkleProofMUST contain a valid proof of ofrawTx.The Bitcoin payment MUST have been submitted to the relay chain, and MUST have sufficient confirmations.
Postconditions
The replaceTokens function in the Vault Registry MUST have been called, providing the
oldVault,newVault,replaceRequest.amount, andreplaceRequest.collateralas arguments.The griefing collateral as specifified in the
ReplaceRequestMUST be released back to oldVault’s free balance in the Griefing Collateral Currency.The
replaceRequest.statusMUST be set toCompleted.
cancelReplace
If a replace request is not executed on time, the replace can be cancelled by the newVault. Since the newVault provided additional collateral in vain, it can claim the oldVault’s griefing collateral.
Specification
Function Signature
cancelReplace(newVault, replaceId)
Parameters
newVault: Account identifier of the Vault accepting the replace request (as tracked inVaultsin Vault Registry).replaceId: The identifier of the replace request inReplaceRequests.
Events
Preconditions
The BTC Parachain status in the Security component MUST NOT be set to
SHUTDOWN:2.Both oldVault and newVault (as specified in the request) MUST be registered in the Vault Registry.
A pending
ReplaceRequestMUST exist with idreplaceId.The
newVaultMUST be equal to the newVault specified in theReplaceRequest.The request MUST have expired.
Postconditions
The cancelReplaceTokens function in the Vault Registry MUST have been called, providing the
oldVault,newVault,replaceRequest.amount, andreplaceRequest.amountas arguments.If newVault IS NOT liquidated:
If unlocking
replaceRequest.collateraldoes not put the collateralization rate of the newVault belowSecureCollateralThreshold, the collateral MUST be unlocked and itsbackingCollateralMUST decrease by the same amount.
The griefing collateral MUST BE slashed from the oldVault to the newVault’s free balance.
The
replaceRequest.statusMUST be set toCancelled.
Events
RequestReplace
Emit an event when a replace request is made by an oldVault.
Event Signature
* RequestReplace(oldVault, btcAmount, replaceId)
Parameters
oldVault: Account identifier of the Vault to be replaced (as tracked inVaultsin Vault Registry).btcAmount: Integer amount of BTC / interBTC to be replaced.replaceId: The unique identified of a replace request.
Functions
WithdrawReplace
Emits an event stating that a Vault (oldVault) has withdrawn some amount of toBeReplacedTokens.
Event Signature
WithdrawReplace(oldVault, withdrawnTokens, withdrawnGriefingCollateral)
Parameters
oldVault: Account identifier of the Vault requesting the replace (as tracked inVaultsin Vault Registry)withdrawnTokens: The amount by whichtoBeReplacedTokenshas decreased.withdrawnGriefingCollateral: The amount of griefing collateral unlocked.
Functions
ref:withdrawReplace
AcceptReplace
Emits an event stating which Vault (newVault) has accepted the ReplaceRequest request (requestId), and how much collateral in DOT it provided (collateral).
Event Signature
AcceptReplace(replaceId, oldVault, newVault, btcAmount, collateral, btcAddress)
Parameters
replaceId: The identifier of the replace request inReplaceRequests.oldVault: Account identifier of the Vault being replaced (as tracked inVaultsin Vault Registry)newVault: Account identifier of the Vault that accepted the replace request (as tracked inVaultsin Vault Registry)btcAmount: Amount of tokens the newVault just accepted.collateral: Amount of collateral the newVault locked for this replace.btcAddress: The address that oldVault should transfer the btc to.
Functions
ref:acceptReplace
ExecuteReplace
Emits an event stating that the old Vault (oldVault) has executed the BTC transfer to the new Vault (newVault), finalizing the ReplaceRequest request (requestId).
Event Signature
ExecuteReplace(oldVault, newVault, replaceId)
Parameters
oldVault: Account identifier of the Vault being replaced (as tracked inVaultsin Vault Registry)newVault: Account identifier of the Vault that accepted the replace request (as tracked inVaultsin Vault Registry)replaceId: The identifier of the replace request inReplaceRequests.
Functions
ref:executeReplace
CancelReplace
Emits an event stating that the old Vault (oldVault) has not completed the replace request, that the new Vault (newVault) cancelled the ReplaceRequest request (requestId), and that slashedCollateral has been slashed from oldVault to newVault.
Event Signature
CancelReplace(replaceId, newVault, oldVault, slashedCollateral)
Parameters
replaceId: The identifier of the replace request inReplaceRequests.oldVault: Account identifier of the Vault being replaced (as tracked inVaultsin Vault Registry)newVault: Account identifier of the Vault that accepted the replace request (as tracked inVaultsin Vault Registry)slashedCollateral: Amount of griefingCollateral slashed to newVault.
Functions
ref:cancelReplace
Error Codes
ERR_UNAUTHORIZED
Message: “Unauthorized: Caller must be newVault.”
Function: cancelReplace
Cause: The caller of this function is not the associated newVault, and hence not authorized to take this action.
ERR_INSUFFICIENT_COLLATERAL
Message: “The provided collateral is too low.”
Function: requestReplace
Cause: The provided collateral is insufficient to match the amount of tokens requested for replacement.
ERR_REPLACE_PERIOD_EXPIRED
Message: “The replace period expired.”
Function: executeReplace
Cause: The time limit as defined by the
ReplacePeriodis not met.
ERR_REPLACE_PERIOD_NOT_EXPIRED
Message: “The period to complete the replace request is not yet expired.”
Function: cancelReplace
Cause: A Vault tried to cancel a replace before it expired.
ERR_AMOUNT_BELOW_BTC_DUST_VALUE
Message: “To be replaced amount is too small.”
Function: requestReplace, acceptReplace
Cause: The Vault requests or accepts an insufficient number of tokens.
ERR_NO_PENDING_REQUEST
Message: “Could not withdraw to-be-replaced tokens because it was already zero.”
Function: requestReplace | acceptReplace
Cause: The Vault requests or accepts an insufficient number of tokens.
ERR_REPLACE_SELF_NOT_ALLOWED
Message: “Vaults can not accept replace request created by themselves.”
Function: acceptReplace
Cause: A Vault tried to accept a replace that it itself had created.
ERR_REPLACE_COMPLETED
Message: “Request is already completed.”
Function: executeReplace | cancelReplace
Cause: A Vault tried to operate on a request that already completed.
ERR_REPLACE_CANCELLED
Message: “Request is already cancelled.”
Function: executeReplace | cancelReplace
Cause: A Vault tried to operate on a request that already cancelled.
ERR_REPLACE_ID_NOT_FOUND
Message: “Invalid replace ID”
Function: executeReplace | cancelReplace
Cause: An invalid replaceID was given - it is not found in the
ReplaceRequestsmap.
ERR_VAULT_NOT_FOUND
Message: “The
Vaultcannot be found.”Function: requestReplace | acceptReplace | cancelReplace
Cause: The Vault was not found in the existing
Vaultslist inVaultRegistry.
Note
It is possible that functions in this pallet return errors defined in other pallets.