Shield Base Overview
Reciprocally-covered asset shields (also called “vaults”) have extremely simple functionality. Their 2 main features are:
1. Accept underlying tokens, return ez-tokens (rcaTokens).
2. In the case of a hack, allow DAO to liquidate funds.
Some actions, such as farming and buying/selling (through a zapper–not necessarily from zapper.fi, but with the same functionality–contract) are not available yet, and “deposit and stake” and “unstake and redeem” are accomplished through adapters.
Let’s go over how these actions work:
The mintTo function requires ownership and approval of the underlying token before a call to the contract. Once called, it calculates the amount of rcaTokens that should be given in exchange for the underlying tokens using classic vault functionality where balance of the underlying token on the contract is compared to rcaToken total supply.
The first action mintTo takes is to call controller to update anything needed, launch events for our frontend to pick up, and verify signature given by the capacity oracle to confirm the action is allowed. It then calculates token amount, withdraw tokens from user, and mints rcaTokens to the user. The reason for the function to be “mintTo” rather than just “mint” is to allow simple/gas-efficient integration with zapper contracts.
This function initiates a withdrawal. Because we cannot have people simply withdrawing tokens directly after a hack so they are not slashed, we must introduce a delay into the redemption process that will begin at 2 days. redeemRequest is fairly standard with its flow in that it updates then checks for changes. It then saves data associated with the amount of tokens that the user wants to withdraw and the end time at which they can withdraw it.
It’s very important for redeemRequest to add the uAmount of the request to maintain accurate calculations through withdrawals. Since rcaTokens are burned upon redeemRequest but uTokens stay in the contract, we must subtract the pending withdrawals from uToken balance when doing calculations in future transactions.
This function completes a redeemRequest after the withdrawal delay has ended. It’s fairly straightforward in that it updates, checks whether the user has a pending redeem, subtracts from pending, then sends the users tokens.
The most notable part of this function is the zapper functionality. To avoid a zapper contract needing to hold tokens for redeem period or other weird workings, we allow the user to redeem assets to a zapper contract, which is then told assets have been transferred to it, and it can then exchange for the tokens the user wants and send back to the user. Because the final functionality of our zapper contracts has not been confirmed yet, we pass arbitrary data–which will likely end up being something like token to transfer to and dex path to take–in with the call for forward compatibility. It’s imperative this call or acceptance of arbitrary data can do no harm.
This function purchases either liquidated underlying tokens or underlying tokens for sale that were taken from fees in exchange for Ether being sent to the treasury contract. It may be able to be used by users such as in the diagram above, but this will likely mostly be used by arbitrage bots profiting from a liquidation.
It updates as normal, then confirms the underlying token’s price using the price merkle root on controller and submitted merkle proofs. This will give the price of one token in Ether, then it can be determined how much Ether is required to purchase the given amount of tokens. Underlying tokens should never be able to be sold if they have not been liquidated from a hack or taken through fees.
This function has almost the exact same functionality as purchaseU, except it converts the underlying amount into an RCA before sending to the purchaser. This would generally be the purchase function a user would use if we expose that functionality to the frontend. The benefits of a user versus arbitrage bot purchasing funds here is that someone looking for immediate profit requires a higher price discount than someone already looking to get invested into a token and wanting to pay less gas than buying it elsewhere and depositing it to the shield.
These value functions serve to convert underlying token value to RCA token value or vice versa. The most notable functionality in these is that the external versions need to input their own data so that updates function correctly. For example, if the frontend is attempting to receive information about the current conversion, it must also account for any updates to the controller that have been made since the last transaction on the shield was made which could change conversion (such as reserve percent changing which would make withdrawals give less underlying tokens).