[ARFC] Onboard LBTC on Aave v3 Core Instance

LBTC (Lombard) technical analysis

Summary

This is a technical analysis of all the smart contracts of the LBTC asset and main dependencies.

Disclosure: This is not an exhaustive security review of the asset like the ones done by the Lombard team, but an analysis from an Aave technical service provider on different aspects we consider critical to review before a new type of listing. Consequently, like with any security review, this is not an absolute statement that the asset is flawless, only that, in our opinion, we don’t see significant problems with its integration with Aave, apart from different trust points.


Analysis

LBTC is a wrapped version of BTC on EVM chains backed by 1:1 BTC reserves, staked in Babylon: users stake their BTC through Babylon and receive 1:1 LBTC that can seamlessly integrate into DeFi applications.

LBTC is also a yield-bearing token, which continues to accrue staking rewards from its staked BTC. Users can also burn LBTC and receive the BTC on Bitcoin.



For the context of this analysis, our focus has been on the following aspects, critical for the correct and secure integration with Aave:

  • A recommendation of pricing strategy to be used in the integration asset <> Aave.
  • Any miscellaneous aspect of the code we can consider of importance.
  • Analysis of the access control (ownerships, admin roles), the nature of the entities involved in the system. Regarding the table permissions’ holders and their criticality/risk, it is done following these guidelines:

Criticality Description
CRITICAL Usually super-admin functionality: it can compromise the system by completely changing its fundamentals, leading to loss of funds if misused or exploited. E.g. proxy admin, default admin
HIGH It can control several parts of the system with some risk of losing funds. E.g., general owners or admin roles involved in the flow of funds
MEDIUM It can cause malfunction and/or minor financial losses if misused or exploited. E.g., fee setter, fee recipient addresses
LOW It can cause system malfunctions, but on non-critical parts without meaningful/direct financial losses. E.g., updating descriptions or certain non-critical parameters.

Risk Description
:green_circle: The role is controlled via a mechanism we consider safe, such as on-chain governance, a timelock contract, or setups involving multi-sigs under certain circumstances.
:yellow_circle: The role is controlled in a way that could expose the system and users to some risk depending on the actions it can control.
:red_circle: The role is controlled via a clearly non-secure method, representing risks for the system and users.

General points

  • The upgradeability admin of the LBTC system is a Timelock (Lombard Timelock) with a 24-hour delay period.
  • It uses an OZ transparent proxy pattern for proxies. Non-upgradable contracts, like the Bascule Drawbridge (technically external to LBTC), use OZ contract extensions, such as Access Control with role-based, Pausable, and the Math library.
  • LBTC also includes of off-chain modules divided into:
    • A consortium system for management across the BTC transactions, where the participants (consortium nodes) perform validations and sign transactions for stake/unstake from Babylon, or mint/burn LBTC across the EVM chains. The consortium generates BTC wallets and verifies deposits before signing any data that confirms the transaction.
    • The so-called CubeSigner hardware manages the keys of the BTC wallets. It protects the keys to be extracted, restricts which transactions can be signed by whom, requests a 3-of-5 approval (MPA) from the consortium members to be validated, and timelocks the keys to safeguard multiple transactions to be signed.
    • A general backend that tracks addresses with staked BTC listens to user transactions and communicates with the consortium by requesting the deposit/withdrawal data be signed, depending on the user’s action.

Contracts

The following is a non-exhaustive overview of the main smart contracts involved with LBTC.



LBTC

The so-called Liquidity BTC is an upgradeable ERC20 contract in which users can mint and burn LBTC, representing 1:1 of their staked BTC, and bridge it across supported EVM chains.

Its access control is managed through role-based permissions using OZ Ownable2StepUpgradeable and a custom pauser role mechanism.

