[ARFC] Deploy Aave v3 on BOB

solvBTC technical analysis


Summary

This is a technical analysis of all the smart contracts of the SolvBTC asset and its main dependencies.
No matter if the Aave on BOB network activation is done or not, the analysis is applicable for future listing appetite in other instances.


Disclosure: This is not an exhaustive security review of the asset like the ones done by the Solv 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

SolvBTC is a wrapped version of 1:1 Bitcoin across different EVM chains. Users can deposit BTC directly from the Bitcoin blockchain and receive SolvBTC on the BNB Chain, or mint using other wrapped Bitcoin assets (on BOB, only WBTC is acceptable). Users can also redeem through a two-step process by first requesting and then claiming.


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 important.
  • Analysis of the access control (ownerships, admin roles) and 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

  • Most system contracts can be upgraded with a 3-day Timelock, while two contracts have their upgradable admin set to an EOA.
  • It uses the OZ Beacon proxy for the SolvBTC implementation and the Transparent proxy pattern for other proxies.
  • For access control, it employs role-based and ownable standards.
  • For the token, it uses the SFT standard.
  • For the exchange rate, it uses different NAV values for deposit and redemptions.

Contracts

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



SolvBTC

It is an OZ BeaconProxy ERC20 contract with 2-step ownable and role-based access control. It represents 1:1 of BTC in the BOB ecosystem.

Permission Owner functions Criticality Risk
UpgradableBeaconSolvBTCFactory3-day Timelock upgradeTo CRITICAL :green_circle:
owner: Safe 3-of-5 destroyBlackFunds, updateBlacklistManager, transferOwnership HIGH :green_circle:
blacklist manager: Safe 3-of-5 addBlacklist, addBlacklistBatch, removeBlacklist, removeBlacklistBatch HIGH :green_circle:
DEFAULT_ADMIN_ROLE: 3-day Timelock grantRole, revokeRole HIGH :green_circle:
SOLVBTC_MINTER_ROLE: SolvBTCMultiAssetPool, BurnMintTokenPool (CCIP), xSolvBTCPool, TunnelContract (Free Tunnel Bridge) mint, burn HIGH :green_circle:
SOLVBTC_POOL_BURNER_ROLE: SolvBTCMultiAssetPool, xSolvBTCPool burn HIGH :green_circle:

  • Access Control

    • The owner can burn funds from a blacklisted address by calling the destroyBlackFunds(address) method.
    • The DEFAULT_ADMIN_ROLE can grant and revoke roles through the grantRole(role, address) and revokeRole(role, address) methods.
    • The SOLVBTC_MINTER_ROLE can mint new SolvBTC tokens and burn them to accounts not blacklisted via the mint(to, amount) and burn(from, amount) functions.
    • The SOLVBTC_POOL_BURNER_ROLE can also burn SolvBTC tokens via the burn(from, amount) function.
    • The blacklist manager can add and remove accounts from the blacklist by calling the addBlacklist(address) and removeBlacklist(address) methods. The manager can also add or remove multiple accounts in batches via the addBlacklistBatch(address[]) removeBlacklistBatch(address[]) functions.
  • Bridges

    • ChainLink CCIP: Chainlink CCIP transmits cross-chain messages between BOB and other blockchains through the Router contract. The BurnMintTokenPool is the facilitator that enables cross-chain transfers via the CCIP Router. It is configured with mint and burn capabilities on SolvBTC.
    • Free Tunnel Bridge: The Free Tunnel bridge enables cross-chain transfers between BOB and other blockchains through the FreeTunnelHub contract. The Tunnel Contract is the facilitator with minting and burning capabilities on SolvBTC. It is an Atomic-Lock-Mint/Atomic-Burn-Mint system where, through the FreeTunnelHub contract, users initiate cross-chain transfers by proposing to burn their assets, and in the destination chain, the Tunnel admin proposes the mint. Then, on the origin chain, the tokens are burned, and in the destination chain, the tokens are minted.

SolvBTCRouter

The SolvBTC Router serves as the starting point for users to mint and redeem SolvBTC by interacting with the SolvBTCMultiAssetPool. It is an OZ Transparent Proxy with a two-step ownable access control.

