/* Copyright 2017-2019 Phillip A. Elsasser Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity 0.5.2; /// @title Math function library with overflow protection inspired by Open Zeppelin library MathLib { int256 constant INT256_MIN = int256((uint256(1) << 255)); int256 constant INT256_MAX = int256(~((uint256(1) << 255))); function multiply(uint256 a, uint256 b) pure internal returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "MathLib: multiplication overflow"); return c; } function divideFractional( uint256 a, uint256 numerator, uint256 denominator ) pure internal returns (uint256) { return multiply(a, numerator) / denominator; } function subtract(uint256 a, uint256 b) pure internal returns (uint256) { require(b <= a, "MathLib: subtraction overflow"); return a - b; } function add(uint256 a, uint256 b) pure internal returns (uint256) { uint256 c = a + b; require(c >= a, "MathLib: addition overflow"); return c; } /// @notice determines the amount of needed collateral for a given position (qty and price) /// @param priceFloor lowest price the contract is allowed to trade before expiration /// @param priceCap highest price the contract is allowed to trade before expiration /// @param qtyMultiplier multiplier for qty from base units /// @param longQty qty to redeem /// @param shortQty qty to redeem /// @param price of the trade function calculateCollateralToReturn( uint priceFloor, uint priceCap, uint qtyMultiplier, uint longQty, uint shortQty, uint price ) pure internal returns (uint) { uint neededCollateral = 0; uint maxLoss; if (longQty > 0) { // calculate max loss from entry price to floor if (price <= priceFloor) { maxLoss = 0; } else { maxLoss = subtract(price, priceFloor); } neededCollateral = multiply(multiply(maxLoss, longQty), qtyMultiplier); } if (shortQty > 0) { // calculate max loss from entry price to ceiling; if (price >= priceCap) { maxLoss = 0; } else { maxLoss = subtract(priceCap, price); } neededCollateral = add(neededCollateral, multiply(multiply(maxLoss, shortQty), qtyMultiplier)); } return neededCollateral; } /// @notice determines the amount of needed collateral for minting a long and short position token function calculateTotalCollateral( uint priceFloor, uint priceCap, uint qtyMultiplier ) pure internal returns (uint) { return multiply(subtract(priceCap, priceFloor), qtyMultiplier); } /// @notice calculates the fee in terms of base units of the collateral token per unit pair minted. function calculateFeePerUnit( uint priceFloor, uint priceCap, uint qtyMultiplier, uint feeInBasisPoints ) pure internal returns (uint) { uint midPrice = add(priceCap, priceFloor) / 2; return multiply(multiply(midPrice, qtyMultiplier), feeInBasisPoints) / 10000; } }