# Anchor Vault + BridgeConnectorWormhole audit Anchor Vault is a smart contract that allows to convert rebasing stETH token into a constant-balance bETH token and periodically send all accrued stETH rewards to the Terra blockchain through a bridge. The bETH token is used as a collateral in the Terra Anchor protocol. The Anchor Vault is deployed & functions already, and was [audited by MixBytes()](https://github.com/lidofinance/audits/blob/main/MixBytes%20bETH%20Vault%20Security%20Audit%20Report.pdf) on July, 30th, 2021. The main reason for the audit request is the coming migration from the Shuttle bridge to the Wormhole. The Vault's [`bridge_connector`](https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/AnchorVault.vy#L101) would be set to `BridgeConnectorWormhole` contract (to be deployed). ## Scope of the audit Commit: https://github.com/lidofinance/anchor-collateral-steth/commit/8d52ce72cb42d48dff1851222e3b624c941ddb30 ### Contracts - AnchorVault: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/AnchorVault.vy (the main vault contract) - AnchorVaultProxy: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/AnchorVaultProxy.sol (proxy contract for AnchorVault) - bEth: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/bEth.vy (bETH token contract) - RewardsLiquidator: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/RewardsLiquidator.vy (a contract for selling stETH rewards to UST) - InsuranceConnector: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/InsuranceConnector.vy (a contract for obtaining the total number of shares burnt for the purpose of insurance/cover application from the Lido protocol) - BridgeConnectorWormhole: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/contracts/BridgeConnectorWormhole.vy (an adapter contract for communicating with the Wormhole bridge) ### Deployed contracts & Deployment The contracts aside from the `BridgeConnectorWormhole` are deployed to the Ethereum mainnet: - AnchorVault: https://etherscan.io/address/0xA2F987A546D4CD1c607Ee8141276876C26b72Bdf (proxy) - AnchorVault: https://etherscan.io/address/0x0627054d17eae63ec23c6d8b07d8db7a66ffd45a (impl) - RewardsLiquidator: https://etherscan.io/address/0x082a5956D63b44685a7CCA89379D565C439fdf3C - InsuranceConnector: https://etherscan.io/address/0x2BDfD3De0fF23373B621CDAD0aD3dF1580efE701 Currently integration uses the Shuttle bridge for cross-chain interactions. The bridge connector contract is deployed there: - BridgeConnectorShuttle: https://etherscan.io/address/0x513251faB2542532753972B8FE9A7b60621affaD Deployment script with post-deployment tests for the current integration can be found here: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/scripts/final_check.py. Wormhole bridge connector deployment scripts can be found here: - `deploy_wormhole_connector`: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/scripts/deploy_wormhole_connector.py - `wormhole_connector_check`: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/scripts/wormhole_connector_check.py ### Tests Tests are located in https://github.com/lidofinance/anchor-collateral-steth/tree/8d52ce72cb42d48dff1851222e3b624c941ddb30/tests. Note that the Wormhole bridge connector tests are here: https://github.com/lidofinance/anchor-collateral-steth/blob/8d52ce72cb42d48dff1851222e3b624c941ddb30/tests/test_connector_wormhole.py ### Architecture `RewardsLiquidator`, `InsuranceConnector` and `BridgeConnectorWormhole` contracts are installed as delegates to the AnchorVault contract and are used by the latter for performing various tasks (see the description above). These contracts can be replaced by the vault admin. The `BridgeConnectorWormhole` contract is designed to interoperate with the Wormhole Ethereum-Terra bridge. The Bridge contract source code can be found here: https://github.com/certusone/wormhole/blob/9bc408ca1912e7000c5c2085215be9d44713028b/ethereum/contracts/bridge/Bridge.sol ## Vault mechanics ### bETH issuance Minting bETH: a user can submit stETH to the vault contract and receive the corresponding amount of freshly-minted bETH tokens which get immediately transferred to a user-specified Terra address via the bridge. The received stETH tokens are locked inside the vault contract. Burning bETH: a user can burn their bETH tokens (which should be already on the Ethereum side) in exchange for stETH tokens from the vault’s balance. The amount of bETH minted per one stETH locked, as well as the amount of stETH released per one bETH burnt, is determined by the current bETH/stETH rate. Normally, this rate is 1, but it might become less than 1 if Lido validators get penalized or slashed. If that happens, the only way of recovering the rate would be applying protocol-wide insurance. The rate cannot be greater than 1. ### stETH rebases stETH is a rebasable token. Balance of each address is internally represented in non-normalized shares, where total number of shares is not bounded, and stETH balance is calculated from shares balance as follows: ``` steth_balance(address) = shares_balance(address) * share_price share_price = total_lido_controlled_ether / total_shares ``` Rebases are performed as a result of Lido oracles reporting Beacon chain rewards or penalties, which results in `total_lido_controlled_ether` changing (and hence balances of all stETH holders increasing or decreasing). This happens once in ~24h. A rebase might also be triggered by applying protocol-wide insurance, which is done by minting stETH in exchange for ETH (which proportionally increases both `total_lido_controlled_ether` and `total_shares`) and burning the minted stETH shares right away, which results in `total_shares` decreasing and `share_price` increasing. The total number of shares burnt to apply insurance since the protocol inception is tracked by the protocol and stored onchain. ### stETH rewards handling All increases in AnchorVault’s stETH balance that result from Beacon rewards should be periodically sold to UST (Anchor-issued stablecoin) and forwarded to a pre-defined Terra address via the bridge. Balance increases resulting from insurance applications should NOT be sold to UST and should instead result in recovering bETH/stETH rate. stETH rebases happen at most once in 24h. Once a rebase has occured, the vault should prohibit submitting and withdrawing stETH until the rewards accrued since the last sell are sold to UST and forwarded to Terra. It should be impossible to sell rewards twice within 24h. ### BridgeConnectorWormhole methods & details Method `_transfer_asset()` is an internal method to transfer required assets from Ethereum blockchain to Terra blockchain via Wormhole token bridge. Aside from common arguments, there is additional `_extra_data` argument to provide ability to submit arbitrary bytes. Leading 64 bytes are reserved to pass `nonce` and `arbiter_fee` to comply the Wormhole token bridge interface while maintaining backward compatibility for `AnchorVault` instance. Method `forward_beth()` transfers **bETH** to Terra chain by using `_transfer_asset()` with predefined values. Method `forward_ust()` transfers **UST** to Terra chain by using `_transfer_asset()` with predefined values. Method `adjust_amount()` allowing to adjust amount of assets to transfer and comply with bridge limitations for fractioning. ## Failure modes 1. Rewards collection is impossible if the current pool prices differ significantly from the ones reported by price oracles. In the event of oracle failure or Ethereum network congestion, rewards collection may be delayed for an indeterminate amount of time. 2. Conversion between stETH and bETH is impossible after stETH has rebased and between `AnchorVault.collect_rewards()` call. Normally, an offchain rewards collection bot performs such a call as soon as it detects a rebase. Thus: - If the bot becomes inoperable, the vault would be deemed unusable until `AnchorVault.collect_rewards()`` call is manually made or the bot is revived. - If stETH undergoes a rebase sooner than 24h after the previous one, the vault would be deemed unusable until 24h passes after the previous rebase and `AnchorVault.collect_rewards()` call is made. - In the event of Ethereum network congestion or price oracle failure, the vault might be deemed unusable until the situation resolves since rewards collection would fail (see 1).