Comment on page
Vault
Users can use this vault to deposit a combination of assets (ERC20, ERC721, ERC1155, etc). The vault will denominate all the pooled assets into one baseCurrency (one unit of account). An increase in value of one asset will offset a decrease in value of another asset. Users can take out a credit line against the single denominated value.
A vault is a smart contract that will contain multiple assets. Using getValue(), the vault returns the combined total value of all (whitelisted) assets the vault contains. Integrating this vault as means of collateral management for your own protocol that requires collateral is encouraged. Arcadia's vault functions will guarantee you a certain value of the vault. For whitelists or liquidation strategies specific to your protocol, contact: dev at arcadia.finance
_IMPLEMENTATION_SLOT
storage slot with the address of the current implementation. This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
bool public isTrustedProtocolSet;
uint16 public vaultVersion;
uint256 public life;
address public baseCurrency;
address public owner;
address public liquidator;
address public registry;
address public trustedProtocol;
address[] public erc20Stored;
address[] public erc721Stored;
address[] public erc1155Stored;
uint256[] public erc721TokenIds;
uint256[] public erc1155TokenIds;
mapping(address => bool) public allowed;
onlyFactory
throws if called by any account other than the factory address.modifier onlyFactory();
onlyAuthorized
throws if called by any account other than an authorised adress.modifier onlyAuthorized();
onlyOwner
throws if called by any account other than the owner.modifier onlyOwner();
constructor
constructor();
function initialize(address owner_, address registry_, uint16 vaultVersion_) external;
- Initiates the variables of the vault
- A proxy will be used to interact with the vault logic. Therefore everything is initialised through an init function. This function will only be called (once) in the same transaction as the proxy vault creation through the factory.
Parameters
Name | Type | Description |
---|---|---|
owner_ | address | The tx.origin: the sender of the 'createVault' on the factory |
registry_ | address | The 'beacon' contract to which should be looked at for external logic. |
vaultVersion_ | uint16 | The version of the vault logic. |
Stores a new address in the EIP1967 implementation slot & updates the vault version.
function upgradeVault(address newImplementation, uint16 newVersion) external onlyFactory;
Returns an
AddressSlot
with member value
located at slot
.function _getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r);
Transfers ownership of the contract to a new account (
newOwner
). Can only be called by the current owner via the factory. A transfer of ownership of this vault by a transfer of ownership of the accompanying ERC721 Vault NFT issued by the factory. Owner of Vault NFT = owner of vaultfunction transferOwnership(address newOwner) public onlyFactory;
Transfers ownership of the contract to a new account (
newOwner
). Internal function without access restriction.function _transferOwnership(address newOwner) internal virtual;
Sets the baseCurrency of a vault.
function setBaseCurrency(address baseCurrency_) public onlyAuthorized;
Parameters
Name | Type | Description |
---|---|---|
baseCurrency_ | address | the new baseCurrency for the vault. |
Internal function: sets baseCurrency.
First checks if there is no locked value. If there is no value locked then the baseCurrency gets changed to the param
function _setBaseCurrency(address baseCurrency_) private;
Parameters
Name | Type | Description |
---|---|---|
baseCurrency_ | address | the new baseCurrency for the vault. |
Initiates a margin account on the vault for one trusted application..
The open position is fetched at a contract of the application -> only allow trusted audited protocols!!!
Currently only one trusted protocol can be set.
Only open margin accounts for protocols you trust! The protocol has significant authorisation: use margin (-> trigger liquidation)
function openTrustedMarginAccount(address protocol) public onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
protocol | address | The contract address of the trusted application. |
Closes the margin account on the vault of the trusted application..
The open position is fetched at a contract of the application -> only allow trusted audited protocols!!!
Currently only one trusted protocol can be set.
function closeTrustedMarginAccount() public onlyOwner;
Can be called by authorised applications to increase a margin position.
function increaseMarginPosition(address baseCurrency_, uint256 amount)
public
view
onlyAuthorized
returns (bool success);
Parameters
Name | Type | Description |
---|---|---|
baseCurrency_ | address | The Base-currency in which the margin position is denominated |
amount | uint256 | The amount the position is increased. |
Returns
Name | Type | Description |
---|---|---|
success | bool | Boolean indicating if there is sufficient free margin to increase the margin position |
Returns the total value of the vault in a specific baseCurrency
Fetches all stored assets with their amounts on the proxy vault. Using a specified baseCurrency, fetches the value of all assets on the proxy vault in said baseCurrency.
function getVaultValue(address baseCurrency_) public view returns (uint256 vaultValue);
Parameters
Name | Type | Description |
---|---|---|
baseCurrency_ | address | The asset to return the value in. |
Returns
Name | Type | Description |
---|---|---|
vaultValue | uint256 | Total value stored on the vault, expressed in baseCurrency. |
Calculates the total collateral value of the vault.
Returns the value denominated in the baseCurrency in which the proxy vault is initialised.
The collateral value of the vault is equal to the spot value of the underlying assets, discounted by a haircut (the collateral factor). Since the value of collateralised assets can fluctuate, the haircut guarantees that the vault remains over-collateralised with a high confidence level (99,9%+). The size of the haircut depends on the underlying risk of the assets in the vault, the bigger the volatility or the smaller the on-chain liquidity, the bigger the haircut will be.
function getCollateralValue() public view returns (uint256 collateralValue);
Returns
Name | Type | Description |
---|---|---|
collateralValue | uint256 | The collateral value, returned in the decimals of the base currency. |
Calculates the total liquidation value of the vault.
Returns the value denominated in the baseCurrency in which the proxy vault is initialised.
The liquidation value of the vault is equal to the spot value of the underlying assets, discounted by a haircut (the liquidation factor). The liquidation value takes into account that not the full value of the assets can go towards repaying the debt, but only a fraction of it, the remaining value is lost due to: slippage while liquidating the assets, fees for the auction initiator, gas fees and a penalty to the protocol.
function getLiquidationValue() public view returns (uint256 liquidationValue);
Returns
Name | Type | Description |
---|---|---|
liquidationValue | uint256 | The liquidation value, returned in the decimals of the base currency. |
Returns the used margin of the proxy vault.
The used margin is denominated in the baseCurrency of the proxy vault.
Currently only one trusted application (Arcadia Lending) can open a margin account. The open position is fetched at a contract of the application -> only allow trusted audited protocols!!!
function getUsedMargin() public view returns (uint256 usedMargin);
Returns
Name | Type | Description |
---|---|---|
usedMargin | uint256 | The used amount of margin a user has taken |
Calculates the remaining margin the owner of the proxy vault can use.
The free margin is denominated in the baseCurrency of the proxy vault, with an equal number of decimals as the base currency.
function getFreeMargin() public view returns (uint256 freeMargin);
Returns
Name | Type | Description |
---|---|---|
freeMargin | uint256 | The remaining amount of margin a user can take. |
Function called to start a vault liquidation.
Requires an unhealthy vault (value / debt < liqThres). Starts the vault auction on the liquidator contract. Increases the life of the vault to indicate a liquidation has happened. Transfers ownership of the proxy vault to the liquidator!
function liquidateVault(address liquidationKeeper) public onlyFactory returns (bool success, address liquidator_);
Parameters
Name | Type | Description |
---|---|---|
liquidationKeeper | address | Address of the keeper who initiated the liquidation process. |
Returns
Name | Type | Description |
---|---|---|
success | bool | Boolean returning if the liquidation process is successfully started. |
liquidator_ | address | |
Deposits assets into the proxy vault by the proxy vault owner.
All arrays should be of same length, each index in each array corresponding to the same asset that will get deposited. If multiple asset IDs of the same contract address are deposited, the assetAddress must be repeated in assetAddresses. The ERC20 gets deposited by transferFrom. ERC721 & ERC1155 using safeTransferFrom. Can only be called by the proxy vault owner to avoid attacks where malicous actors can deposit 1 wei assets, increasing gas costs upon credit issuance and withrawals. Example inputs: [wETH, DAI, Bayc, Interleave], [0, 0, 15, 2], [1018, 1018, 1, 100], [0, 0, 1, 2] [Interleave, Interleave, Bayc, Bayc, wETH], [3, 5, 16, 17, 0], [123, 456, 1, 1, 10**18], [2, 2, 1, 1, 0]
function deposit(
address[] calldata assetAddresses,
uint256[] calldata assetIds,
uint256[] calldata assetAmounts,
uint256[] calldata assetTypes
) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
assetAddresses | address[] | The contract addresses of the asset. For each asset to be deposited one address, even if multiple assets of the same contract address are deposited. |
assetIds | uint256[] | The asset IDs that will be deposited for ERC721 & ERC1155. When depositing an ERC20, this will be disregarded, HOWEVER a value (eg. 0) must be filled! |
assetAmounts | uint256[] | The amounts of the assets to be deposited. |
assetTypes | uint256[] | The types of the assets to be deposited. 0 = ERC20 1 = ERC721 2 = ERC1155 Any other number = failed tx |
Deposits assets into the proxy vault.
Each index in each array corresponding to the same asset that will get deposited. If multiple asset IDs of the same contract address are deposited, the assetAddress must be repeated in assetAddresses. The ERC20 gets deposited by transferFrom. ERC721 & ERC1155 using safeTransferFrom. Example inputs: [wETH, DAI, Bayc, Interleave], [0, 0, 15, 2], [1018, 1018, 1, 100], [0, 0, 1, 2] [Interleave, Interleave, Bayc, Bayc, wETH], [3, 5, 16, 17, 0], [123, 456, 1, 1, 10**18], [2, 2, 1, 1, 0]
function _deposit(
address[] memory assetAddresses,
uint256[] memory assetIds,
uint256[] memory assetAmounts,
uint256[] memory assetTypes,
address from
) internal;
Parameters
Name | Type | Description |
---|---|---|
assetAddresses | address[] | The contract addresses of the asset. For each asset to be deposited one address, even if multiple assets of the same contract address are deposited. |
assetIds | uint256[] | The asset IDs that will be deposited for ERC721 & ERC1155. When depositing an ERC20, this will be disregarded, HOWEVER a value (eg. 0) must be filled! |
assetAmounts | uint256[] | The amounts of the assets to be deposited. |
assetTypes | uint256[] | The types of the assets to be deposited. 0 = ERC20 1 = ERC721 2 = ERC1155 Any other number = failed tx |
from | address | The address to deposit from. |
Processes withdrawals of assets by and to the owner of the proxy vault.
All arrays should be of same length, each index in each array corresponding to the same asset that will get withdrawn. If multiple asset IDs of the same contract address are to be withdrawn, the assetAddress must be repeated in assetAddresses. The ERC20 get withdrawn by transfers. ERC721 & ERC1155 using safeTransferFrom. Can only be called by the proxy vault owner. Will fail if balance on proxy vault is not sufficient for one of the withdrawals. Will fail if "the value after withdrawal / open debt (including unrealised debt) > collateral threshold". If no debt is taken yet on this proxy vault, users are free to withraw any asset at any time. Example inputs: [wETH, DAI, Bayc, Interleave], [0, 0, 15, 2], [1018, 1018, 1, 100], [0, 0, 1, 2] [Interleave, Interleave, Bayc, Bayc, wETH], [3, 5, 16, 17, 0], [123, 456, 1, 1, 10**18], [2, 2, 1, 1, 0]
function withdraw(
address[] calldata assetAddresses,
uint256[] calldata assetIds,
uint256[] calldata assetAmounts,
uint256[] calldata assetTypes
) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
assetAddresses | address[] | The contract addresses of the asset. For each asset to be withdrawn one address, even if multiple assets of the same contract address are withdrawn. |
assetIds | uint256[] | The asset IDs that will be withdrawn for ERC721 & ERC1155. When withdrawing an ERC20, this will be disregarded, HOWEVER a value (eg. 0) must be filled! |
assetAmounts | uint256[] | The amounts of the assets to be withdrawn. |
assetTypes | uint256[] | The types of the assets to be withdrawn. 0 = ERC20 1 = ERC721 2 = ERC1155 Any other number = failed tx |
Processes withdrawals of assets
Each index in each array corresponding to the same asset that will get withdrawn. If multiple asset IDs of the same contract address are to be withdrawn, the assetAddress must be repeated in assetAddresses. The ERC20 get withdrawn by transfers. ERC721 & ERC1155 using safeTransferFrom. Will fail if balance on proxy vault is not sufficient for one of the withdrawals. Example inputs: [wETH, DAI, Bayc, Interleave], [0, 0, 15, 2], [1018, 1018, 1, 100], [0, 0, 1, 2] [Interleave, Interleave, Bayc, Bayc, wETH], [3, 5, 16, 17, 0], [123, 456, 1, 1, 10**18], [2, 2, 1, 1, 0]
function _withdraw(
address[] memory assetAddresses,
uint256[] memory assetIds,
uint256[] memory assetAmounts,
uint256[] memory assetTypes,
address to
) internal;
Parameters
Name | Type | Description |
---|---|---|
assetAddresses | address[] | The contract addresses of the asset. For each asset to be withdrawn one address, even if multiple assets of the same contract address are withdrawn. |
assetIds | uint256[] | The asset IDs that will be withdrawn for ERC721 & ERC1155. When withdrawing an ERC20, this will be disregarded, HOWEVER a value (eg. 0) must be filled! |
assetAmounts | uint256[] | The amounts of the assets to be withdrawn. |
assetTypes | uint256[] | The types of the assets to be withdrawn. 0 = ERC20 1 = ERC721 2 = ERC1155 Any other number = failed tx |
to | address | The address to withdraw to. |
Internal function used to deposit ERC20 tokens.
Used for all tokens types = 0. Note the transferFrom, not the safeTransferFrom to allow legacy ERC20s. After successful transfer, the function checks whether the same asset has been deposited. This check is done using a loop: writing it in a mapping vs extra loops is in favor of extra loops in this case. If the address has not yet been seen, the ERC20 token address is stored.
function _depositERC20(address from, address ERC20Address, uint256 amount) private;
Parameters
Name | Type | Description |
---|---|---|
from | address | Address the tokens should be taken from. This address must have pre-approved the proxy vault. |
ERC20Address | address | The asset address that should be transferred. |
amount | uint256 | The amount of ERC20 tokens to be transferred. |
Internal function used to deposit ERC721 tokens.
Used for all tokens types = 1. Note the transferFrom. No amounts are given since ERC721 are one-off's. After successful transfer, the function pushes the ERC721 address to the stored token and stored ID array. This may cause duplicates in the ERC721 stored addresses array, but this is intended.
function _depositERC721(address from, address ERC721Address, uint256 id) private;
Parameters
Name | Type | Description |
---|---|---|
from | address | Address the tokens should be taken from. This address must have pre-approved the proxy vault. |
ERC721Address | address | The asset address that should be transferred. |
id | uint256 | The ID of the token to be transferred. |
Internal function used to deposit ERC1155 tokens.
Used for all tokens types = 2. Note the safeTransferFrom. After successful transfer, the function checks whether the combination of address & ID has already been stored. If not, the function pushes the new address and ID to the stored arrays. This may cause duplicates in the ERC1155 stored addresses array, but this is intended.
function _depositERC1155(address from, address ERC1155Address, uint256 id, uint256 amount) private;
Parameters
Name | Type | Description |
---|---|---|
from | address | The Address the tokens should be taken from. This address must have pre-approved the proxy vault. |
ERC1155Address | address | The asset address that should be transferred. |
id | uint256 | The ID of the token to be transferred. |
amount | uint256 | The amount of ERC1155 tokens to be transferred. |
Internal function used to withdraw ERC20 tokens.
Used for all tokens types = 0. Note the transferFrom, not the safeTransferFrom to allow legacy ERC20s. After successful transfer, the function checks whether the proxy vault has any leftover balance of said asset. If not, it will pop() the ERC20 asset address from the stored addresses array. Note: this shifts the order of erc20Stored! This check is done using a loop: writing it in a mapping vs extra loops is in favor of extra loops in this case.
function _withdrawERC20(address to, address ERC20Address, uint256 amount) private;
Parameters
Name | Type | Description |
---|---|---|
to | address | Address the tokens should be sent to. This will in any case be the proxy vault owner either being the original user or the liquidator!. |
ERC20Address | address | The asset address that should be transferred. |
amount | uint256 | The amount of ERC20 tokens to be transferred. |
Internal function used to withdraw ERC721 tokens.
Used for all tokens types = 1. Note the safeTransferFrom. No amounts are given since ERC721 are one-off's. After successful transfer, the function checks whether any other ERC721 is deposited in the proxy vault. If not, it pops the stored addresses and stored IDs (pop() of two arrs is 180 gas cheaper than deleting). If there are, it loops through the stored arrays and searches the ID that's withdrawn, then replaces it with the last index, followed by a pop(). Sensitive to ReEntrance attacks! SafeTransferFrom therefore done at the end of the function.
function _withdrawERC721(address to, address ERC721Address, uint256 id) private;
Parameters
Name | Type | Description |
---|---|---|
to | address | Address the tokens should be taken from. This address must have pre-approved the proxy vault. |
ERC721Address | address | The asset address that should be transferred. |
id | uint256 | The ID of the token to be transferred. |
Internal function used to withdraw ERC1155 tokens.
Used for all tokens types = 2. Note the safeTransferFrom. After successful transfer, the function checks whether there is any balance left for that ERC1155. If there is, it simply transfers the tokens. If not, it checks whether it can pop() (used for gas savings vs delete) the stored arrays. If there are still other ERC1155's on the contract, it looks for the ID and token address to be withdrawn and then replaces it with the last index, followed by a pop(). Sensitive to ReEntrance attacks! SafeTransferFrom therefore done at the end of the function.
function _withdrawERC1155(address to, address ERC1155Address, uint256 id, uint256 amount) private;
Parameters
Name | Type | Description |
---|---|---|
to | address | Address the tokens should be taken from. This address must have pre-approved the proxy vault. |
ERC1155Address | address | The asset address that should be transferred. |
id | uint256 | The ID of the token to be transferred. |
amount | uint256 | The amount of ERC1155 tokens to be transferred. |
Generates three arrays about the stored assets in the proxy vault in the format needed for vault valuation functions.
No balances are stored on the contract. Both for gas savings upon deposit and to allow for rebasing/... tokens. Loops through the stored asset addresses and fills the arrays. The vault valuation function fetches the asset type through the asset registries. There is no importance of the order in the arrays, but all indexes of the arrays correspond to the same asset.
function generateAssetData()
public
view
returns (address[] memory assetAddresses, uint256[] memory assetIds, uint256[] memory assetAmounts);
Returns
Name | Type | Description |
---|---|---|
assetAddresses | address[] | An array of asset addresses. |
assetIds | uint256[] | An array of asset IDs. Will be '0' for ERC20's |
assetAmounts | uint256[] | An array of the amounts/balances of the asset on the proxy vault. wil be '1' for ERC721's |
Calls external action handlers to execute and interact with external logic.
Similar to flash loans, this function optimistically calls external logic and checks for the vault state at the very end.
function vaultManagementAction(address actionHandler, bytes calldata actionData) public onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
actionHandler | address | the address of the action handler to call |
actionData | bytes | a bytes object containing two actionAssetData structs, an address array and a bytes array |
function onERC721Received(address, address, uint256, bytes calldata) public pure returns (bytes4);
function onERC1155Received(address, address, uint256, uint256, bytes calldata) public pure returns (bytes4);
fallback() external;
event Upgraded(address indexed implementation);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
struct AddressSlot {
address value;
}
Last modified 8mo ago