Permission Owner functions Criticality Risk
proxy AdminLombardTimeLock upgradeAndCall() CRITICAL :green_circle:
general owner: LombardTimelock transferOwnership(), renounceOwnership(), toggleWithdrawals(), changeConsortium(), changeBascule(), transferPauserRole(), CRITICAL :green_circle:
general owner: LombardTimelock addDestination(), removeDestination() HIGH :green_circle:
pauser: Safe 2-of-8 pause(), unpause() HIGH :green_circle:
general owner: LombardTimelock changeDepositAbsoluteCommission(), changeDepositRelativeCommission(), changeTreasuryAddress(), changeBurnCommission(), changeDustFeeRate(), changeNameAndSymbol() MEDIUM :green_circle:

Access Control

  • The owner (Lombard Timelock) can add and remove supported chains via the addDestination(chain) and removeDestination(chain) functions.
  • The owner can change the contract’s ERC20 name and symbol via the changeNameAndSymbol(name, symbol) function.
  • The owner can enable/disable withdrawals via the toggleWithdrawals() function.
  • The owner can update the fees on LBTC operations (burn and bridge) by calling the changeBurnCommission(fee), changeDustFeeRate(fee), changeDepositAbsoluteCommission(fee), and changeDepositRelativeCommission(fee) functions.
  • The owner can update the consortium, bascule drawbridge, treasury, and pauser addresses via the changeConsortium(address), changeBascule(address), changeTreasuryAddress(address), and transferPauserRole(address) functions.
  • The pauser role can pause and unpause the contract via the pause() and unpause() functions.

Mint and Burn

  • Minting LBTC starts with the user sending their BTC to a staking address managed by the consortium. Once the deposit is confirmed by the consortium and reported in the bascule drawbridge, the user receives encoded data with uint256 chainId, address to, uint64 amount, bytes32 txId, uint32 index, and the keccak256 hash of the data signed by the Consortium threshold key.
    Right after, With this data in hand, the user can finally initiate the mint via the mint(data, signature) function. Internally, it verifies if the signature is signed by the consortium address in the _checkAndUseProof() function, stores it to avoid replay attacks, and confirms in the bascule bridge.
  • The user initiates the unstake of their BTC by calling the redeem(BTCAddress, amount) function, which checks internally if the BTCAddress is valid and if the amount is not below the dust amount set by the owner.
    Then, the backend listens to the burn event and informs the consortium about the unstake. The consortium validates the request and builds the BTC transaction so the CubeSigner can sign the transaction with the consortium members to transfer the BTC to the user’s address.
    The unstaking period lasts 9 days on Babylon and Lombard.

Bridging

  • Users can bridge their LBTC to supported chains (currently mainnet, Binance Smart Chain, Base, and Corn) via the depositToBridge(chain, address, amount) function. Internally, it checks if the chain is supported and discounts the bridge fee before burning the tokens. Then, the backend listens to the bridge event and communicates to the consortium so it can validate, report to the bascule drawbridge, and provide data with uint256 chainId, address to, uint64 amount, bytes32 txId, uint32 index, and the keccak256 hash of the data signed by the Consortium threshold key.
    On the destination chain, the user, with this data in their hands, finalizes the bridge by claiming their tokens via the withdrawFromBridge(data, signature) function. This function internally checks if the data is correct and the signature is from the consortium address in the _checkAndUseProof() function.
    Finally, it is double-confirmed in the bascule bridge, and the tokens are sent to the user.
    In the case of the Corn blockchain, the tokens are locked on the source chain and minted on the destination chain.

LombardConsortium

It’s an upgradeable ERC1271 contract that verifies signatures for a given hash.
Responsible for checking whether the hash is signed by a threshold address stored in the contract. It is upgradeable by the Lombard Timelock.


Permission owner functions Criticality Risk
proxy adminLombardTimelock upgradeAndCall() CRITICAL :green_circle:
general owner: LombardTimelock transferOwnership(), renounceOwnership(), changeThresholdAddr(), HIGH :green_circle:

  • The contract owner (LombardTimelock) can set a different threshold address by calling the changeThresholdAddr(address) function.
  • This contract mainly validates signatures via the isValidSignature(hash, signature) function. It validates via ECDSA recovery if the hash signed by the signature is equivalent to the threshold address.


Bascule Drawbridge

The Bascule is a non-upgradeable contract responsible for registering deposits with unique deposit IDs and validating them when users request to mint LBTC or redeem BTC. It uses an OZ roles-based access control.