Permission Owner functions Criticality Risk
ProxyAdmin3-day Timelock upgrade, upgradeAndCall CRITICAL :green_circle:
Admin: Safe 3-of-5 setOpenFundMarket, setSolvBTCMultiAssetPool, transferAdmin HIGH :yellow_circle:

  • Access Control

    • The admin can configure the OFM and the SolvBTCMultiAssetPool addresses via the setOpenFundMarket(address) and setSolvBTCMultiAssetPool(address) methods.
  • Minting and Redemptions

    • Users can mint SolvBTC on BOB by depositing WBTC through the createSubscription(pool Id, amount) method. Internally, it first validates that pool Id is the SolvBTC and creates a subscription in the OFM (Open Fund Market) contract by calling OFM.subscribe(pool Id, amount, open fund share, expire) which calculates the amount of shares the user will receive through a navOracle contract (basically a contract to determine the denominator that controls how many shares per subscription the user gets*; for WBTC, the exchange rate is set at 1:0.9975).* and mints the amount as an SFT (Semi Fungible Token) to the router. Then, the router deposits the SFT amount in the SolvBTCMultiAssetPool contract via the SolvBTCMultiAssetPool.deposit(SFT, id, amount), which sends the SolvBTC amount to the user.
    • Users can redeem their SolvBTC using the createRedemption(pool Id, amount) function. Internally, after transferring the SolvBTC to the router, it withdraws the SFT from the SolvBTCMultiAssetPool and creates a request in the OFM contract by calling the OFM.requestRedeem(pool Id, amount), which mints a redemption SFT to the user. After 7 days, the user can claim their tokens from the Redemption SFT contract using the openFundRedemption.claimTo(to, tokenId, token, amount) which burns the SFT. It’s important to mention that no fee is applied for redemptions. Therefore, in the case of redemptions on BOB from SolvBTC to WBTC, the conversion ratio is 1:1.
    • It is also possible to cancel the request via the cancelRedemption(pool Id, sft redemption Id), which will transfer the redemption SFT to the router and mint back the SolvBTC tokens to the user.

OpenFundMarket

It is the contract that creates and tracks pools of SolvBTC and handles minting of SFT tokens for the router. It’s a Transparent Proxy contract with a two-step ownable access control.

Permission Owner functions Criticality Risk
ProxyAdminEOA (0x55C0…013E) upgrade, upgradeAndCall CRITICAL :red_circle:
Admin: Safe 3-of-5 setGovernorOnlyAdmin HIGH :red_circle:
Governor: EOA (0x55C0…013E) updatePoolInfoOnlyGovernor, setCurrencyOnlyGovernor, addSFTOnlyGovernor, removeSFTOnlyGovernor, setProtocolFeeOnlyGovernor, updateFundraisingEndTime HIGH :red_circle:
Pool Managers: WBTC → EOA (0x2e51…2BB0) setWhiteList, closeCurrentRedeemSlot, removePool HIGH :red_circle:
subscribeNavManager: Safe 1-of-3 setSubscribeNav HIGH :red_circle:
redeemNavManager: Safe 1-of-3 setRedeemNav, updateFundraisingEndTime HIGH :red_circle:

  • Access Control

    • The admin can configure the governor address through the setGovernorOnlyAdmin(address) method.
    • New SolvBTC Pools are created permissionlessly through the createPool(Pool Info) function; however, the Governor needs to enable the token that this pool will receive in exchange for SolvBTC via the setCurrencyOnlyGovernor(address) function and enable both the SFT OpenFundMarket and the SFT OpenFundRedemption addresses and their manager via the addSFTOnlyGovernor(address sft, address manager) method.
    • The Governor can change the pool configuration via the updatePoolInfoOnlyGovernor(), including max cap, min, and max values of subscription, and subscription and redemption NAV addresses.
    • The Governor can remove the SFT OpenFund Market and Redemption info by calling the removeSFTOnlyGovernor(address sft) . This will disable the pool.
    • Pool managers can whitelist addresses through the setWhiteList(address) function. By whitelisting an address, the pool becomes non-permissionless, and only those whitelisted addresses can subscribe for the SFT shares.
    • Pool managers can delete a pool by calling the removePool(Pool Id) function, which is only possible if no subscriptions have been made.
    • The subscribe Nav Manager can configure new pools and their nav value (used to calculate the exchange rate) in the navOracle via the setSubscribeNav(Pool Id, nav) function. While the redeem Nav Manager via the setRedeemNav(Pool Id, nav) function.
    • The redeem Nav Manager and the Governor can set a new period in which it is possible to fund the pool, via the updateFundraisingEndTime(Pool Id, time).
  • Subscription and Redemption

    • The router mainly, but users can also subscribe (mint SFT shares that can be deposited in exchange for SolvBTC tokens) by calling the subscribe(poolId, amount, openFundShareId, expireTime) function. It first validates whether the poolId exists, and if the cap has been reached by minting the amount. After all validations, the OFM contract calls the mintValueOnlyIssueMarket() in the SFT token, which sends the SFT shares to the msg.sender (router or users). It is important to mention that this function does not mint any SolvBTC; instead, it issues SFT shares, which are used to mint SolvBTC through the SolvBTCMultiAssetPool contract.
    • The router or users can request a redemption by calling the requestRedeem(poolId, openFundShareId, openFundRedemptionId, amount) method. After checking whether the request is enabled and if the poolId exists, it will call the SFT openFundRedemption token and mint via the mintOnlyIssueMarket() a redemption NFT, which will be used to claim the underlying assets later (WBTC in this case).
    • Requests can also be canceled through the revokeRedeem(poolId, openFundRedemptionId) method.
    • The pool manager can complete a current redemption request and start a new round via the closeCurrentRedeemSlot(Pool Id) function. It will retrieve the latest redeem slot and verify if it is closed at least 24h after the previous request, and call the OpenFundRedemption to create a new slot with the data of the latest redemption using the OPR.createSlotOnlyIssueMarket(RedeemInfo) to allow users to claim their underlying tokens later.

