Blueberry Bank Contract
about
BlueberryBank.sol
is a smart contract that implements a bank in which users can borrow and lend different tokens, as well as keep track of their positions. The contract includes the following functionalities:- Allowing borrowing, lending, and repaying different tokens
- Tracking the state of each position and storing position data
- Implement a borrowing limit for each user's position
- Use an oracle to determine token prices
- Implement a fee system for borrowing, lending, and deployment inside of the protocol
function initialize(ICoreOracle oracle_, IProtocolConfig config_) external initializer
This function initializes the bank smart contract by setting the Oracle smart contract, the Protocol config address, and the Fee manager address. It also initializes some internal state variables. The function can only be called by the contract owner.
Parameters:
Name | Type | Description |
---|---|---|
oracle | address | The oracle smart contract address |
config_ | address | The Protocol config smart contract adress |
function EXECUTOR() external view override returns (address)
This function returns the current executor of the smart contract, which is the owner of the current position. If there is no position under execution, it reverts with an error.
Parameters:
address
- the address of the current position owner
function setAllowContractCalls(bool ok) external onlyOwner
This function sets the
allowContractCalls
flag to allow or disallow contract calls. If allowContractCalls
is set to true
, then only externally-owned accounts (EOAs) can call the contract. This function can only be called by the contract owner.Parameters
ok
- The status to setallowContractCalls
to. Iffalse
, only EOA can call the contract.
whitelistContracts(address[] calldata contracts, bool[] calldata statuses) external onlyOwner
This function sets the status of the given contracts in the whitelist. The function can only be called by the contract owner.
Parameters:
Name | Type | Description |
---|---|---|
contracts | Array | An array of contract addresses to change the status of. |
statuses | Array | An array of boolean values to change the status of the corresponding contract address in contracts . |
whitelistSpells(address[] calldata spells, bool[] calldata statuses) external onlyOwner
This function sets the status of the given spells in the whitelist. The function can only be called by the contract owner.
Parameters:
Name | Type | Description |
---|---|---|
spells | Array | An array of contract addresses to change the status of. |
statuses | Array | An array of boolean values to change the status of the corresponding contract address in spells . |
whitelistTokens(address[] calldata tokens, bool[] calldata statuses) external onlyOwner
This function sets the status of the given tokens in the whitelist. It also checks whether the given tokens are supported by the Oracle smart contract. The function can only be called by the contract owner.
Parameters:
Name | Type | Description |
---|---|---|
tokens | Array | An array of contract addresses to change the status of. |
statuses | Array | An array of boolean values to change the status of the corresponding contract address in tokens . |
whitelistERC1155(address[] memory tokens, bool ok) external onlyOwner
This function sets the status of the given ERC1155(wrapped tokens) in the whitelist. The function can only be called by the contract owner.
Parameters:
Name | Type | Description |
---|---|---|
tokens | Array | An array of contract addresses to change the status of. |
ok | bool | The status of the corresponding whitelisted wrapped tokens in tokens . |
addBank(address token, address softVault, address hardVault, uint256 liqThreshold) external onlyOwner onlyWhitelistedToken(token)
This function adds a new bank to the ecosystem. It creates a new
Bank
struct and sets its properties, such as the underlying token for the bank and the address of the soft and hard vaults. It also checks whether the bToken
for the soft vault has already been added to any other bank. If the bToken
has already been added to a bank, it reverts with an error. The function can only be called by the contract owner.Parameters:
Name | Type | Description |
---|---|---|
token | Address | The address of the underlying token for the bank |
softvault | Address | The address of the soft vault for the bank |
hardvault | Address | The address of the hard vault for the bank |
liqThreshold | uint256 | The numerical value for liquidation threshold for the bank |
setBankStatus(uint256 _bankStatus) external onlyOwner
This function is used to set the bank status to a new value. Only callable by the owner
Parameters:
Name | Type | Description |
---|---|---|
_bankStatus | uint256 | The new bank status value to set |
Modifiers
onlyOwner
: Only the contract owner can call this function
Return
- None
function isBorrowAllowed() public view returns (bool)
This function is used to check whether borrowing is allowed for the bank or not
Parameters:
- None
Modifiers:
- None
Return:
- bool: Returns true if borrowing is allowed, false otherwise.
function isRepayAllowed() public view returns (bool)
This function is used to check whether repaying is allowed for the bank or not
Parameters:
- None
Modifiers:
- None
Return:
- bool: Returns true if repaying is allowed, false otherwise.
function isLendAllowed() public view returns (bool)
This function is used to check whether lending is allowed for the bank or not
Parameters:
- None
Modifiers:
- None
Return:
- bool: Returns true if lending is allowed, false otherwise.
function isWithdrawLendAllowed() public view returns (bool)
This function is used to check whether withdrawing lending is allowed for the bank or not
Parameters:
- None
Modifiers:
- None
Return:
- bool: Returns true if withdrawing lend is allowed, false otherwise.
function accrue(address token) public override
This function is used to trigger interest accrual for the given bank.
Parameters:
Name | Type | Description |
---|---|---|
token | address | The underlying token for which interest accrual needs to be triggered |
function accrueAll(address[] memory token) external
This function is used to trigger interest accrual for a list of banks.
Parameters:
Name | Type | Description |
---|---|---|
tokens | array | The list of underlying tokens for which interest accrual needs to be triggered. |
Modifiers:
- None
Return:
- None
function _borrowBalanceStored(address token) internal view returns (uint256)
This internal function is used to get the stored borrow balance for the given token
Parameters:
Name | Type | Description |
---|---|---|
token | address | The underlying token for which the stored borrow balance needs to be retrieved |
Modifiers:
- None
Return:
- uint256: The stored borrow balance for the given token.
function currentPositionDebt(uint256 positionId) public view returns (uint256 debt)
This function returns the debt of a given position considering the debt interest stored.
Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The ID of the position to query for the debt balance |
Return:
debt
uint256: The current debt balance of the specified position.
function getPositionDebt(uint256 positionId) public view returns (uint256 debt)
This function returns the debt of the specified position considering the debt interest stored. The function should be called after calling the
accrue
function to get the current debt.Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The ID of the position to query for the debt balance |
Modifiers:
- None
Returns:
debt
(uint256): The debt balance of the specified position.
function getBankInfo(address token) external view override returns (bool isListed, address bToken, uint256 totalShare)
This function returns the bank information for the specified token.
Parameters:
Name | Type | Description |
---|---|---|
token | address | The token address to find the specific bank information |
Modifiers:
- None
Returns:
isListed
(bool): True if the specified token is listed in the banks, otherwise falsebToken
(address): The address of the associated bToken contract for the specified tokentotalShare
(uin256): The total share of the specified token in the bank
function getPositionInfo(uint256 positionId) external view override returns (Position memory)
This function returns the information of the specified position.
Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for position information |
Modifiers:
- None
Returns:
Position
(struct): The information about the specified position
function getCurrenPositionInfo() external view override returns (Position memory)
This function returns the information about the current position
Returns:
Position
(struct): The information about the current position
Modifiers:
if (POSITION_ID == _NO_ID)
: MODIFIES THE FUNCTION TO CHECK IFPOSITION_ID
is not equal to_NO_ID
before executing the function.
function getPositionValue(uint256 positionId) public view override returns (uint256 positionValue)
This function returns the USD value of the total collateral of the specified position considering yields generated from the collaterals.
Parameters
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for position value information |
Return:
positionValue
(uin256): The USD value of the total collateral of the specified position.
function getDebtValue(uint256 positionId) public view override returns (uint256 debtValue)
This function should be called to get the current USD value of a position's debt. This function should be called after calling
accrue()
to get the current debt balance.Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for position debt value information |
Return:
debtValue
(uint256): The USD value of the position's debt
function getIsolatedCollateralValue(uint256 positionId) public view override returns (uint256 icollValue)
This function returns the USD value of the isolated collateral of a given position. It takes into consideration the stored lending interest in the position. This function should be called after calling
accrue()
to get the current debt.Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for position's isolated collateral value information |
Return:
icollValue
(uint256): The USD value of the position's collateral.
function getPositionRisk(uint256 positionId) public view returns (uint256 risk)
This function calculates the risk ratio of a given position, which represents the degree of risk associated with the position. The higher the risk ratio, the higher the risk. By taking into consideration the following factors:
pv
(uint256): The position valueov
(uint256): The debt valuecv
(uint256): The isolated collateral value
If the position is closed or overcollateralized, the risk is set to 0. If there is no isolated collateral or there is an error with the isolated underlying token, the risk is set to the maximum value of
Constants.DENOMINATOR
. Otherwise, the risk is calculated as (ov - pv) * Constants.DENOMINATOR / cv
Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for the position's risk |
Returns:
risk
(uint256): The calculated risk ratio
function isLiquidatable(uint256 positionId) public view returns (bool)
This function checks whether a given position can be liquidated by first calculating its risk ratio using the
getPositionRisk
function. It then compares the risk ratio to the liquidation threshold defined in the oracle for the underlying token of the position. If the risk ratio is higher than or equal to the liquidation threshold, the position is considered liquidatable and the function returns true
. Otherwise, the function returns false
.Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for the position's liquidation status. |
Returns:
- bool: A boolean value indicating whether the position is liquidatable or not.
function liquidate(uint256 positionId, address debtToken, uint256 amountCall) external override lock poke(debtToken)
This function liquidates a position, paying off its debt for the original owner and taking the collateral of the position.
Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The ID of the position to liquidate |
debtToken | address | The debt token to repay |
amountCall | uint256 | The amount ot repay when doing transferFrom call |
Details:
- 1.Check if the repay operation is allowed
- 2.Check if the
amountCall
parameter is non-zero - 3.Check if the position is liquidatable using the
isLiquidatable
function - 4.Retrieve the position and bank information
- 5.Calculate the amount paid and the share of the debt to repay using the
_repay
function - 6.Calculate the liquidation size and the share of the underlying vault using the
oldShare
value, thecollateralSize
, and theunderlyingValueShare
fields of this position - 7.Update the
collateralSize
andunderlyingVaultShare
fields of the position - 8.Transfer the position (wrapped LP tokens) to the liquidator using the
safeTransferFrom
function of the ERC1155 token - 9.Transfer the underlying collateral (vault share tokens) to the liquidator using the
safeTransfer
function of the ERC20 token for a soft vault or thesafeTransferFrom
function of the ERC1155 token for a hard vault. - 10.Emit the
positionId
of the position liquidated,msg.sender
the address of the liquidator,debtToken
The token address that got repaid,amountPaid
How much did the liquidator pay to the bank,share
the share of the vault tokens,liqSize
how large the liquidation was, anduVaultShare
the underlying vault token share.
function execute(uint256 positionId, address spell, bytes memory data) external lock onlyEOAEx returns (uint256)
This function allows the called to execute a spell with supplied data. The spell must be whitelisted before execution. If the positionID is zero, a new position will be created. If it is not zero, the function will check if the position exists, and is owned by the caller, and if not, it will revert. The function will set the global variables
POSITION_ID
and SPELL
to the supplied positionID
and spell
, respectively. It will then execute the spell with the supplied data and handle any errors that may occur. Finally, it will check if the position is liquidatable and emit an event.Modifiers
onlyEOAEx
: The function can only be called by an externally-owned account that is executing a spell
Parameters
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to execute the action, or zero for new position |
spell | address | The target spell to invoke the execution |
data | bytes memory | Extra data to pass to the target for the execution |
Return:
- (uint256): The position ID that was executed and created.
function lend(address token, uint256 amount) external override inExec poke(token) onlyWhitelistedToken(token)
This function allows the called to lend tokens to the bank as isolated collateral. The function must be called while under execution. The token must be whitelisted before lending.
Modifiers:
inExec
: The function can only be called while under executionpoke(token)
: The function will poke the token before execution to ensure its balance and allowance is up-to-dateonlyWhitelistedToken(token)
: The function can only be called with a whitelisted token
Parameters
Name | Type | Description |
---|---|---|
token | address | The token to be deposited in the bank as isolated collateral |
amount | uint256 | The amount of tokens to be lent |
function withdrawLend(address token, uint256 shareAmount) external override inExec poke(token)
This function withdraws isolated collateral tokens that were lent to the bank. It first checks if the withdrawLend function is allowed to execute. It then retrieves the Position storage and Bank memory objects from their respective mappings. If the token address does not match the underlying token address in the Position storage, the function throws an
INVALID_UTOKEN
error.If
shareAmount
is equal to type(uint256).max
, the function sets shareAmount
to the underlyingVaultShare stored in the Position storage.The function then calculates the amount to withdraw using either the softVault or hardVault. If
_isSoftVault(token)
returns true, the function calls the approve
and withdraw
functions of the ISoftVault
interface. If it returns false, the function calls the withdraw
function of the IHardVault
interface.After the tokens are withdrawn, the underlyingVaultShare stored in the Position storage is updated, the tokens are approved for transfer to the
feeManager
contract, and the withdrawal fee is taken by calling the doCutWithdrawFee
function of the feeManager
contract. Finally, the tokens are transferred to the caller.Modifiers:
inExec
: This modifier checks if the function is being called from the spell contract while under executionpoke
: This modifier updates the state of the contract by calling the poke method with the given token address
Parameters:
Name | Type | Description |
---|---|---|
token | address | The token address of the isolated collateral token to be withdrawn |
shareAmount | uint256 | The number of share tokens to be withdrawn |
function borrow(address token, uint256 amount) external override inExec poke(token) onlyWhitelistedToken(token) returns (uint256 borrowedAmount)
This function allows the caller to borrow tokens from the bank. It first checks if the borrow function is allowed to execute. It then retrieves the Bank storage and Position storage objects from their respective mappings. If the Position storage has no debt token set, it sets the token. This function can only be called from the spell contract while under execution
Modifiers:
inExec
: This modifier checks if the function is being called from the spell contract while under executionpoke
: This modifier updates the state of the contract by calling the poke method with the given token addressonlyWhitelistedToken
: This modifier checks if the given token address is whitelisted
Parameters:
Name | Type | Description |
---|---|---|
token | address | The token to borrow from the bank |
amount | uint256 | The number of tokens to borrow |
Return:
borrowedAmount
(uint256): The number of tokens borrowed.
function repay(address token, uint256 amountCall) external override inExec poke(token) onlyWhitelistedToken(token)
This function allows a user to repay a specific token to the bank. It should only be called during execution. Before executing the function, it checks whether the repay is allowed. If the repay is not allowed, it will revert with an error message.
The function then calls the internal function
_repay()
with the position ID, token, and amountCall as parameters. _repay()
calculates the amount to be repaid and the corresponding debt share reduced. The function then emits a Repay
event with the relevant parameters.Modifiers:
inExec
: This modifier checks if the function is being called from the spell contract while under executionpoke
: This modifier updates the state of the contract by calling the poke method with the given token addressonlyWhitelistedToken
: This modifier checks if the given token address is whitelisted
Parameters:
Name | Type | Description |
---|---|---|
token | address | The token to be repaid to the bank |
amountCall | uint256 | The number of tokens to be repaid via transferFrom |
function _repay(uint256 positionId, address token, uint256 amountCall) internal returns (uint256, uint256)
This function is used to perform a repayment action on a given position ID, using the specified token. It returns the amount actually taken and the debt share reduced. The debt token of the position must match the specified token, otherwise, the function will revert. The amount to repay must not exceed the old debt, otherwise, the function will revert. The function must be called while under execution.
Parameters:
Name | Type | Description |
---|---|---|
positionId | uint256 | The position ID to query for repayment of debt |
token | address | The token to be repaid to the bank |
amountCall | uint256 | The number of tokens to be repaid via transferFrom |
Returns:
Name | Type | Description |
---|---|---|
paid | uint | The amount actually taken from the user |
lessShare | uint | The debt share reduced from the position after repayment. |
function putCollateral(address collToken, uint256 collId, uint256 amountCall) external override inExec
This function allows users to put more collateral into their position. The function first checks if the collateral token being used is the same as the one already specified in the position. If not, it checks if the oracle supports the wrapped token of the LP address. If the collateral size of the position is greater than zero, it reverts. If both checks pass, the collateral token and ID are updated in the position.
The function then calls the internal _doERC1155TransferIn() function to transfer the ERC1155 tokens from the user's wallet to the contract. The amount of tokens transferred is added to the position's collateral size. An event PutCollateral() is then emitted to signify that collateral has been added to the position.
Modifiers:
inExec
Can only be called during execution
Parameters:
Name | Type | Description |
---|---|---|
collToken | address | The address of the token that will be used as collateral |
collId | uint256 | The token ID that corresponds to the specific ERC1155 toke being used as collateral. |
amountCall | uint256 | The amount of ERC1155 tokens to be put as collateral by calling transferFrom |
function takeCollateral(uint256 amount) external override inExec returns (uint256)
This function allows users to take some of their collateral back. It must only be called during execution. The function first retrieves the position from the positions mapping. If the amount to be taken back is set to the maximum uint256 value, it sets the amount to the full collateral size of the position. Then, it reduces the collateral size of the position by the amount being taken back.
The function then calls the safeTransferFrom() function of the IERC1155Upgradeable interface to transfer the ERC1155 tokens from the contract back to the user's wallet. An event TakeCollateral() is emitted to signify that collateral has been taken back from the position. The amount of tokens taken back is returned.
Modifiers:
inExec
Can only be called during execution
Parameters:
amount
(uint256): The amount of ERC1155 tokens to be taken back by transfer
function _doBorrow(address token, uint256 amountCall) internal returns (uint256 borrowAmount)
This function is used to perform a borrow from a bank and returns the amount borrowed.
Parameters:
Name | Type |
---|