Skip to content

Commit

Permalink
Reduce Controller bytecode size (#433)
Browse files Browse the repository at this point in the history
* feat: getVaultWithDetails()

* remove leading 0s

* adjust return in hasExpired

* adjust return in getPayout

* adjust private interfaces

* remove duplicate partial and full pauser addresses

* interfaces back to public, marginVault error codes

* action error strings

* try catch

* avoid changing slot

* test: fix pauser tests

* overload isSettlementAllowed

* add getOTokenDetails in calculator

* refactor isSettlementAllowed

* fix action tests

* fix controller tests

* fix: setPauser

* fix: MarginVault error code

* fix: integration test error codes

* revert partial and full pauser change

* test: fix

* change functions visibility and update order

* test: use getVault() in controller.test.ts

* fix: backward compatibility for redeeming

* test: backward compatibility'

* chore: rename _getOTokenDetail()

* docs: update docs & diagrams

* fix: typo

Co-authored-by: Haythem Sellami <sellamihaythem96@gmail.com>
Co-authored-by: Anton Cheng <antonassocareer@gmail.com>
Co-authored-by: CruzMolina <7537712+CruzMolina@users.noreply.github.com>
  • Loading branch information
4 people authored Jun 24, 2021
1 parent 758191c commit 67a2bff
Show file tree
Hide file tree
Showing 51 changed files with 1,553 additions and 1,162 deletions.
300 changes: 178 additions & 122 deletions contracts/core/Controller.sol

Large diffs are not rendered by default.

46 changes: 41 additions & 5 deletions contracts/core/MarginCalculator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -364,16 +364,14 @@ 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,
address strikeAsset,
uint256 strikePrice,
uint256 expiry,
bool isPut
) = otoken.getOtokenDetails();
) = _getOtokenDetails(_otoken);

require(now >= expiry, "MarginCalculator: Otoken not expired yet");

Expand Down Expand Up @@ -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());
}

Expand All @@ -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()
);
Expand Down Expand Up @@ -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()
);
}
}
}
73 changes: 47 additions & 26 deletions contracts/libs/Actions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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});
}
Expand All @@ -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({
Expand All @@ -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({
Expand All @@ -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({
Expand All @@ -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({
Expand All @@ -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});
}
Expand All @@ -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));
Expand All @@ -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});
}
Expand Down
61 changes: 28 additions & 33 deletions contracts/libs/MarginVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -47,23 +60,17 @@ 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
if ((_index == _vault.shortOtokens.length) && (_index == _vault.shortAmounts.length)) {
_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;
Expand All @@ -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);

Expand All @@ -108,23 +115,17 @@ 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
if ((_index == _vault.longOtokens.length) && (_index == _vault.longAmounts.length)) {
_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;
Expand All @@ -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);

Expand All @@ -169,23 +170,17 @@ 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
if ((_index == _vault.collateralAssets.length) && (_index == _vault.collateralAmounts.length)) {
_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;
Expand All @@ -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);

Expand Down
Loading

0 comments on commit 67a2bff

Please sign in to comment.