OpenFundRedemption

The OpenFundRedemption is the contract for users to claim their requested redemptions. It is an OZ Beacon Proxy with a 2-step ownable for access control.

Permission Owner functions Criticality Risk
Admin → BeaconFactoryEOA (0x55C0…013E) upgradeTo, setConcreteOnlyAdmin CRITICAL :red_circle:
OpenFundMarket createSlotOnlyIssueMarket, setRedeemNavOnlyMarket HIGH :green_circle:

  • Access Control

    • The admin can set the OpenFundRedemptionConcrete contract calling the setConcreteOnlyAdmin(address) function. This OFR Concrete contract is used to store data related to slots, token IDs, and claimable amounts.
    • The OFM contract can create slots with data regarding the underlying token and its pool ID via the createSlotOnlyIssueMarket(SlotInfo) function.
    • The OFM contract can set the redemption nav for at a slot via the setRedeemNavOnlyDelegate(slot, nav) function. The nav is the value of shares with the decimal places used during the redemption.
  • Claim redemption request

    • Users can claim their request via the claimTo(to, tokenId, currency, value) function. Internally, it validates whether the user is the owner or has permissions for the tokenId, whether the currency is a valid underlying token, and whether the value is claimable. Then, it calls the OFR Concrete to update the internal claimable slot storage of the tokenIdThe system burns the users’ SFT shares and transfers the underlying token to the user.

SolvBTCMultiAssetPool

The MultiAssetPool is the contract that interacts directly with the SolvBTC by minting or burning tokens. It can receive different SFT tokens minted with different underlying (on BOB only WBTC) and, in exchange, will mint/burn the new SolvBTC tokens. It’s an OZ Transparent proxy with 2-step ownable/admin access control.

Permission Owner functions Criticality Risk
ProxyAdmin3-day Timelock upgrade, upgradeAndCall CRITICAL :green_circle:
Admin: Safe 3-of-5 addSftSlotOnlyAdmin, changeSftSlotAllowedOnlyAdmin, transferAdmin HIGH :yellow_circle:

  • Access Control

    • The admin can add new SFT slots for specific ERC20 underlying tokens via the addSftSlotOnlyAdmin(sft, slot, token, holdingValueSftId) function. It first validates that the slot is new and wasn’t configured previously with another ERC20 token, then if holdingValueSftId > 0, it checks if the slot matches the slot parameter, and if the MultiAssetPool contract is the owner of the SftId of the holdingValueSftId. After those validations, deposits and withdrawals of the SFT in that specific slot are enabled.
    • The admin can modify deposits and withdrawals from a specific SFT slot via the changeSftSlotAllowedOnlyAdmin(sft, slot, depositAllowed, withdrawAllowed) function.
  • Deposits and Withdraws

    • The router mainly, but users with SFT shares can mint SolvBTC via the deposit(sft, sftId, value) function. It validates that deposited SFT shares are allowed in the slot of the sftId and then mints the value of SolvBTC tokens.
    • The router mainly, but users can withdraw SFT shares by calling the withdraw(sft, slot, sftId, value). Internally, it checks if withdrawals are enabled in the slot of the sftId and then burns the SolvBTC tokens and sends the equivalent value of SFT shares.

Pricing strategy

See Conclusion.

Miscellaneous

  • The system has undergone audits by OZ, Paladin, Salus, and Quantstamp that can be found here.
  • In general, the system relies on Multisig and EOAs for upgradability and configuration, which could pose several risks to the asset if, for example, the EOA keys are compromised and the contracts are upgraded to malicious implementations. We suggested the team adjust the general configuration with multisig wallets and timelocks.

Conclusion

We think the complexity of solvBTC, in combination with the highly centralized access control of different critical parts of the system (especially the OpenFundMarket), doesn’t make the asset suitable for onboarding on Aave at the current moment.

Once the team does an overall review of the access control and improves it, we will be able to re-evaluate.

Its yield-bearing version (xSolvBTC) is dependent on the underlying being suitable for listing.