diff --git a/contracts/core/Controller.sol b/contracts/core/Controller.sol
index 1a6f7f030..f4889a0fa 100644
--- a/contracts/core/Controller.sol
+++ b/contracts/core/Controller.sol
@@ -21,43 +21,43 @@ import {CalleeInterface} from "../interfaces/CalleeInterface.sol";
/**
* Controller Error Codes
- * CO1: sender is not fullPauser
- * CO2: sender is not partialPauser
- * CO3: callee is not a whitelisted address
- * CO4: system is partially paused
- * CO5: system is fully paused
- * CO6: msg.sender is not authorized to run action
- * CO7: invalid addressbook address
- * CO8: invalid owner address
- * CO9: invalid input
- * CO10: fullPauser cannot be set to address zero
- * CO11: partialPauser cannot be set to address zero
- * CO12: can not run actions for different owners
- * CO13: can not run actions on different vaults
- * CO14: invalid final vault state
- * CO15: can not run actions on inexistent vault
- * CO16: cannot deposit long otoken from this address
- * CO17: otoken is not whitelisted to be used as collateral
- * CO18: otoken used as collateral is already expired
- * CO19: can not withdraw an expired otoken
- * CO20: cannot deposit collateral from this address
- * CO21: asset is not whitelisted to be used as collateral
- * CO22: can not withdraw collateral from a vault with an expired short otoken
- * CO23: otoken is not whitelisted to be minted
- * CO24: can not mint expired otoken
- * CO25: cannot burn from this address
- * CO26: can not burn expired otoken
- * CO27: otoken is not whitelisted to be redeemed
- * CO28: can not redeem un-expired otoken
- * CO29: asset prices not finalized yet
- * CO30: can't settle vault with no otoken
- * CO31: can not settle vault with un-expired otoken
- * CO32: can not settle undercollateralized vault
- * CO33: can not liquidate vault
- * CO34: can not leave less than collateral dust
- * CO35: invalid vault id
- * CO36: cap amount should be greater than zero
- * CO37: collateral exceed naked margin cap
+ * C1: sender is not full pauser
+ * C2: sender is not partial pauser
+ * C3: callee is not a whitelisted address
+ * C4: system is partially paused
+ * C5: system is fully paused
+ * C6: msg.sender is not authorized to run action
+ * C7: invalid addressbook address
+ * C8: invalid owner address
+ * C9: invalid input
+ * C10: fullPauser cannot be set to address zero
+ * C11: partialPauser cannot be set to address zero
+ * C12: can not run actions for different owners
+ * C13: can not run actions on different vaults
+ * C14: invalid final vault state
+ * C15: can not run actions on inexistent vault
+ * C16: cannot deposit long otoken from this address
+ * C17: otoken is not whitelisted to be used as collateral
+ * C18: otoken used as collateral is already expired
+ * C19: can not withdraw an expired otoken
+ * C20: cannot deposit collateral from this address
+ * C21: asset is not whitelisted to be used as collateral
+ * C22: can not withdraw collateral from a vault with an expired short otoken
+ * C23: otoken is not whitelisted to be minted
+ * C24: can not mint expired otoken
+ * C25: cannot burn from this address
+ * C26: can not burn expired otoken
+ * C27: otoken is not whitelisted to be redeemed
+ * C28: can not redeem un-expired otoken
+ * C29: asset prices not finalized yet
+ * C30: can't settle vault with no otoken
+ * C31: can not settle vault with un-expired otoken
+ * C32: can not settle undercollateralized vault
+ * C33: can not liquidate vault
+ * C34: can not leave less than collateral dust
+ * C35: invalid vault id
+ * C36: cap amount should be greater than zero
+ * C37: collateral exceed naked margin cap
*/
/**
@@ -234,7 +234,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @notice modifier to check if sender is the fullPauser address
*/
modifier onlyFullPauser {
- require(msg.sender == fullPauser, "CO1");
+ require(msg.sender == fullPauser, "C1");
_;
}
@@ -243,7 +243,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @notice modifier to check if the sender is the partialPauser address
*/
modifier onlyPartialPauser {
- require(msg.sender == partialPauser, "CO2");
+ require(msg.sender == partialPauser, "C2");
_;
}
@@ -265,7 +265,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
*/
modifier onlyWhitelistedCallee(address _callee) {
if (callRestricted) {
- require(_isCalleeWhitelisted(_callee), "CO3");
+ require(_isCalleeWhitelisted(_callee), "C3");
}
_;
@@ -275,14 +275,14 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @dev check if the system is not in a partiallyPaused state
*/
function _isNotPartiallyPaused() internal view {
- require(!systemPartiallyPaused, "CO4");
+ require(!systemPartiallyPaused, "C4");
}
/**
* @dev check if the system is not in an fullyPaused state
*/
function _isNotFullyPaused() internal view {
- require(!systemFullyPaused, "CO5");
+ require(!systemFullyPaused, "C5");
}
/**
@@ -291,7 +291,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _accountOwner owner of a vault
*/
function _isAuthorized(address _sender, address _accountOwner) internal view {
- require((_sender == _accountOwner) || (operators[_accountOwner][_sender]), "CO6");
+ require((_sender == _accountOwner) || (operators[_accountOwner][_sender]), "C6");
}
/**
@@ -300,8 +300,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _owner account owner address
*/
function initialize(address _addressBook, address _owner) external initializer {
- require(_addressBook != address(0), "CO7");
- require(_owner != address(0), "CO8");
+ require(_addressBook != address(0), "C7");
+ require(_owner != address(0), "C8");
__Ownable_init(_owner);
__ReentrancyGuard_init_unchained();
@@ -330,7 +330,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _partiallyPaused new boolean value to set systemPartiallyPaused to
*/
function setSystemPartiallyPaused(bool _partiallyPaused) external onlyPartialPauser {
- require(systemPartiallyPaused != _partiallyPaused, "CO9");
+ require(systemPartiallyPaused != _partiallyPaused, "C9");
systemPartiallyPaused = _partiallyPaused;
@@ -339,11 +339,11 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
/**
* @notice allows the fullPauser to toggle the systemFullyPaused variable and fully pause or fully unpause the system
- * @dev can only be called by the fullPauser
+ * @dev can only be called by the fullyPauser
* @param _fullyPaused new boolean value to set systemFullyPaused to
*/
function setSystemFullyPaused(bool _fullyPaused) external onlyFullPauser {
- require(systemFullyPaused != _fullyPaused, "CO9");
+ require(systemFullyPaused != _fullyPaused, "C9");
systemFullyPaused = _fullyPaused;
@@ -356,11 +356,9 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _fullPauser new fullPauser address
*/
function setFullPauser(address _fullPauser) external onlyOwner {
- require(_fullPauser != address(0), "CO10");
- require(fullPauser != _fullPauser, "CO9");
-
+ require(_fullPauser != address(0), "C10");
+ require(fullPauser != _fullPauser, "C9");
emit FullPauserUpdated(fullPauser, _fullPauser);
-
fullPauser = _fullPauser;
}
@@ -370,11 +368,9 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _partialPauser new partialPauser address
*/
function setPartialPauser(address _partialPauser) external onlyOwner {
- require(_partialPauser != address(0), "CO11");
- require(partialPauser != _partialPauser, "CO9");
-
+ require(_partialPauser != address(0), "C11");
+ require(partialPauser != _partialPauser, "C9");
emit PartialPauserUpdated(partialPauser, _partialPauser);
-
partialPauser = _partialPauser;
}
@@ -385,7 +381,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _isRestricted new call restriction state
*/
function setCallRestriction(bool _isRestricted) external onlyOwner {
- require(callRestricted != _isRestricted, "CO9");
+ require(callRestricted != _isRestricted, "C9");
callRestricted = _isRestricted;
@@ -399,7 +395,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _isOperator new boolean value that expresses if the sender is giving or revoking privileges for _operator
*/
function setOperator(address _operator, bool _isOperator) external {
- require(operators[msg.sender][_operator] != _isOperator, "CO9");
+ require(operators[msg.sender][_operator] != _isOperator, "C9");
operators[msg.sender][_operator] = _isOperator;
@@ -420,7 +416,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _cap cap amount, should be scaled by collateral asset decimals
*/
function setNakedCap(address _collateral, uint256 _cap) external onlyOwner {
- require(_cap > 0, "CO36");
+ require(_cap > 0, "C36");
nakedCap[_collateral] = _cap;
@@ -489,7 +485,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @return amount of collateral that can be taken out
*/
function getProceed(address _owner, uint256 _vaultId) external view returns (uint256) {
- (MarginVault.Vault memory vault, uint256 typeVault, ) = getVault(_owner, _vaultId);
+ (MarginVault.Vault memory vault, uint256 typeVault, ) = getVaultWithDetails(_owner, _vaultId);
(uint256 netValue, bool isExcess) = calculator.getExcessCollateral(vault, typeVault);
@@ -529,30 +525,34 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @return amount of collateral to pay out
*/
function getPayout(address _otoken, uint256 _amount) public view returns (uint256) {
- uint256 rate = calculator.getExpiredPayoutRate(_otoken);
- return rate.mul(_amount).div(10**BASE);
+ return calculator.getExpiredPayoutRate(_otoken).mul(_amount).div(10**BASE);
}
/**
* @dev return if an expired oToken is ready to be settled, only true when price for underlying,
* strike and collateral assets at this specific expiry is available in our Oracle module
+ * @param _otoken oToken
+ */
+ function isSettlementAllowed(address _otoken) external view returns (bool) {
+ (address underlying, address strike, address collateral, uint256 expiry) = _getOtokenDetails(_otoken);
+ return _canSettleAssets(underlying, strike, collateral, expiry);
+ }
+
+ /**
+ * @dev return if underlying, strike, collateral are all allowed to be settled
* @param _underlying oToken underlying asset
* @param _strike oToken strike asset
* @param _collateral oToken collateral asset
* @param _expiry otoken expiry timestamp
* @return True if the oToken has expired AND all oracle prices at the expiry timestamp have been finalized, False if not
*/
- function isSettlementAllowed(
+ function canSettleAssets(
address _underlying,
address _strike,
address _collateral,
uint256 _expiry
- ) public view returns (bool) {
- bool isUnderlyingFinalized = oracle.isDisputePeriodOver(_underlying, _expiry);
- bool isStrikeFinalized = oracle.isDisputePeriodOver(_strike, _expiry);
- bool isCollateralFinalized = oracle.isDisputePeriodOver(_collateral, _expiry);
-
- return isUnderlyingFinalized && isStrikeFinalized && isCollateralFinalized;
+ ) external view returns (bool) {
+ return _canSettleAssets(_underlying, _strike, _collateral, _expiry);
}
/**
@@ -570,9 +570,17 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @return True if the otoken has expired, False if not
*/
function hasExpired(address _otoken) external view returns (bool) {
- uint256 otokenExpiryTimestamp = OtokenInterface(_otoken).expiryTimestamp();
+ return now >= OtokenInterface(_otoken).expiryTimestamp();
+ }
- return now >= otokenExpiryTimestamp;
+ /**
+ * @notice return a specific vault
+ * @param _owner account owner
+ * @param _vaultId vault id of vault to return
+ * @return Vault struct that corresponds to the _vaultId of _owner
+ */
+ function getVault(address _owner, uint256 _vaultId) external view returns (MarginVault.Vault memory) {
+ return (vaults[_owner][_vaultId]);
}
/**
@@ -581,7 +589,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _vaultId vault id of vault to return
* @return Vault struct that corresponds to the _vaultId of _owner, vault type and the latest timestamp when the vault was updated
*/
- function getVault(address _owner, uint256 _vaultId)
+ function getVaultWithDetails(address _owner, uint256 _vaultId)
public
view
returns (
@@ -593,6 +601,24 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
return (vaults[_owner][_vaultId], vaultType[_owner][_vaultId], vaultLatestUpdate[_owner][_vaultId]);
}
+ /**
+ * @notice get cap amount for collateral asset
+ * @param _asset collateral asset address
+ * @return cap amount
+ */
+ function getNakedCap(address _asset) external view returns (uint256) {
+ return nakedCap[_asset];
+ }
+
+ /**
+ * @notice get amount of collateral deposited in all naked margin vaults
+ * @param _asset collateral asset address
+ * @return naked pool balance
+ */
+ function getNakedPoolBalance(address _asset) external view returns (uint256) {
+ return nakedPoolBalance[_asset];
+ }
+
/**
* @notice execute a variety of actions
* @dev for each action in the action array, execute the corresponding action, only one vault can be modified
@@ -628,8 +654,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
) {
// check if this action is manipulating the same vault as all other actions, if a vault has already been updated
if (vaultUpdated) {
- require(vaultOwner == action.owner, "CO12");
- require(vaultId == action.vaultId, "CO13");
+ require(vaultOwner == action.owner, "C12");
+ require(vaultId == action.vaultId, "C13");
}
vaultUpdated = true;
vaultId = action.vaultId;
@@ -670,10 +696,10 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _vaultId vault id of the final vault
*/
function _verifyFinalState(address _owner, uint256 _vaultId) internal view {
- (MarginVault.Vault memory vault, uint256 typeVault, ) = getVault(_owner, _vaultId);
+ (MarginVault.Vault memory vault, uint256 typeVault, ) = getVaultWithDetails(_owner, _vaultId);
(, bool isValidVault) = calculator.getExcessCollateral(vault, typeVault);
- require(isValidVault, "CO14");
+ require(isValidVault, "C14");
}
/**
@@ -688,7 +714,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
{
uint256 vaultId = accountVaultCounter[_args.owner].add(1);
- require(_args.vaultId == vaultId, "CO15");
+ require(_args.vaultId == vaultId, "C15");
// store new vault
accountVaultCounter[_args.owner] = vaultId;
@@ -707,15 +733,15 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
notPartiallyPaused
onlyAuthorized(msg.sender, _args.owner)
{
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
// only allow vault owner or vault operator to deposit long otoken
- require((_args.from == msg.sender) || (_args.from == _args.owner), "CO16");
+ require((_args.from == msg.sender) || (_args.from == _args.owner), "C16");
- require(whitelist.isWhitelistedOtoken(_args.asset), "CO17");
+ require(whitelist.isWhitelistedOtoken(_args.asset), "C17");
OtokenInterface otoken = OtokenInterface(_args.asset);
- require(now < otoken.expiryTimestamp(), "CO18");
+ require(now < otoken.expiryTimestamp(), "C18");
vaults[_args.owner][_args.vaultId].addLong(_args.asset, _args.amount, _args.index);
@@ -734,11 +760,11 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
notPartiallyPaused
onlyAuthorized(msg.sender, _args.owner)
{
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
OtokenInterface otoken = OtokenInterface(_args.asset);
- require(now < otoken.expiryTimestamp(), "CO19");
+ require(now < otoken.expiryTimestamp(), "C19");
vaults[_args.owner][_args.vaultId].removeLong(_args.asset, _args.amount, _args.index);
@@ -757,18 +783,18 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
notPartiallyPaused
onlyAuthorized(msg.sender, _args.owner)
{
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
// only allow vault owner or vault operator to deposit collateral
- require((_args.from == msg.sender) || (_args.from == _args.owner), "CO20");
+ require((_args.from == msg.sender) || (_args.from == _args.owner), "C20");
- require(whitelist.isWhitelistedCollateral(_args.asset), "CO21");
+ require(whitelist.isWhitelistedCollateral(_args.asset), "C21");
- (, uint256 typeVault, ) = getVault(_args.owner, _args.vaultId);
+ (, uint256 typeVault, ) = getVaultWithDetails(_args.owner, _args.vaultId);
if (typeVault == 1) {
nakedPoolBalance[_args.asset] = nakedPoolBalance[_args.asset].add(_args.amount);
- require(nakedPoolBalance[_args.asset] <= nakedCap[_args.asset], "CO37");
+ require(nakedPoolBalance[_args.asset] <= nakedCap[_args.asset], "C37");
}
vaults[_args.owner][_args.vaultId].addCollateral(_args.asset, _args.amount, _args.index);
@@ -788,14 +814,14 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
notPartiallyPaused
onlyAuthorized(msg.sender, _args.owner)
{
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
- (MarginVault.Vault memory vault, uint256 typeVault, ) = getVault(_args.owner, _args.vaultId);
+ (MarginVault.Vault memory vault, uint256 typeVault, ) = getVaultWithDetails(_args.owner, _args.vaultId);
if (_isNotEmpty(vault.shortOtokens)) {
OtokenInterface otoken = OtokenInterface(vault.shortOtokens[0]);
- require(now < otoken.expiryTimestamp(), "CO22");
+ require(now < otoken.expiryTimestamp(), "C22");
}
if (typeVault == 1) {
@@ -819,12 +845,12 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
notPartiallyPaused
onlyAuthorized(msg.sender, _args.owner)
{
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
- require(whitelist.isWhitelistedOtoken(_args.otoken), "CO23");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
+ require(whitelist.isWhitelistedOtoken(_args.otoken), "C23");
OtokenInterface otoken = OtokenInterface(_args.otoken);
- require(now < otoken.expiryTimestamp(), "CO24");
+ require(now < otoken.expiryTimestamp(), "C24");
vaults[_args.owner][_args.vaultId].addShort(_args.otoken, _args.amount, _args.index);
@@ -844,14 +870,14 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
onlyAuthorized(msg.sender, _args.owner)
{
// check that vault id is valid for this vault owner
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
// only allow vault owner or vault operator to burn otoken
- require((_args.from == msg.sender) || (_args.from == _args.owner), "CO25");
+ require((_args.from == msg.sender) || (_args.from == _args.owner), "C25");
OtokenInterface otoken = OtokenInterface(_args.otoken);
// do not allow burning expired otoken
- require(now < otoken.expiryTimestamp(), "CO26");
+ require(now < otoken.expiryTimestamp(), "C26");
// remove otoken from vault
vaults[_args.owner][_args.vaultId].removeShort(_args.otoken, _args.amount, _args.index);
@@ -871,14 +897,14 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
OtokenInterface otoken = OtokenInterface(_args.otoken);
// check that otoken to redeem is whitelisted
- require(whitelist.isWhitelistedOtoken(_args.otoken), "CO27");
+ require(whitelist.isWhitelistedOtoken(_args.otoken), "C27");
- (address collateral, address underlying, address strike, , uint256 expiry, ) = otoken.getOtokenDetails();
+ (address collateral, address underlying, address strike, uint256 expiry) = _getOtokenDetails(address(otoken));
// only allow redeeming expired otoken
- require(now >= expiry, "CO28");
+ require(now >= expiry, "C28");
- require(isSettlementAllowed(underlying, strike, collateral, expiry), "CO29");
+ require(_canSettleAssets(underlying, strike, collateral, expiry), "C29");
uint256 payout = getPayout(_args.otoken, _args.amount);
@@ -895,9 +921,9 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _args SettleVaultArgs structure
*/
function _settleVault(Actions.SettleVaultArgs memory _args) internal onlyAuthorized(msg.sender, _args.owner) {
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
- (MarginVault.Vault memory vault, uint256 typeVault, ) = getVault(_args.owner, _args.vaultId);
+ (MarginVault.Vault memory vault, uint256 typeVault, ) = getVaultWithDetails(_args.owner, _args.vaultId);
OtokenInterface otoken;
@@ -910,7 +936,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
bool hasShort = _isNotEmpty(vault.shortOtokens);
bool hasLong = _isNotEmpty(vault.longOtokens);
- require(hasShort || hasLong, "CO30");
+ require(hasShort || hasLong, "C30");
otoken = hasShort ? OtokenInterface(vault.shortOtokens[0]) : OtokenInterface(vault.longOtokens[0]);
@@ -921,17 +947,17 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
}
}
- (address collateral, address underlying, address strike, , uint256 expiry, ) = otoken.getOtokenDetails();
+ (address collateral, address underlying, address strike, uint256 expiry) = _getOtokenDetails(address(otoken));
// do not allow settling vault with un-expired otoken
- require(now >= expiry, "CO31");
- require(isSettlementAllowed(underlying, strike, collateral, expiry), "CO29");
+ require(now >= expiry, "C31");
+ require(_canSettleAssets(underlying, strike, collateral, expiry), "C29");
(uint256 payout, bool isValidVault) = calculator.getExcessCollateral(vault, typeVault);
// require that vault is valid (has excess collateral) before settling
// to avoid allowing settling undercollateralized naked margin vault
- require(isValidVault, "CO32");
+ require(isValidVault, "C32");
delete vaults[_args.owner][_args.vaultId];
@@ -953,7 +979,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
* @param _args liquidation action arguments struct
*/
function _liquidate(Actions.LiquidateArgs memory _args) internal notPartiallyPaused {
- require(_checkVaultId(_args.owner, _args.vaultId), "CO35");
+ require(_checkVaultId(_args.owner, _args.vaultId), "C35");
// check if vault is undercollateralized
// the price is the amount of collateral asset to pay per 1 repaid debt(otoken)
@@ -964,7 +990,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
_args.roundId
);
- require(isUnderCollat, "CO33");
+ require(isUnderCollat, "C33");
// amount of collateral to offer to liquidator
uint256 collateralToSell = _args.amount.mul(price).div(1e8);
@@ -972,7 +998,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
// if vault is partially liquidated (amount of short otoken is still greater than zero)
// make sure remaining collateral amount is greater than dust amount
if (vault.shortAmounts[0].sub(_args.amount) > 0) {
- require(vault.collateralAmounts[0].sub(collateralToSell) >= collateralDust, "CO34");
+ require(vault.collateralAmounts[0].sub(collateralToSell) >= collateralDust, "C34");
}
// burn short otoken from liquidator address, index of short otoken hardcoded at 0
@@ -1057,7 +1083,10 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
uint256
)
{
- (MarginVault.Vault memory vault, uint256 typeVault, uint256 latestUpdateTimestamp) = getVault(_owner, _vaultId);
+ (MarginVault.Vault memory vault, uint256 typeVault, uint256 latestUpdateTimestamp) = getVaultWithDetails(
+ _owner,
+ _vaultId
+ );
(bool isUnderCollat, uint256 price, uint256 collateralDust) = calculator.isLiquidatable(
vault,
typeVault,
@@ -1069,21 +1098,48 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade
}
/**
- * @notice get cap amount for collateral asset
- * @param _asset collateral asset address
- * @return cap amount
+ * @dev get otoken detail, from both otoken versions
*/
- function getNakedCap(address _asset) external view returns (uint256) {
- return nakedCap[_asset];
+ function _getOtokenDetails(address _otoken)
+ internal
+ view
+ returns (
+ address,
+ address,
+ address,
+ uint256
+ )
+ {
+ OtokenInterface otoken = OtokenInterface(_otoken);
+ try otoken.getOtokenDetails() returns (
+ address collateral,
+ address underlying,
+ address strike,
+ uint256,
+ uint256 expiry,
+ bool
+ ) {
+ return (collateral, underlying, strike, expiry);
+ } catch {
+ return (otoken.collateralAsset(), otoken.underlyingAsset(), otoken.strikeAsset(), otoken.expiryTimestamp());
+ }
}
/**
- * @notice get amount of collateral deposited in all naked margin vaults
- * @param _asset collateral asset address
- * @return naked pool balance
+ * @dev return if an expired oToken is ready to be settled, only true when price for underlying,
+ * strike and collateral assets at this specific expiry is available in our Oracle module
+ * @return True if the oToken has expired AND all oracle prices at the expiry timestamp have been finalized, False if not
*/
- function getNakedPoolBalance(address _asset) external view returns (uint256) {
- return nakedPoolBalance[_asset];
+ function _canSettleAssets(
+ address _underlying,
+ address _strike,
+ address _collateral,
+ uint256 _expiry
+ ) internal view returns (bool) {
+ return
+ oracle.isDisputePeriodOver(_underlying, _expiry) &&
+ oracle.isDisputePeriodOver(_strike, _expiry) &&
+ oracle.isDisputePeriodOver(_collateral, _expiry);
}
/**
diff --git a/contracts/core/MarginCalculator.sol b/contracts/core/MarginCalculator.sol
index cad64886f..4987c09fb 100644
--- a/contracts/core/MarginCalculator.sol
+++ b/contracts/core/MarginCalculator.sol
@@ -364,8 +364,6 @@ contract MarginCalculator is Ownable {
function getExpiredPayoutRate(address _otoken) external view returns (uint256) {
require(_otoken != address(0), "MarginCalculator: Invalid token address");
- OtokenInterface otoken = OtokenInterface(_otoken);
-
(
address collateral,
address underlying,
@@ -373,7 +371,7 @@ contract MarginCalculator is Ownable {
uint256 strikePrice,
uint256 expiry,
bool isPut
- ) = otoken.getOtokenDetails();
+ ) = _getOtokenDetails(_otoken);
require(now >= expiry, "MarginCalculator: Otoken not expired yet");
@@ -1072,7 +1070,7 @@ contract MarginCalculator is Ownable {
vaultDetails.longStrikePrice,
vaultDetails.longExpiryTimestamp,
vaultDetails.isLongPut
- ) = long.getOtokenDetails();
+ ) = _getOtokenDetails(address(long));
vaultDetails.longCollateralDecimals = uint256(ERC20Interface(vaultDetails.longCollateralAsset).decimals());
}
@@ -1086,7 +1084,7 @@ contract MarginCalculator is Ownable {
vaultDetails.shortStrikePrice,
vaultDetails.shortExpiryTimestamp,
vaultDetails.isShortPut
- ) = short.getOtokenDetails();
+ ) = _getOtokenDetails(address(short));
vaultDetails.shortCollateralDecimals = uint256(
ERC20Interface(vaultDetails.shortCollateralAsset).decimals()
);
@@ -1249,4 +1247,42 @@ contract MarginCalculator is Ownable {
return _underlyingPrice.isGreaterThan(_strikePrice) ? _underlyingPrice.sub(_strikePrice) : ZERO;
}
+
+ /**
+ * @dev get otoken detail, from both otoken versions
+ */
+ function _getOtokenDetails(address _otoken)
+ internal
+ view
+ returns (
+ address,
+ address,
+ address,
+ uint256,
+ uint256,
+ bool
+ )
+ {
+ OtokenInterface otoken = OtokenInterface(_otoken);
+ try otoken.getOtokenDetails() returns (
+ address collateral,
+ address underlying,
+ address strike,
+ uint256 strikePrice,
+ uint256 expiry,
+ bool isPut
+ ) {
+ return (collateral, underlying, strike, strikePrice, expiry, isPut);
+ } catch {
+ // v1 otoken
+ return (
+ otoken.collateralAsset(),
+ otoken.underlyingAsset(),
+ otoken.strikeAsset(),
+ otoken.strikePrice(),
+ otoken.expiryTimestamp(),
+ otoken.isPut()
+ );
+ }
+ }
}
diff --git a/contracts/libs/Actions.sol b/contracts/libs/Actions.sol
index c32f709ef..08c70aba7 100644
--- a/contracts/libs/Actions.sol
+++ b/contracts/libs/Actions.sol
@@ -9,6 +9,30 @@ import {MarginVault} from "./MarginVault.sol";
* @title Actions
* @author Opyn Team
* @notice A library that provides a ActionArgs struct, sub types of Action structs, and functions to parse ActionArgs into specific Actions.
+ * errorCode
+ * A1 can only parse arguments for open vault actions
+ * A2 cannot open vault for an invalid account
+ * A3 cannot open vault with an invalid type
+ * A4 can only parse arguments for mint actions
+ * A5 cannot mint from an invalid account
+ * A6 can only parse arguments for burn actions
+ * A7 cannot burn from an invalid account
+ * A8 can only parse arguments for deposit actions
+ * A9 cannot deposit to an invalid account
+ * A10 can only parse arguments for withdraw actions
+ * A11 cannot withdraw from an invalid account
+ * A12 cannot withdraw to an invalid account
+ * A13 can only parse arguments for redeem actions
+ * A14 cannot redeem to an invalid account
+ * A15 can only parse arguments for settle vault actions
+ * A16 cannot settle vault for an invalid account
+ * A17 cannot withdraw payout to an invalid account
+ * A18 can only parse arguments for liquidate action
+ * A19 cannot liquidate vault for an invalid account owner
+ * A20 cannot send collateral to an invalid account
+ * A21 cannot parse liquidate action with no round id
+ * A22 can only parse arguments for call actions
+ * A23 target address cannot be address(0)
*/
library Actions {
// possible actions that can be performed
@@ -163,8 +187,8 @@ library Actions {
* @return arguments for a open vault action
*/
function _parseOpenVaultArgs(ActionArgs memory _args) internal pure returns (OpenVaultArgs memory) {
- require(_args.actionType == ActionType.OpenVault, "Actions: can only parse arguments for open vault actions");
- require(_args.owner != address(0), "Actions: cannot open vault for an invalid account");
+ require(_args.actionType == ActionType.OpenVault, "A1");
+ require(_args.owner != address(0), "A2");
// if not _args.data included, vault type will be 0 by default
uint256 vaultType;
@@ -175,7 +199,7 @@ library Actions {
}
// for now we only have 2 vault types
- require(vaultType < 2, "Actions: cannot open vault with an invalid type");
+ require(vaultType < 2, "A3");
return OpenVaultArgs({owner: _args.owner, vaultId: _args.vaultId, vaultType: vaultType});
}
@@ -186,8 +210,8 @@ library Actions {
* @return arguments for a mint action
*/
function _parseMintArgs(ActionArgs memory _args) internal pure returns (MintArgs memory) {
- require(_args.actionType == ActionType.MintShortOption, "Actions: can only parse arguments for mint actions");
- require(_args.owner != address(0), "Actions: cannot mint from an invalid account");
+ require(_args.actionType == ActionType.MintShortOption, "A4");
+ require(_args.owner != address(0), "A5");
return
MintArgs({
@@ -206,8 +230,8 @@ library Actions {
* @return arguments for a burn action
*/
function _parseBurnArgs(ActionArgs memory _args) internal pure returns (BurnArgs memory) {
- require(_args.actionType == ActionType.BurnShortOption, "Actions: can only parse arguments for burn actions");
- require(_args.owner != address(0), "Actions: cannot burn from an invalid account");
+ require(_args.actionType == ActionType.BurnShortOption, "A6");
+ require(_args.owner != address(0), "A7");
return
BurnArgs({
@@ -228,9 +252,9 @@ library Actions {
function _parseDepositArgs(ActionArgs memory _args) internal pure returns (DepositArgs memory) {
require(
(_args.actionType == ActionType.DepositLongOption) || (_args.actionType == ActionType.DepositCollateral),
- "Actions: can only parse arguments for deposit actions"
+ "A8"
);
- require(_args.owner != address(0), "Actions: cannot deposit to an invalid account");
+ require(_args.owner != address(0), "A9");
return
DepositArgs({
@@ -251,10 +275,10 @@ library Actions {
function _parseWithdrawArgs(ActionArgs memory _args) internal pure returns (WithdrawArgs memory) {
require(
(_args.actionType == ActionType.WithdrawLongOption) || (_args.actionType == ActionType.WithdrawCollateral),
- "Actions: can only parse arguments for withdraw actions"
+ "A10"
);
- require(_args.owner != address(0), "Actions: cannot withdraw from an invalid account");
- require(_args.secondAddress != address(0), "Actions: cannot withdraw to an invalid account");
+ require(_args.owner != address(0), "A11");
+ require(_args.secondAddress != address(0), "A12");
return
WithdrawArgs({
@@ -273,8 +297,8 @@ library Actions {
* @return arguments for a redeem action
*/
function _parseRedeemArgs(ActionArgs memory _args) internal pure returns (RedeemArgs memory) {
- require(_args.actionType == ActionType.Redeem, "Actions: can only parse arguments for redeem actions");
- require(_args.secondAddress != address(0), "Actions: cannot redeem to an invalid account");
+ require(_args.actionType == ActionType.Redeem, "A13");
+ require(_args.secondAddress != address(0), "A14");
return RedeemArgs({receiver: _args.secondAddress, otoken: _args.asset, amount: _args.amount});
}
@@ -285,21 +309,18 @@ library Actions {
* @return arguments for a settle vault action
*/
function _parseSettleVaultArgs(ActionArgs memory _args) internal pure returns (SettleVaultArgs memory) {
- require(
- _args.actionType == ActionType.SettleVault,
- "Actions: can only parse arguments for settle vault actions"
- );
- require(_args.owner != address(0), "Actions: cannot settle vault for an invalid account");
- require(_args.secondAddress != address(0), "Actions: cannot withdraw payout to an invalid account");
+ require(_args.actionType == ActionType.SettleVault, "A15");
+ require(_args.owner != address(0), "A16");
+ require(_args.secondAddress != address(0), "A17");
return SettleVaultArgs({owner: _args.owner, vaultId: _args.vaultId, to: _args.secondAddress});
}
function _parseLiquidateArgs(ActionArgs memory _args) internal pure returns (LiquidateArgs memory) {
- require(_args.actionType == ActionType.Liquidate, "Actions: can only parse arguments for liquidate action");
- require(_args.owner != address(0), "Actions: cannot liquidate vault for an invalid account owner");
- require(_args.secondAddress != address(0), "Actions: cannot send collateral to an invalid account");
- require(_args.data.length == 32, "Actions: cannot parse liquidate action with no round id");
+ require(_args.actionType == ActionType.Liquidate, "A18");
+ require(_args.owner != address(0), "A19");
+ require(_args.secondAddress != address(0), "A20");
+ require(_args.data.length == 32, "A21");
// decode chainlink round id from _args.data
uint256 roundId = abi.decode(_args.data, (uint256));
@@ -320,8 +341,8 @@ library Actions {
* @return arguments for a call action
*/
function _parseCallArgs(ActionArgs memory _args) internal pure returns (CallArgs memory) {
- require(_args.actionType == ActionType.Call, "Actions: can only parse arguments for call actions");
- require(_args.secondAddress != address(0), "Actions: target address cannot be address(0)");
+ require(_args.actionType == ActionType.Call, "A22");
+ require(_args.secondAddress != address(0), "A23");
return CallArgs({callee: _args.secondAddress, data: _args.data});
}
diff --git a/contracts/libs/MarginVault.sol b/contracts/libs/MarginVault.sol
index 11a17e84c..1cc418ce4 100644
--- a/contracts/libs/MarginVault.sol
+++ b/contracts/libs/MarginVault.sol
@@ -7,6 +7,19 @@ pragma experimental ABIEncoderV2;
import {SafeMath} from "../packages/oz/SafeMath.sol";
+/**
+ * MarginVault Error Codes
+ * V1: invalid short otoken amount
+ * V2: invalid short otoken index
+ * V3: short otoken address mismatch
+ * V4: invalid long otoken amount
+ * V5: invalid long otoken index
+ * V6: long otoken address mismatch
+ * V7: invalid collateral amount
+ * V8: invalid collateral token index
+ * V9: collateral token address mismatch
+ */
+
/**
* @title MarginVault
* @author Opyn Team
@@ -47,7 +60,7 @@ library MarginVault {
uint256 _amount,
uint256 _index
) external {
- require(_amount > 0, "MarginVault: invalid short otoken amount");
+ require(_amount > 0, "V1");
// valid indexes in any array are between 0 and array.length - 1.
// if adding an amount to an preexisting short oToken, check that _index is in the range of 0->length-1
@@ -55,15 +68,9 @@ library MarginVault {
_vault.shortOtokens.push(_shortOtoken);
_vault.shortAmounts.push(_amount);
} else {
- require(
- (_index < _vault.shortOtokens.length) && (_index < _vault.shortAmounts.length),
- "MarginVault: invalid short otoken index"
- );
+ require((_index < _vault.shortOtokens.length) && (_index < _vault.shortAmounts.length), "V2");
address existingShort = _vault.shortOtokens[_index];
- require(
- (existingShort == _shortOtoken) || (existingShort == address(0)),
- "MarginVault: short otoken address mismatch"
- );
+ require((existingShort == _shortOtoken) || (existingShort == address(0)), "V3");
_vault.shortAmounts[_index] = _vault.shortAmounts[_index].add(_amount);
_vault.shortOtokens[_index] = _shortOtoken;
@@ -84,8 +91,8 @@ library MarginVault {
uint256 _index
) external {
// check that the removed short oToken exists in the vault at the specified index
- require(_index < _vault.shortOtokens.length, "MarginVault: invalid short otoken index");
- require(_vault.shortOtokens[_index] == _shortOtoken, "MarginVault: short otoken address mismatch");
+ require(_index < _vault.shortOtokens.length, "V2");
+ require(_vault.shortOtokens[_index] == _shortOtoken, "V3");
uint256 newShortAmount = _vault.shortAmounts[_index].sub(_amount);
@@ -108,7 +115,7 @@ library MarginVault {
uint256 _amount,
uint256 _index
) external {
- require(_amount > 0, "MarginVault: invalid long otoken amount");
+ require(_amount > 0, "V4");
// valid indexes in any array are between 0 and array.length - 1.
// if adding an amount to an preexisting short oToken, check that _index is in the range of 0->length-1
@@ -116,15 +123,9 @@ library MarginVault {
_vault.longOtokens.push(_longOtoken);
_vault.longAmounts.push(_amount);
} else {
- require(
- (_index < _vault.longOtokens.length) && (_index < _vault.longAmounts.length),
- "MarginVault: invalid long otoken index"
- );
+ require((_index < _vault.longOtokens.length) && (_index < _vault.longAmounts.length), "V5");
address existingLong = _vault.longOtokens[_index];
- require(
- (existingLong == _longOtoken) || (existingLong == address(0)),
- "MarginVault: long otoken address mismatch"
- );
+ require((existingLong == _longOtoken) || (existingLong == address(0)), "V6");
_vault.longAmounts[_index] = _vault.longAmounts[_index].add(_amount);
_vault.longOtokens[_index] = _longOtoken;
@@ -145,8 +146,8 @@ library MarginVault {
uint256 _index
) external {
// check that the removed long oToken exists in the vault at the specified index
- require(_index < _vault.longOtokens.length, "MarginVault: invalid long otoken index");
- require(_vault.longOtokens[_index] == _longOtoken, "MarginVault: long otoken address mismatch");
+ require(_index < _vault.longOtokens.length, "V5");
+ require(_vault.longOtokens[_index] == _longOtoken, "V6");
uint256 newLongAmount = _vault.longAmounts[_index].sub(_amount);
@@ -169,7 +170,7 @@ library MarginVault {
uint256 _amount,
uint256 _index
) external {
- require(_amount > 0, "MarginVault: invalid collateral amount");
+ require(_amount > 0, "V7");
// valid indexes in any array are between 0 and array.length - 1.
// if adding an amount to an preexisting short oToken, check that _index is in the range of 0->length-1
@@ -177,15 +178,9 @@ library MarginVault {
_vault.collateralAssets.push(_collateralAsset);
_vault.collateralAmounts.push(_amount);
} else {
- require(
- (_index < _vault.collateralAssets.length) && (_index < _vault.collateralAmounts.length),
- "MarginVault: invalid collateral token index"
- );
+ require((_index < _vault.collateralAssets.length) && (_index < _vault.collateralAmounts.length), "V8");
address existingCollateral = _vault.collateralAssets[_index];
- require(
- (existingCollateral == _collateralAsset) || (existingCollateral == address(0)),
- "MarginVault: collateral token address mismatch"
- );
+ require((existingCollateral == _collateralAsset) || (existingCollateral == address(0)), "V9");
_vault.collateralAmounts[_index] = _vault.collateralAmounts[_index].add(_amount);
_vault.collateralAssets[_index] = _collateralAsset;
@@ -206,8 +201,8 @@ library MarginVault {
uint256 _index
) external {
// check that the removed collateral exists in the vault at the specified index
- require(_index < _vault.collateralAssets.length, "MarginVault: invalid collateral asset index");
- require(_vault.collateralAssets[_index] == _collateralAsset, "MarginVault: collateral token address mismatch");
+ require(_index < _vault.collateralAssets.length, "V8");
+ require(_vault.collateralAssets[_index] == _collateralAsset, "V9");
uint256 newCollateralAmount = _vault.collateralAmounts[_index].sub(_amount);
diff --git a/contracts/tests/OtokenImplV1.sol b/contracts/tests/OtokenImplV1.sol
new file mode 100644
index 000000000..0766ba3f9
--- /dev/null
+++ b/contracts/tests/OtokenImplV1.sol
@@ -0,0 +1,64 @@
+pragma solidity =0.6.10;
+
+import {ERC20PermitUpgradeable} from "../packages/oz/upgradeability/erc20-permit/ERC20PermitUpgradeable.sol";
+import {AddressBookInterface} from "../interfaces/AddressBookInterface.sol";
+
+/**
+ * SPDX-License-Identifier: UNLICENSED
+ * @dev The Otoken inherits ERC20PermitUpgradeable because we need to use the init instead of constructor
+ * This is V1 implementation, with no getOtokenDetails()
+ */
+contract OtokenImplV1 is ERC20PermitUpgradeable {
+ address public addressBook;
+ address public controller;
+ address public underlyingAsset;
+ address public strikeAsset;
+ address public collateralAsset;
+
+ uint256 public strikePrice;
+ uint256 public expiryTimestamp;
+
+ bool public isPut;
+
+ bool public inited = false;
+
+ function init(
+ address _addressBook,
+ address _underlyingAsset,
+ address _strikeAsset,
+ address _collateralAsset,
+ uint256 _strikePrice,
+ uint256 _expiryTimestamp,
+ bool _isPut
+ ) external initializer {
+ inited = true;
+ controller = AddressBookInterface(_addressBook).getController();
+ underlyingAsset = _underlyingAsset;
+ strikeAsset = _strikeAsset;
+ collateralAsset = _collateralAsset;
+ strikePrice = _strikePrice;
+ expiryTimestamp = _expiryTimestamp;
+ isPut = _isPut;
+ string memory tokenName = "ETHUSDC/1597511955/200P/USDC";
+ string memory tokenSymbol = "oETHUSDCP";
+ __ERC20_init_unchained(tokenName, tokenSymbol);
+ __ERC20Permit_init(tokenName);
+ _setupDecimals(8);
+ }
+
+ function mintOtoken(address _to, uint256 _amount) external {
+ _mint(_to, _amount);
+ }
+
+ function burnOtoken(address account, uint256 amount) external {
+ _burn(account, amount);
+ }
+
+ function getChainId() external view returns (uint256 chainId) {
+ this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ chainId := chainid()
+ }
+ }
+}
diff --git a/docs/contracts-documentation/core/Controller.md b/docs/contracts-documentation/core/Controller.md
index 865847ca5..f39f8f8ce 100644
--- a/docs/contracts-documentation/core/Controller.md
+++ b/docs/contracts-documentation/core/Controller.md
@@ -42,6 +42,8 @@ Contract that controls the Gamma Protocol and the interaction of all sub contrac
- `refreshConfiguration() (external)`
+- `setNakedCap(address _collateral, uint256 _cap) (external)`
+
- `operate(struct Actions.ActionArgs[] _actions) (external)`
- `sync(address _owner, uint256 _vaultId) (external)`
@@ -56,13 +58,21 @@ Contract that controls the Gamma Protocol and the interaction of all sub contrac
- `getPayout(address _otoken, uint256 _amount) (public)`
-- `isSettlementAllowed(address _underlying, address _strike, address _collateral, uint256 _expiry) (public)`
+- `isSettlementAllowed(address _otoken) (external)`
+
+- `canSettleAssets(address _underlying, address _strike, address _collateral, uint256 _expiry) (external)`
- `getAccountVaultCounter(address _accountOwner) (external)`
- `hasExpired(address _otoken) (external)`
-- `getVault(address _owner, uint256 _vaultId) (public)`
+- `getVault(address _owner, uint256 _vaultId) (external)`
+
+- `getVaultWithDetails(address _owner, uint256 _vaultId) (public)`
+
+- `getNakedCap(address _asset) (external)`
+
+- `getNakedPoolBalance(address _asset) (external)`
- `_runActions(struct Actions.ActionArgs[] _actions) (internal)`
@@ -98,6 +108,10 @@ Contract that controls the Gamma Protocol and the interaction of all sub contrac
- `_isLiquidatable(address _owner, uint256 _vaultId, uint256 _roundId) (internal)`
+- `_getOtokenDetails(address _otoken) (internal)`
+
+- `_canSettleAssets(address _underlying, address _strike, address _collateral, uint256 _expiry) (internal)`
+
- `_refreshConfigInternal() (internal)`
## Events:
@@ -138,6 +152,8 @@ Contract that controls the Gamma Protocol and the interaction of all sub contrac
- `Donated(address donator, address asset, uint256 amount)`
+- `NakedCapUpdated(address collateral, uint256 cap)`
+
### Modifier `notPartiallyPaused()`
modifier to check if the system is not partially paused, where only redeem and settleVault is allowed
@@ -216,7 +232,7 @@ use donate() instead of direct transfer() to store the balance in assetBalance
allows the partialPauser to toggle the systemPartiallyPaused variable and partially pause or partially unpause the system
-can only be called by the partialPauser
+can only be called by the pauser
#### Parameters:
@@ -226,7 +242,7 @@ can only be called by the partialPauser
allows the fullPauser to toggle the systemFullyPaused variable and fully pause or fully unpause the system
-can only be called by the fullPauser
+can only be called by the pauser
#### Parameters:
@@ -280,6 +296,18 @@ can only be updated by the vault owner
updates the configuration of the controller. can only be called by the owner
+### Function `setNakedCap(address _collateral, uint256 _cap) external`
+
+set cap amount for collateral asset used in naked margin
+
+can only be called by owner
+
+#### Parameters:
+
+- `_collateral`: collateral asset address
+
+- `_cap`: cap amount, should be scaled by collateral asset decimals
+
### Function `operate(struct Actions.ActionArgs[] _actions) external`
execute a number of actions on specific vaults
@@ -376,7 +404,7 @@ get an oToken's payout/cash value after expiry, in the collateral asset
- amount of collateral to pay out
-### Function `isSettlementAllowed(address _underlying, address _strike, address _collateral, uint256 _expiry) → bool public`
+### Function `isSettlementAllowed(address _otoken) → bool external`
return if an expired oToken is ready to be settled, only true when price for underlying,
@@ -384,6 +412,14 @@ strike and collateral assets at this specific expiry is available in our Oracle
#### Parameters:
+- `_otoken`: oToken
+
+### Function `canSettleAssets(address _underlying, address _strike, address _collateral, uint256 _expiry) → bool external`
+
+return if underlying, strike, collateral are all allowed to be settled
+
+#### Parameters:
+
- `_underlying`: oToken underlying asset
- `_strike`: oToken strike asset
@@ -420,7 +456,21 @@ check if an oToken has expired
- True if the otoken has expired, False if not
-### Function `getVault(address _owner, uint256 _vaultId) → struct MarginVault.Vault, uint256, uint256 public`
+### Function `getVault(address _owner, uint256 _vaultId) → struct MarginVault.Vault external`
+
+return a specific vault
+
+#### Parameters:
+
+- `_owner`: account owner
+
+- `_vaultId`: vault id of vault to return
+
+#### Return Values:
+
+- Vault struct that corresponds to the _vaultId of _owner
+
+### Function `getVaultWithDetails(address _owner, uint256 _vaultId) → struct MarginVault.Vault, uint256, uint256 public`
return a specific vault
@@ -434,6 +484,30 @@ return a specific vault
- Vault struct that corresponds to the _vaultId of _owner, vault type and the latest timestamp when the vault was updated
+### Function `getNakedCap(address _asset) → uint256 external`
+
+get cap amount for collateral asset
+
+#### Parameters:
+
+- `_asset`: collateral asset address
+
+#### Return Values:
+
+- cap amount
+
+### Function `getNakedPoolBalance(address _asset) → uint256 external`
+
+get amount of collateral deposited in all naked margin vaults
+
+#### Parameters:
+
+- `_asset`: collateral asset address
+
+#### Return Values:
+
+- naked pool balance
+
### Function `_runActions(struct Actions.ActionArgs[] _actions) → bool, address, uint256 internal`
execute a variety of actions
@@ -618,6 +692,20 @@ check if a vault is liquidatable in a specific round id
- vault struct, isLiquidatable, true if vault is undercollateralized, the price of 1 repaid otoken and the otoken collateral dust amount
+### Function `_getOtokenDetails(address _otoken) → address, address, address, uint256 internal`
+
+get otoken detail, from both otoken versions
+
+### Function `_canSettleAssets(address _underlying, address _strike, address _collateral, uint256 _expiry) → bool internal`
+
+return if an expired oToken is ready to be settled, only true when price for underlying,
+
+strike and collateral assets at this specific expiry is available in our Oracle module
+
+#### Return Values:
+
+- True if the oToken has expired AND all oracle prices at the expiry timestamp have been finalized, False if not
+
### Function `_refreshConfigInternal() internal`
updates the internal configuration of the controller
@@ -693,3 +781,7 @@ emits an event when the call action restriction changes
### Event `Donated(address donator, address asset, uint256 amount)`
emits an event when a donation transfer executed
+
+### Event `NakedCapUpdated(address collateral, uint256 cap)`
+
+emits an event when naked cap is updated
diff --git a/docs/contracts-documentation/core/MarginCalculator.md b/docs/contracts-documentation/core/MarginCalculator.md
index f69dc27cf..8d720b9ae 100644
--- a/docs/contracts-documentation/core/MarginCalculator.md
+++ b/docs/contracts-documentation/core/MarginCalculator.md
@@ -8,8 +8,6 @@ Calculator module that checks if a given vault is valid, calculates margin requi
- `setCollateralDust(address _collateral, uint256 _dust) (external)`
-- `setCollateralCap(address _collateral, uint256 _cap) (external)`
-
- `setUpperBoundValues(address _underlying, address _strike, address _collateral, bool _isPut, uint256[] _timesToExpiry, uint256[] _values) (external)`
- `updateUpperBoundValue(address _underlying, address _strike, address _collateral, bool _isPut, uint256 _timeToExpiry, uint256 _value) (external)`
@@ -20,8 +18,6 @@ Calculator module that checks if a given vault is valid, calculates margin requi
- `getCollateralDust(address _collateral) (external)`
-- `getCollateralCap(address _collateral) (external)`
-
- `getTimesToExpiry(address _underlying, address _strike, address _collateral, bool _isPut) (external)`
- `getMaxPrice(address _underlying, address _strike, address _collateral, bool _isPut, uint256 _timeToExpiry) (external)`
@@ -74,12 +70,12 @@ Calculator module that checks if a given vault is valid, calculates margin requi
- `_getCashValue(struct FixedPointInt256.FixedPointInt _strikePrice, struct FixedPointInt256.FixedPointInt _underlyingPrice, bool _isPut) (internal)`
+- `_getOtokenDetails(address _otoken) (internal)`
+
## Events:
- `CollateralDustUpdated(address collateral, uint256 dust)`
-- `CollateralCapUpdated(address collateral, uint256 cap)`
-
- `TimeToExpiryAdded(bytes32 productHash, uint256 timeToExpiry)`
- `MaxPriceAdded(bytes32 productHash, uint256 timeToExpiry, uint256 value)`
@@ -110,18 +106,6 @@ can only be called by owner
- `_dust`: dust amount, should be scaled by collateral asset decimals
-### Function `setCollateralCap(address _collateral, uint256 _cap) external`
-
-set cap amount for collateral asset used in naked margin
-
-can only be called by owner
-
-#### Parameters:
-
-- `_collateral`: collateral asset address
-
-- `_cap`: cap amount, should be scaled by collateral asset decimals
-
### Function `setUpperBoundValues(address _underlying, address _strike, address _collateral, bool _isPut, uint256[] _timesToExpiry, uint256[] _values) external`
set product upper bound values
@@ -202,18 +186,6 @@ get dust amount for collateral asset
- dust amount
-### Function `getCollateralCap(address _collateral) → uint256 external`
-
-get cap amount for collateral asset
-
-#### Parameters:
-
-- `_collateral`: collateral asset address
-
-#### Return Values:
-
-- cap amount
-
### Function `getTimesToExpiry(address _underlying, address _strike, address _collateral, bool _isPut) → uint256[] external`
get times to expiry for a specific product
@@ -694,13 +666,13 @@ cash value = max(underlying price - strike price, 0)
- `_isPut`: option type, true for put and false for call option
-### Event `CollateralDustUpdated(address collateral, uint256 dust)`
+### Function `_getOtokenDetails(address _otoken) → address, address, address, uint256, uint256, bool internal`
-emits an event when collateral dust is updated
+get otoken detail, from both otoken versions
-### Event `CollateralCapUpdated(address collateral, uint256 cap)`
+### Event `CollateralDustUpdated(address collateral, uint256 dust)`
-emits an event when collateral cap is updated
+emits an event when collateral dust is updated
### Event `TimeToExpiryAdded(bytes32 productHash, uint256 timeToExpiry)`
diff --git a/docs/contracts-documentation/libs/Actions.md b/docs/contracts-documentation/libs/Actions.md
index a7471ebb7..d1782f086 100644
--- a/docs/contracts-documentation/libs/Actions.md
+++ b/docs/contracts-documentation/libs/Actions.md
@@ -2,6 +2,54 @@
A library that provides a ActionArgs struct, sub types of Action structs, and functions to parse ActionArgs into specific Actions.
+errorCode
+
+A1 can only parse arguments for open vault actions
+
+A2 cannot open vault for an invalid account
+
+A3 cannot open vault with an invalid type
+
+A4 can only parse arguments for mint actions
+
+A5 cannot mint from an invalid account
+
+A6 can only parse arguments for burn actions
+
+A7 cannot burn from an invalid account
+
+A8 can only parse arguments for deposit actions
+
+A9 cannot deposit to an invalid account
+
+A10 can only parse arguments for withdraw actions
+
+A11 cannot withdraw from an invalid account
+
+A12 cannot withdraw to an invalid account
+
+A13 can only parse arguments for redeem actions
+
+A14 cannot redeem to an invalid account
+
+A15 can only parse arguments for settle vault actions
+
+A16 cannot settle vault for an invalid account
+
+A17 cannot withdraw payout to an invalid account
+
+A18 can only parse arguments for liquidate action
+
+A19 cannot liquidate vault for an invalid account owner
+
+A20 cannot send collateral to an invalid account
+
+A21 cannot parse liquidate action with no round id
+
+A22 can only parse arguments for call actions
+
+A23 target address cannot be address(0)
+
## Functions:
- `_parseOpenVaultArgs(struct Actions.ActionArgs _args) (internal)`
diff --git a/docs/contracts-documentation/tests/OtokenImplV1.md b/docs/contracts-documentation/tests/OtokenImplV1.md
new file mode 100644
index 000000000..a5917194a
--- /dev/null
+++ b/docs/contracts-documentation/tests/OtokenImplV1.md
@@ -0,0 +1,25 @@
+# `OtokenImplV1`
+
+SPDX-License-Identifier: UNLICENSED
+
+The Otoken inherits ERC20PermitUpgradeable because we need to use the init instead of constructor
+
+This is V1 implementation, with no getOtokenDetails()
+
+## Functions:
+
+- `init(address _addressBook, address _underlyingAsset, address _strikeAsset, address _collateralAsset, uint256 _strikePrice, uint256 _expiryTimestamp, bool _isPut) (external)`
+
+- `mintOtoken(address _to, uint256 _amount) (external)`
+
+- `burnOtoken(address account, uint256 amount) (external)`
+
+- `getChainId() (external)`
+
+### Function `init(address _addressBook, address _underlyingAsset, address _strikeAsset, address _collateralAsset, uint256 _strikePrice, uint256 _expiryTimestamp, bool _isPut) external`
+
+### Function `mintOtoken(address _to, uint256 _amount) external`
+
+### Function `burnOtoken(address account, uint256 amount) external`
+
+### Function `getChainId() → uint256 chainId external`
diff --git a/docs/control-flow/Gamma.png b/docs/control-flow/Gamma.png
index 8c0a37f45..65c295c33 100644
Binary files a/docs/control-flow/Gamma.png and b/docs/control-flow/Gamma.png differ
diff --git a/docs/control-flow/GammaController.png b/docs/control-flow/GammaController.png
index 49407a418..1e1cf4280 100644
Binary files a/docs/control-flow/GammaController.png and b/docs/control-flow/GammaController.png differ
diff --git a/docs/control-flow/GammaHighLevel.png b/docs/control-flow/GammaHighLevel.png
index 15066cbe7..282d24048 100644
Binary files a/docs/control-flow/GammaHighLevel.png and b/docs/control-flow/GammaHighLevel.png differ
diff --git a/docs/uml/GammaAddressbook.png b/docs/uml/GammaAddressbook.png
index c1478f914..42c9d460d 100644
Binary files a/docs/uml/GammaAddressbook.png and b/docs/uml/GammaAddressbook.png differ
diff --git a/docs/uml/GammaAddressbook.svg b/docs/uml/GammaAddressbook.svg
index f520a40b4..322fdd69b 100644
--- a/docs/uml/GammaAddressbook.svg
+++ b/docs/uml/GammaAddressbook.svg
@@ -27,15 +27,15 @@
addresses: mapping(bytes32=>address)
External:
- setOtokenImpl(_otokenImpl: address)
- getOtokenImpl(): address
+ getOtokenImpl(): address
+ getOtokenFactory(): address
getWhitelist(): address
getController(): address
getMarginPool(): address
getMarginCalculator(): address
getLiquidationManager(): address
getOracle(): address
- getOtokenFactory(): address
+ setOtokenImpl(_otokenImpl: address)
setOtokenFactory(_otokenFactory: address)
setWhitelist(_whitelist: address)
setController(_controller: address)
diff --git a/docs/uml/GammaCalculator.png b/docs/uml/GammaCalculator.png
index 13e50854a..33a9e64db 100644
Binary files a/docs/uml/GammaCalculator.png and b/docs/uml/GammaCalculator.png differ
diff --git a/docs/uml/GammaCalculator.svg b/docs/uml/GammaCalculator.svg
index 843bb160c..7083818df 100644
--- a/docs/uml/GammaCalculator.svg
+++ b/docs/uml/GammaCalculator.svg
@@ -4,69 +4,66 @@
-