Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of Bitcoin depositor (tBTC Depositor) (#91)
The Acre Bitcoin Depositor contract is an implementation of a depositor contract mentioned in [RFC-11](https://github.com/keep-network/tbtc-v2/blob/main/docs/rfc/rfc-11.adoc). This contract serves as an integrator of tBTC Bridge and Acre stBTC staking contract. Bitcoin deposits revealed via the tBTC Depositor contract will be automatically staked in Acre after the tBTC minting process is completed on the tBTC network side. The contract is based on the `AbstractTBTCDepositor` (keep-network/tbtc-v2#778). The staking process consists of two steps: - `initializeStake` - this step reveals a deposit to tBTC Bridge to start the minting process - `finalizeStake` - this step should be called after tBTC minting on the tBTC Bridge side is completed, and tBTC token is transferred to the tBTC Depositor contract, this step calculates the approximate amount of minted tBTC tokens, and stakes them in stBTC contract. The functions are unprotected, meaning anyone can call them (e.g. bots). This solution will be used to enable a gasless minting experience for the users, where only a funding Bitcoin transaction will be required from them. ### tBTC Minting Fees The complexity comes with the actual minted tBTC amount calculation as the tBTC network fees are not unambiguously predictable. The stake finalization step calculates the amount to stake in Acre by deducting approximate tBTC network minting fees from the initial funding transaction amount. The calculation is performed in `AbstractTBTCDepositor._calculateTbtcAmount` function. The amount to stake is calculated d: `amount = depositAmount - depositTreasuryFee - optimisticMintingFee - depositTxMaxFee` These calculations are approximate and can leave some imbalance in the Depositor contract, as: - `depositTreasuryFee` - this is a precise value, snapshotted at the moment of deposit reveal, - `optimisticMintingFee` - this is an optimistic minting fee calculated at the moment of completion notification, there is a very low possibility that the fee was updated in the tBTC Vault contract between tBTC was minted and completion notification was submitted, - `depositTxMaxFee` - this is the maximum transaction fee that can be deducted on Bitcoin transaction sweeping, in most cases it will be higher than the actual deducted amount, and will grow the reserve in the depositor contract. For the great majority of the deposits, such an algorithm will return a tbtcAmount slightly lesser than the actual amount of TBTC minted for the deposit. This will cause some TBTC to be left in the contract and ensure there is enough liquidity to finalize the deposit. However, in some rare cases, where the actual values of those fees change between the deposit minting and finalization, the tbtcAmount returned by this function may be greater than the actual amount of TBTC minted for the deposit. If this happens and the reserve coming from previous deposits leftovers does not provide enough liquidity, the deposit will have to wait for finalization until the reserve is refilled by subsequent deposits or a manual top-up. The Acre governance is responsible for handling such cases. #### Fee changes simulation Please see the simulation performed by @lukasz-zimnoch for fee changes analysis: <details> <summary> Fee changes simulation </summary> **Case 1 - Deposit is optimistically minted (currently 98.6% of mainnet deposits)** Let's say a deposit is 100 BTC, `treasury_fee = 5%`, `opt_minting_fee = 3%` and `max_tx_fee = 0.01 BTC`. The actually minted amount will be `(100 BTC * 0.95) * 0.97 = 92.15 TBTC` and this will be in direct control of the depositor contract. The actual `tx_fee` remains as debt after the deposit is swept and we know it is lower than `max_tx_fee = 0.01 BTC` The depositor contract does the finalization AFTER the deposit is optimistically minted. If it uses the `tbtc_net_amount = btc_gross_amount - treasury_fee - opt_minting_fee - max_tx_fee` equation, it will compute `tbtc_net_amount = 100 BTC - 5 BTC - 2.85 BTC - 0.01 BTC = 92.14 TBTC`. Note that `92.15 - 92.14 = 0.01 TBTC` is in reserve to cover the `tx_fee` debt which is more than enough. Now, consider fee changes. Fee changes matters only if they occur between deposit mint and deposit finalization. Let's suppose the depositor contract received the aforementioned `92.15 TBTC`. This is the outcome if particular fees change between deposit mint and finalization: - If `treasury_fee` changes, it doesn't matter as we used the real snapshotted value - If `opt_minting_fee` increases, let's say to 5%, the `tbtc_net_amount = 100 BTC - 5 BTC - 4.75 BTC - 0.01 BTC = 90.24 TBTC`. That means `92.15 - 90.24 = 1.91 TBTC` stays in reserve - If `opt_minting_fee` decreases, let's say to 1%, the `tbtc_net_amount = 100 BTC - 5 BTC - 0.95 BTC - 0.01 BTC = 94.04 TBTC`. The loss is `92.15 - 94.04 = -1.89 TBTC`. If there is a reserve, we take from there. If not, we can either pay the full balance 92.15 or wait for the gov or next deposits to fill the gap (new deposits won't have this error) - If `max_tx_fee` increases to `0.05 BTC`, the `tbtc_net_amount = 100 BTC - 5 BTC - 2.85 BTC - 0.05 BTC = 92.10 BTC`. That means `92.15 - 90.10 = 0.05 TBTC` stays in reserve. We know that actual `tx_fee` accrued as debt will be lower so we are covered. The corner case here is `max_tx_fee` increases AFTER deposit finalization. This can make the real debt slightly uncovered but only if the actual tx_fee exceeds the old value of `max_tx_fee` - If `max_tx_fee` decreases to `0.002 BTC`, the `tbtc_net_amount = 100 BTC - 5 BTC - 2.85 BTC - 0.002 BTC = 92.148 BTC`. That means `92.15 - 92.148 = 0.002 TBTC` stays in reserve. We know that actual `tx_fee` accrued as debt will be lower so we are covered. The corner case here is `max_tx_fee` decreases AFTER deposit finalization. However, this is not a problem as the reserve will still be greater than the debt (we used old `max_tx_fee` to cut the reserve while the debt is below the new `max_tx_fee` value) ----- As you can see, almost all cases cause the positive imbalance and reserve increase. There are only two cases that cause negative imbalance: - `opt_minting_fee` decreases between deposit minting and finalization - `max_tx_fee` increases after deposit finalization The first case requires a very unfortunate timing. It becomes a real problem only when the reserve is not enough to cover the loss. We can decrease the probability by keeping the delay between minting and finalization as short as possible. The second case is similar. In practice, `max_tx_fee` never changed and the only reason to do so would be a global change of fee levels on Bitcoin. Moreover, the `max_tx_fee` is just a cap and the actual fee is always lower as tBTC clients estimate it according to the network circumstances. Last but not least, this becomes a real problem only in case a deposit is not optimistically minted but swept instead (currently 1.4% of mainnet deposits went this way) so part of their minted amount is used to repaid the accrued debt. It also requires that the reserve is not enough to cover the loss. **Case 2 - Deposit is not optimistically minted but swept (currently 1.4% of mainnet deposits)** Let's say a deposit is `100 BTC`, `treasury_fee = 5%`, `opt_minting_fee = 3%` and `max_tx_fee = 0.01 BTC` but the `actual tx_fee = 0.005 BTC`. The actually minted amount will be `100 BTC * 0.95 - 0.005 BTC = 94.995 TBTC` (`opt_minting_fee` is not accrued here) and this will be in direct control of the depositor contract. The depositor contract does the finalization AFTER the deposit is swept. If it uses the `tbtc_net_amount = btc_gross_amount - treasury_fee - opt_minting_fee - max_tx_fee` equation, it will compute `tbtc_net_amount = 100 BTC - 5 BTC - 2.85 BTC - 0.01 BTC = 92.14 TBTC`. Note that `94.995 - 92.14 = 2.855` TBTC stays in reserve. Now, consider fee changes. Fee changes matter only if they occur between deposit sweep and deposit finalization. Let's suppose the depositor contract received the aforementioned `94.995 TBTC`. This is the outcome if particular fees change between deposit sweep and finalization: - If treasury_fee changes, it doesn't matter as we used the real snapshotted value - If `opt_minting_fee` increases, let's say to 5%, the `tbtc_net_amount = 100 BTC - 5 BTC - 4.75 BTC - 0.01 BTC = 90.24 TBTC`. That means `94.995 - 90.24 = 4.755 TBTC` stays in reserve - If `opt_minting_fee` decreases, let's say to 1%, the `tbtc_net_amount = 100 BTC - 5 BTC - 0.95 BTC - 0.01 BTC = 94.04 TBTC`. That means `94.995 - 94.04 = 0.955 TBTC` stays in reserve - If `max_tx_fee` increases to `0.05 BTC`, the `tbtc_net_amount = 100 BTC - 5 BTC - 2.85 BTC - 0.05 BTC = 92.10 BTC`. That means `94.995 - 92.10 = 2.895 TBTC` stays in reserve. - If max_tx_fee decreases to `0.002 BTC`, the `tbtc_net_amount = 100 BTC - 5 BTC - 2.85 BTC - 0.002 BTC = 92.148 BTC`. That means `94.995 - 92.148 = 2.847 TBTC` stays in reserve. As you can see, fee changes in this case do not cause a negative imbalance at all. The only risk is that this deposit is partially used to repay previous debts. However, we are balancing this unlikely case by always deducting the `opt_minting_fee` fee which commits to the reserve. The risk that the reserve won't be enough is low here. </details> ### Maximum Stake Limit The Acre contract has a limit for the maximum amount of deposits it can accept. Due to an asynchronous manner of staking where Bitcoin has to be first bridged to tBTC via tBTC Bridge, the limit for deposits may be reached in the meantime of stake request initialization and finalization. In such cases, the stake request has to wait until more deposits are accepted by the Acre contract (the maximum limit is increased, or funds are withdrawn from the Acre contract, making space for new deposits). In this PR we added a path where stake requests that are unable to be finalized will be added to a queue and finalized later. If the user is not willing to wait anymore for the stake request to be finalized, they can recall the tBTC stake request and withdraw to their wallet the liquid tBTC that got minted. This solution should be improved further to not allow the user to reduce the possibility of such a situation happening. Different possibilities are being explored as part of #191. ----- Refs: #60 Depends on: keep-network/tbtc-v2#760
- Loading branch information