Important to highlight is designed to be a third-party extra security layer (on top of the consortium), and it is controlled by a separate team and infrascture: Cubist.

Permission owner functions Criticality Risk
DEFAULT_ADMIN_ROLE: EOA 0xC8bd…0889 (MPC by Cubist) grantRole(), revokeRole(), setMaxDeposits(), updateValidateThreshold() MEDIUM :yellow_circle:
DEPOSIT_REPORTER_ROLE: EOA 0xfa70…B3fe reportDeposits() MEDIUM :green_circle:
WITHDRAWAL_VALIDATOR_ROLE: LBTC contract validateWithdrawal() MEDIUM :green_circle:
VALIDATION_GUARDIAN_ROLE: not assigned updateValidateThreshold() MEDIUM :green_circle:

Access Control

  • Permissions in the contract are divided into DEFAULT_ADMIN_ROLE, PAUSER_ROLE, DEPOSIT_REPORTER_ROLE, WITHDRAWAL_VALIDATOR_ROLE, and VALIDATION_GUARDIAN_ROLE, with the DEFAULT_ADMIN_ROLE as responsible for setting the other roles.
  • The DEFAULT_ADMIN_ROLE (EOA 0xC8bd…0889) can set the maximum number of deposits that can be reported at once by calling the setMaxDeposits(value) function.
  • The PAUSER_ROLE (EOA 0x1E07…32aC) can pause or unpause the contract via the pause() and unpause() functions.
  • The VALIDATION_GUARDIAN_ROLE (not assigned) can update the withdrawal validation threshold via the updateValidateThreshold(value) function. However, the validation guardian role can only increase the threshold (validate fewer deposits), and its role is renounced right after execution, while the default admin can lower the threshold.

Validation Process

  • The DEPOSIT_REPORTER_ROLE (EOA 0xfa70…B3fe) is the main responsible for reporting all BTC deposits into the stake addresses via the reportDeposits(reportId, depositIDs[]). Internally, it verifies whether the number of reported deposits exceeds the maximum set and whether each depositID wasn’t previously reported.
  • The WITHDRAWAL_VALIDATOR_ROLE (LBTC contract) verifies the user’s deposit transaction status via the validateWithdrawal(depositID, amount) function. It checks whether the depositID has already been withdrawn and whether the amount is above the threshold.


Miscellaneous

  • The system has multiple security reviews: one on its V1 release by Halborn and Veridise and another on its V2 release by OpenZeppelin and Veridise. The reports can be found here.
  • A Chainlink PoR (Proof of Reserve) is on the works (HERE). Additionally, the system has a RedStone’s Proof of Reserves oracle on mainnet, Base, and BSC, updated every 24 hours or if it deviates more than 1%. The PoRs can be visualized on their Dune reserves page.
  • Because BTC is built on top of Babylon, it’s important to mention that slashing events can occur if validators take bad actions, such as double-signing. Slashing is not currently live but will be implemented in the future Babylon phase roadmap.


Asset pricing

Even if more an aspect to analyse on the side of the risk providers, secondary market pricing is not really recommended from our side, given that the asset has very thin liquidity and consequently, risk of manipulation.
Therefore, as we think the asset security is robust enough, pricing based on BTC/USD seems reasonable.

Complementary, we think the following aspects are very important to consider on the final listing risk parameters:

  • At the moment, the asset doesn’t accrue rewards, but it will in the future (depending on the activation of the mechanism on Babylon). It is very important to monitor this, as the usage of a BTC/USD price feed will misprice the asset when rewards are enabled. Worth to mention that if only used as collateral, using BTC/USD with rewards enabled would only undervalue the asset, technically only hurting users borrowing against LBTC and not suppliers.
  • The redeeming time from LBTC to BTC is relatively long, so liquidation bonus (in any e-mode) should be high enough to always keep liquidations profitable. Especially in e-mode/default combinations with no correlation, like LBTC collateral and stablecoins borrowings.


Conclusion

We think LBTC doesn’t have any problem in terms of integration with Aave, and there is no major technical blocker for listing.

3 Likes