文件 1 的 1:InitializableProductProxy.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
abstract contract Proxy {
fallback () payable external {
_fallback();
}
receive () payable external {
_fallback();
}
function _implementation() virtual internal view returns (address);
function _delegate(address implementation) internal {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
function _willFallback() virtual internal {
}
function _fallback() internal {
if(OpenZeppelinUpgradesAddress.isContract(msg.sender) && msg.data.length == 0 && gasleft() <= 2300)
return;
_willFallback();
_delegate(_implementation());
}
}
abstract contract BaseUpgradeabilityProxy is Proxy {
event Upgraded(address indexed implementation);
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
function _implementation() override internal view returns (address impl) {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
impl := sload(slot)
}
}
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
function _setImplementation(address newImplementation) internal {
require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
}
contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
event AdminChanged(address previousAdmin, address newAdmin);
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
function admin() external ifAdmin returns (address) {
return _admin();
}
function implementation() external ifAdmin returns (address) {
return _implementation();
}
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
_upgradeTo(newImplementation);
(bool success,) = newImplementation.delegatecall(data);
require(success);
}
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
function _willFallback() virtual override internal {
require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
}
}
interface IAdminUpgradeabilityProxyView {
function admin() external view returns (address);
function implementation() external view returns (address);
}
abstract contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
constructor(address _logic, bytes memory _data) public payable {
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if(_data.length > 0) {
(bool success,) = _logic.delegatecall(_data);
require(success);
}
}
}
contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy {
constructor(address _admin, address _logic, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
_setAdmin(_admin);
}
function _willFallback() override(Proxy, BaseAdminUpgradeabilityProxy) internal {
super._willFallback();
}
}
abstract contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
function initialize(address _logic, bytes memory _data) public payable {
require(_implementation() == address(0));
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if(_data.length > 0) {
(bool success,) = _logic.delegatecall(_data);
require(success);
}
}
}
contract InitializableAdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, InitializableUpgradeabilityProxy {
function initialize(address _admin, address _logic, bytes memory _data) public payable {
require(_implementation() == address(0));
InitializableUpgradeabilityProxy.initialize(_logic, _data);
assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
_setAdmin(_admin);
}
function _willFallback() override(Proxy, BaseAdminUpgradeabilityProxy) internal {
super._willFallback();
}
}
interface IProxyFactory {
function productImplementation() external view returns (address);
function productImplementations(bytes32 name) external view returns (address);
}
contract ProductProxy is Proxy {
bytes32 internal constant FACTORY_SLOT = 0x7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af1;
bytes32 internal constant NAME_SLOT = 0x4cd9b827ca535ceb0880425d70eff88561ecdf04dc32fcf7ff3b15c587f8a870;
function _name() virtual internal view returns (bytes32 name_) {
bytes32 slot = NAME_SLOT;
assembly { name_ := sload(slot) }
}
function _setName(bytes32 name_) internal {
bytes32 slot = NAME_SLOT;
assembly { sstore(slot, name_) }
}
function _setFactory(address newFactory) internal {
require(OpenZeppelinUpgradesAddress.isContract(newFactory), "Cannot set a factory to a non-contract address");
bytes32 slot = FACTORY_SLOT;
assembly {
sstore(slot, newFactory)
}
}
function _factory() internal view returns (address factory_) {
bytes32 slot = FACTORY_SLOT;
assembly {
factory_ := sload(slot)
}
}
function _implementation() virtual override internal view returns (address) {
address factory_ = _factory();
if(OpenZeppelinUpgradesAddress.isContract(factory_))
return IProxyFactory(factory_).productImplementations(_name());
else
return address(0);
}
}
contract InitializableProductProxy is ProductProxy {
function __InitializableProductProxy_init(address factory_, bytes32 name_, bytes memory data_) public payable {
require(_factory() == address(0));
assert(FACTORY_SLOT == bytes32(uint256(keccak256('eip1967.proxy.factory')) - 1));
assert(NAME_SLOT == bytes32(uint256(keccak256('eip1967.proxy.name')) - 1));
_setFactory(factory_);
_setName(name_);
if(data_.length > 0) {
(bool success,) = _implementation().delegatecall(data_);
require(success);
}
}
}
contract Initializable {
bool private initialized;
bool private initializing;
modifier initializer() {
require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
initialized = true;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
function isConstructor() private view returns (bool) {
address self = address(this);
uint256 cs;
assembly { cs := extcodesize(self) }
return cs == 0;
}
uint256[50] private ______gap;
}
contract ContextUpgradeSafe is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
uint256[50] private __gap;
}
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function max_(int256 a, int256 b) internal pure returns (int256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function min_(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
function abs(int a) internal pure returns (uint) {
return a >= 0 ? uint(a) : uint(-a);
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function add(uint256 a, int256 b) internal pure returns (uint256 c) {
c = a + uint256(b);
require(b >= 0 && c >= a || b < 0 && c < a, "SafeMath: addition overflow");
}
function add_(int256 a, uint256 b) internal pure returns (int256 c) {
c = a + int256(b);
require(c >= a, "SafeMath: addition overflow");
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, int256 b) internal pure returns (uint256 c) {
c = a - uint256(b);
require(b >= 0 && c <= a || b < 0 && c > a, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function sub0(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : 0;
}
function sub_(uint256 a, uint256 b) internal pure returns (int256 c) {
c = int256(a - b);
require(a >= b && c >= 0 || a < b && c < 0, "SafeMath: sub_ overflow");
}
function sub_(int256 a, int256 b) internal pure returns (int256 c) {
c = a - b;
require(a >= b && c >= 0 || a < b && c < 0, "SafeMath: sub_ overflow");
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
library OpenZeppelinUpgradesAddress {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
}
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract ERC20UpgradeSafe is Initializable, ContextUpgradeSafe, IERC20 {
using SafeMath for uint256;
using Address for address;
mapping (address => uint256) internal _balances;
mapping (address => mapping (address => uint256)) internal _allowances;
uint256 internal _totalSupply;
string internal _name;
string internal _symbol;
uint8 internal _decimals;
function __ERC20_init(string memory name, string memory symbol) internal initializer {
__Context_init_unchained();
__ERC20_init_unchained(name, symbol);
}
function __ERC20_init_unchained(string memory name, string memory symbol) internal initializer {
_name = name;
_symbol = symbol;
_decimals = 18;
DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), _chainId(), address(this)));
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
if(sender != _msgSender() && _allowances[sender][_msgSender()] != uint(-1))
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
function _chainId() internal pure returns (uint id) {
assembly { id := chainid() }
}
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
bytes32 public DOMAIN_SEPARATOR;
mapping (address => uint) public nonces;
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, 'permit EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'permit INVALID_SIGNATURE');
_approve(owner, spender, value);
}
uint256[42] private __gap;
}
abstract contract ERC20CappedUpgradeSafe is Initializable, ERC20UpgradeSafe {
uint256 private _cap;
function __ERC20Capped_init(uint256 cap) internal initializer {
__Context_init_unchained();
__ERC20Capped_init_unchained(cap);
}
function __ERC20Capped_init_unchained(uint256 cap) internal initializer {
require(cap > 0, "ERC20Capped: cap is 0");
_cap = cap;
}
function cap() public view returns (uint256) {
return _cap;
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
if (from == address(0)) {
require(totalSupply().add(amount) <= _cap, "ERC20Capped: cap exceeded");
}
}
uint256[49] private __gap;
}
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), "SafeERC20: call to non-contract");
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
contract Governable is Initializable {
address public governor;
event GovernorshipTransferred(address indexed previousGovernor, address indexed newGovernor);
function __Governable_init_unchained(address governor_) virtual public initializer {
governor = governor_;
emit GovernorshipTransferred(address(0), governor);
}
modifier governance() {
require(msg.sender == governor);
_;
}
function renounceGovernorship() public governance {
emit GovernorshipTransferred(governor, address(0));
governor = address(0);
}
function transferGovernorship(address newGovernor) public governance {
_transferGovernorship(newGovernor);
}
function _transferGovernorship(address newGovernor) internal {
require(newGovernor != address(0));
emit GovernorshipTransferred(governor, newGovernor);
governor = newGovernor;
}
}
contract Configurable is Governable {
mapping (bytes32 => uint) internal config;
function getConfig(bytes32 key) public view returns (uint) {
return config[key];
}
function getConfigI(bytes32 key, uint index) public view returns (uint) {
return config[bytes32(uint(key) ^ index)];
}
function getConfigA(bytes32 key, address addr) public view returns (uint) {
return config[bytes32(uint(key) ^ uint(addr))];
}
function _setConfig(bytes32 key, uint value) internal {
if(config[key] != value)
config[key] = value;
}
function _setConfig(bytes32 key, uint index, uint value) internal {
_setConfig(bytes32(uint(key) ^ index), value);
}
function _setConfig(bytes32 key, address addr, uint value) internal {
_setConfig(bytes32(uint(key) ^ uint(addr)), value);
}
function setConfig(bytes32 key, uint value) external governance {
_setConfig(key, value);
}
function setConfigI(bytes32 key, uint index, uint value) external governance {
_setConfig(bytes32(uint(key) ^ index), value);
}
function setConfigA(bytes32 key, address addr, uint value) public governance {
_setConfig(bytes32(uint(key) ^ uint(addr)), value);
}
}
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}
contract Constants {
bytes32 internal constant _Call_ = 'Call';
bytes32 internal constant _Put_ = 'Put';
bytes32 internal constant _permissionless_ = 'permissionless';
bytes32 internal constant _feeTo_ = 'feeTo';
bytes32 internal constant _WETH_ = 'WETH';
uint256 internal constant MAX_FEE_RATE = 0.10 ether;
}
contract Factory is Configurable, ContextUpgradeSafe, Constants {
using SafeERC20 for IERC20;
using SafeMath for uint;
using SafeMath for int;
mapping(bytes32 => address) public productImplementations;
mapping(address => mapping(address => mapping(uint => mapping(uint => address)))) public calls;
mapping(address => mapping(address => mapping(uint => mapping(uint => address)))) public puts;
address[] public allCalls;
address[] public allPuts;
function length() public view returns (uint) {
return allCalls.length;
}
uint public feeRate;
function setFee(uint feeRate_, address feeTo) public governance {
require(feeRate_ <= MAX_FEE_RATE);
feeRate = feeRate_;
config[_feeTo_] = uint(feeTo);
}
function __Factory_init(address governor, address implCall, address implPut, address WETH, address feeTo) public initializer {
__Governable_init_unchained(governor);
__Factory_init_unchained(implCall, implPut, WETH, feeTo);
}
function __Factory_init_unchained(address implCall, address implPut, address WETH, address feeTo) public governance {
productImplementations[_Call_] = implCall;
productImplementations[_Put_] = implPut;
config[_WETH_] = uint(WETH);
setFee(0.005 ether, feeTo);
}
function upgradeProductImplementationsTo(address implCall, address implPut) external governance {
productImplementations[_Call_] = implCall;
productImplementations[_Put_] = implPut;
}
function createOption(address underlying, address currency, uint priceFloor, uint priceCap) public returns (address call_, address put) {
require(underlying != currency, 'IDENTICAL_ADDRESSES');
require(underlying != address(0) && currency != address(0), 'ZERO_ADDRESS');
require(priceFloor < priceCap, 'priceCap should biger than priceFloor');
require(config[_permissionless_] != 0 || _msgSender() == governor);
require(calls[underlying][currency][priceFloor][priceCap] == address(0), 'the Call/Put exist already');
bytes memory bytecode = type(InitializableProductProxy).creationCode;
bytes32 salt = keccak256(abi.encodePacked(_Call_, underlying, currency, priceFloor, priceCap));
assembly {
call_ := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
InitializableProductProxy(payable(call_)).__InitializableProductProxy_init(address(this), _Call_, abi.encodeWithSignature('__Call_init(address,address,uint256,uint256)', underlying, currency, priceFloor, priceCap));
salt = keccak256(abi.encodePacked(_Put_, underlying, currency, priceFloor, priceCap));
assembly {
put := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
InitializableProductProxy(payable(put)).__InitializableProductProxy_init(address(this), _Put_, abi.encodeWithSignature('__Put_init(address,address,uint256,uint256)', underlying, currency, priceFloor, priceCap));
calls[underlying][currency][priceFloor][priceCap] = call_;
puts [underlying][currency][priceFloor][priceCap] = put;
allCalls.push(call_);
allPuts.push(put);
emit CreateOption(_msgSender(), underlying, currency, priceFloor, priceCap, call_, put, allCalls.length);
}
event CreateOption(address indexed creator, address indexed underlying, address indexed currency, uint priceFloor, uint priceCap, address call, address put, uint count);
function _transfer(address payable sender, address callOrPut, address undOrCur, int vol) internal {
if(vol > 0) {
address from = sender;
uint fee = uint(vol).mul(feeRate).div(1e18);
if(msg.value > 0 && undOrCur == address(config[_WETH_])) {
uint deltaAndFee = uint(vol).add(fee);
require(msg.value >= deltaAndFee, 'msg.value not enough');
IWETH(config[_WETH_]).deposit{value: deltaAndFee}();
if(msg.value > deltaAndFee)
sender.transfer(msg.value - deltaAndFee);
from = address(this);
}
if(from == address(this)) {
IERC20(undOrCur).safeTransfer(callOrPut, uint(vol));
IERC20(undOrCur).safeTransfer(address(config[_feeTo_]), fee);
} else {
IERC20(undOrCur).safeTransferFrom(from, callOrPut, uint(vol));
IERC20(undOrCur).safeTransferFrom(from, address(config[_feeTo_]), fee);
}
} else if(vol < 0) {
uint fee = uint(-vol).mul(feeRate).div(1e18);
Call(callOrPut).withdraw_(address(config[_feeTo_]), fee);
address to = sender;
if(undOrCur == address(config[_WETH_]))
to = address(this);
uint v = uint(-vol).sub(fee);
Call(callOrPut).withdraw_(to, v);
if(to == address(this)) {
IWETH(config[_WETH_]).withdraw(v);
sender.transfer(v);
}
}
}
function _checkMistakeETH(address payable sender, address underlying, address currency, int dUnd, int dCur) internal {
address WETH = address(config[_WETH_]);
if(msg.value > 0 && ((underlying != WETH && currency != WETH) || (underlying == WETH && dUnd <= 0) || (currency == WETH && dCur <= 0)))
sender.transfer(msg.value);
}
function swap(address underlying, address currency, uint priceFloor, uint priceCap, int dCall, int dPut, int undMax, int curMax) public payable returns (address call, address put, int dUnd, int dCur) {
return _swap(_msgSender(), underlying, currency, priceFloor, priceCap, dCall, dPut, undMax, curMax);
}
function _swap(address payable sender, address underlying, address currency, uint priceFloor, uint priceCap, int dCall, int dPut, int undMax, int curMax) internal returns (address call, address put, int dUnd, int dCur) {
call = calls[underlying][currency][priceFloor][priceCap];
put = puts [underlying][currency][priceFloor][priceCap];
if(put == address(0))
(call, put) = createOption(underlying, currency, priceFloor, priceCap);
(dUnd, dCur, priceFloor, priceCap) = calcDelta(priceFloor, priceCap, Call(call).totalSupply(), Put(put).totalSupply(), dCall, dPut);
require(SafeMath.add_(dUnd, Math.abs(dUnd).mul(feeRate).div(1e18)) <= undMax && SafeMath.add_(dCur, Math.abs(dCur).mul(feeRate).div(1e18)) <= curMax, 'slippage too high');
_transfer(sender, call, underlying, dUnd);
_transfer(sender, put, currency, dCur);
_checkMistakeETH(sender, underlying, currency, dUnd, dCur);
if(dCall > 0)
Call(call).mint_(sender, uint(dCall));
else if(dCall < 0)
Call(call).burn_(sender, uint(-dCall));
if(dPut > 0)
Put(put).mint_(sender, uint(dPut));
else if(dPut < 0)
Put(put).burn_(sender, uint(-dPut));
require(IERC20(underlying).balanceOf(call) >= priceFloor && IERC20(currency).balanceOf(put) >= priceCap, 'reserve less than expected');
emit Swap(sender, underlying, currency, Call(call).priceFloor(), Call(call).priceCap(), call, put, dCall, dPut, dUnd, dCur);
}
event Swap(address indexed sender, address indexed underlying, address indexed currency, uint priceFloor, uint priceCap, address call, address put, int dCall, int dPut, int dUnd, int dCur);
function _swap2(address undFrom, address curFrom, address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int volPut, int undMax, int curMax) internal returns (address call, address put, int dUnd, int dCur) {
call = calls[underlying][currency][priceFloor][priceCap];
put = puts [underlying][currency][priceFloor][priceCap];
if(volCall < 0)
Call(call).transferFrom(undFrom, address(this), uint(-volCall));
if(volPut < 0)
Put (put ).transferFrom(curFrom, address(this), uint(-volPut));
if(undMax > 0)
IERC20(underlying).safeTransferFrom(undFrom, address(this), uint(undMax));
if(curMax > 0)
IERC20(currency ).safeTransferFrom(curFrom, address(this), uint(curMax));
(call, put, dUnd, dCur) = _swap(address(uint160(address(this))), underlying, currency, priceFloor, priceCap, volCall, volPut, undMax, curMax);
if(Math.max_(0, undMax) > dUnd)
IERC20(underlying).safeTransfer(undFrom, uint(Math.max_(0, undMax).sub_(dUnd)));
if(Math.max_(0, curMax) > dCur)
IERC20(currency ).safeTransfer(curFrom, uint(Math.max_(0, curMax).sub_(dCur)));
if(volCall > 0)
Call(call).transfer(undFrom, uint(volCall));
if(volPut > 0)
Put (put ).transfer(curFrom, uint(volPut));
}
function swap2_(address undFrom, address curFrom, address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int volPut, int undMax, int curMax) external governance returns (address call, address put, int dUnd, int dCur) {
uint oldFeeRate = feeRate;
feeRate = 0;
(call, put, dUnd, dCur) = _swap2(undFrom, curFrom, underlying, currency, priceFloor, priceCap, volCall, volPut, undMax, curMax);
feeRate = oldFeeRate;
}
function mint4(address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int volPut, int undMax, int curMax) public payable returns (address call, address put, int dUnd, int dCur) {
return swap(underlying, currency, priceFloor, priceCap, volCall, volPut, undMax, curMax);
}
function mint(address callOrPut, int volCall, int volPut, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Call(callOrPut).attributes();
(, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, volCall, volPut, undMax, curMax);
}
function mintCall4(address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int undMax, int curMax) public payable returns (address call, int dUnd, int dCur) {
(call, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, volCall, 0, undMax, curMax);
}
function mintCall(address call, int volCall, int undMax, int curMax) public payable returns (int dUnd, int dCur) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Call(call).attributes();
(, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, volCall, 0, undMax, curMax);
}
function mintCall_(address payable sender, address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int undMax, int curMax) public payable returns (int dUnd, int dCur) {
require(msg.sender == calls[underlying][currency][priceFloor][priceCap], 'Only Call');
(, , dUnd, dCur) = _swap(sender, underlying, currency, priceFloor, priceCap, volCall, 0, undMax, curMax);
}
function mintPut4(address underlying, address currency, uint priceFloor, uint priceCap, int volPut, int undMax, int curMax) public payable returns (address put, int dUnd, int dCur) {
(, put, dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, 0, volPut, undMax, curMax);
}
function mintPut(address put, int volPut, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Put(put).attributes();
(, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, 0, volPut, undMax, curMax);
}
function mintPut_(address payable sender, address underlying, address currency, uint priceFloor, uint priceCap, int volPut, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
require(msg.sender == puts[underlying][currency][priceFloor][priceCap], 'Only Put');
(, , dUnd, dCur) = _swap(sender, underlying, currency, priceFloor, priceCap, 0, volPut, undMax, curMax);
}
function burn4(address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int volPut, int undMax, int curMax) public payable returns (address call, address put, int dUnd, int dCur) {
return swap(underlying, currency, priceFloor, priceCap, volCall, volPut, undMax, curMax);
}
function burn(address callOrPut, int volCall, int volPut, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Call(callOrPut).attributes();
(, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, volCall, volPut, undMax, curMax);
}
function burnCall4(address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int undMax, int curMax) public payable returns (address call, int dUnd, int dCur) {
(call, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, volCall, 0, undMax, curMax);
}
function burnCall(address call, int volCall, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Call(call).attributes();
(, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, volCall, undMax, curMax, curMax);
}
function burnCall_(address payable sender, address underlying, address currency, uint priceFloor, uint priceCap, int volCall, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
require(msg.sender == calls[underlying][currency][priceFloor][priceCap], 'Only Call');
(, , dUnd, dCur) = _swap(sender, underlying, currency, priceFloor, priceCap, volCall, undMax, curMax, curMax);
}
function burnPut4(address underlying, address currency, uint priceFloor, uint priceCap, int volPut, int undMax, int curMax) public payable returns (address put, int dUnd, int dCur) {
(, put, dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, 0, volPut, undMax, curMax);
}
function burnPut(address put, int volPut, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Put(put).attributes();
(, , dUnd, dCur) = swap(underlying, currency, priceFloor, priceCap, 0, volPut, undMax, curMax);
}
function burnPut_(address payable sender, address underlying, address currency, uint priceFloor, uint priceCap, int volPut, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
require(msg.sender == puts[underlying][currency][priceFloor][priceCap], 'Only Put');
(, , dUnd, dCur) = _swap(sender, underlying, currency, priceFloor, priceCap, 0, volPut, undMax, curMax);
}
function calc(uint priceFloor, uint priceCap, uint totalCall, uint totalPut) public pure returns (uint totalUnd, uint totalCur) {
if(totalCall == 0 && totalPut == 0)
return (0, 0);
uint temp = totalCall.mul(totalPut).div(totalCall.add(totalPut)).mul(priceCap.sub(priceFloor)).div(1e18).mul(2);
totalUnd = temp.mul(totalCall).div(totalCall.mul(priceFloor).add(totalPut.mul(priceCap)).div(1e18));
totalCur = temp.mul(totalPut).div(totalCall.add(totalPut));
}
function calcDelta(uint priceFloor, uint priceCap, uint totalCall, uint totalPut, int dCall, int dPut) public pure returns (int dUnd, int dCur, uint totalUnd, uint totalCur) {
(uint oldUnd, uint oldCur) = calc(priceFloor, priceCap, totalCall, totalPut);
(totalUnd, totalCur) = calc(priceFloor, priceCap, totalCall.add(dCall), totalPut.add(dPut));
dUnd = totalUnd.sub_(oldUnd);
dCur = totalCur.sub_(oldCur);
}
function calcDeltaWithFeeAndSlippage(uint priceFloor, uint priceCap, uint totalCall, uint totalPut, int dCall, int dPut, uint slippage) public view returns (int undMax, int curMax, uint totalUnd, uint totalCur) {
(undMax, curMax, totalUnd, totalCur) = calcDelta(priceFloor, priceCap, totalCall, totalPut, dCall, dPut);
undMax = SafeMath.add_(undMax, Math.abs(undMax).mul(feeRate.add(slippage)).div(1e18));
curMax = SafeMath.add_(curMax, Math.abs(curMax).mul(feeRate.add(slippage)).div(1e18));
}
function priceValue(uint priceFloor, uint priceCap, uint totalCall, uint totalPut) public pure returns (uint priceUnderlying, uint valueReserve) {
priceUnderlying = (priceFloor.mul(totalCall).add(priceCap.mul(totalPut))).div(totalCall.add(totalPut));
valueReserve = priceUnderlying.sub(priceFloor).mul(totalCall).add(priceCap.sub(priceUnderlying).mul(totalPut)).div(1e18);
}
function priceValue4(address underlying, address currency, uint priceFloor, uint priceCap) public view returns (uint priceUnderlying, uint valueReserve) {
address call = calls[underlying][currency][priceFloor][priceCap];
address put = puts [underlying][currency][priceFloor][priceCap];
if(put == address(0))
return (0, 0);
return priceValue(priceFloor, priceCap, Call(call).totalSupply(), Put(put).totalSupply());
}
function priceValue1(address callOrPut) public view returns (uint priceUnderlying, uint valueReserve) {
(address underlying, address currency, uint priceFloor, uint priceCap) = Call(callOrPut).attributes();
return priceValue4(underlying, currency, priceFloor, priceCap);
}
function priceTo18(uint _price, uint8 underlyingDecimals, uint8 currencyDecimals) public pure returns (uint) {
return _price.mul(10 ** uint256(underlyingDecimals)).div(10 ** uint256(currencyDecimals));
}
function priceTo18a(uint _price, address underlying, address currency) public view returns (uint) {
return priceTo18(_price, ERC20UpgradeSafe(underlying).decimals(), ERC20UpgradeSafe(currency).decimals());
}
function priceFrom18(uint price18, uint8 underlyingDecimals, uint8 currencyDecimals) public pure returns (uint) {
return price18.mul(10 ** uint256(currencyDecimals)).div(10 ** uint256(underlyingDecimals));
}
function priceFrom18a(uint price18, address underlying, address currency) public view returns (uint) {
return priceFrom18(price18, ERC20UpgradeSafe(underlying).decimals(), ERC20UpgradeSafe(currency).decimals());
}
}
contract Call is ERC20UpgradeSafe {
using SafeERC20 for IERC20;
using SafeMath for uint;
address public factory;
address public underlying;
address public currency;
uint public priceFloor;
uint public priceCap;
function __Call_init(address _underlying, address _currency, uint _priceFloor, uint _priceCap) external initializer {
(string memory name, string memory symbol) = spellNameAndSymbol(_underlying, _currency, _priceFloor, _priceCap);
__ERC20_init(name, symbol);
_setupDecimals(ERC20UpgradeSafe(_underlying).decimals());
factory = _msgSender();
underlying = _underlying;
currency = _currency;
priceFloor = _priceFloor;
priceCap = _priceCap;
}
function spellNameAndSymbol(address _underlying, address _currency, uint _priceFloor, uint _priceCap) public view returns (string memory name, string memory symbol) {
return('AntiMatter.Finance Perpetual Call Token', 'Call');
}
function setNameAndSymbol(string memory name, string memory symbol) external {
require(_msgSender() == Factory(factory).governor());
_name = name;
_symbol = symbol;
}
modifier onlyFactory {
require(_msgSender() == factory, 'Only Factory');
_;
}
function withdraw_(address to, uint volume) external onlyFactory {
IERC20(underlying).safeTransfer(to, volume);
}
function mint_(address _to, uint volume) external onlyFactory {
_mint(_to, volume);
}
function burn_(address _from, uint volume) external onlyFactory {
_burn(_from, volume);
}
function mint(int volume, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
return Factory(factory).mintCall_{value: msg.value}(_msgSender(), underlying, currency, priceFloor, priceCap, volume, undMax, curMax);
}
function burn(int volume, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
return Factory(factory).burnCall_{value: msg.value}(_msgSender(), underlying, currency, priceFloor, priceCap, volume, undMax, curMax);
}
function burnAll(int undMax, int curMax) external payable returns (int dUnd, int dCur) {
return Factory(factory).burnCall_{value: msg.value}(_msgSender(), underlying, currency, priceFloor, priceCap, int(balanceOf(_msgSender())), undMax, curMax);
}
function attributes() public view returns (address _underlying, address _currency, uint _priceFloor, uint _priceCap) {
return (underlying, currency, priceFloor, priceCap);
}
function priceValue() public view returns (uint priceUnderlying, uint valueReserve) {
return Factory(factory).priceValue1(address(this));
}
}
contract Put is ERC20UpgradeSafe, Constants {
using SafeERC20 for IERC20;
using SafeMath for uint;
address public factory;
address public underlying;
address public currency;
uint public priceFloor;
uint public priceCap;
function __Put_init(address _underlying, address _currency, uint _priceFloor, uint _priceCap) external initializer {
(string memory name, string memory symbol) = spellNameAndSymbol(_underlying, _currency, _priceFloor, _priceCap);
__ERC20_init(name, symbol);
_setupDecimals(ERC20UpgradeSafe(_underlying).decimals());
factory = _msgSender();
underlying = _underlying;
currency = _currency;
priceFloor = _priceFloor;
priceCap = _priceCap;
}
function spellNameAndSymbol(address _underlying, address _currency, uint _priceFloor, uint _priceCap) public view returns (string memory name, string memory symbol) {
return('AntiMatter.Finance Perpetual Put Token', 'Put');
}
function setNameAndSymbol(string memory name, string memory symbol) external {
require(_msgSender() == Factory(factory).governor());
_name = name;
_symbol = symbol;
}
modifier onlyFactory {
require(_msgSender() == factory, 'Only Factory');
_;
}
function withdraw_(address to, uint volume) external onlyFactory {
IERC20(currency).safeTransfer(to, volume);
}
function mint_(address _to, uint volume) external onlyFactory {
_mint(_to, volume);
}
function burn_(address _from, uint volume) external onlyFactory {
_burn(_from, volume);
}
function mint(int volume, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
return Factory(factory).mintPut_{value: msg.value}(_msgSender(), underlying, currency, priceFloor, priceCap, volume, undMax, curMax);
}
function burn(int volume, int undMax, int curMax) external payable returns (int dUnd, int dCur) {
return Factory(factory).burnPut_{value: msg.value}(_msgSender(), underlying, currency, priceFloor, priceCap, volume, undMax, curMax);
}
function burnAll(int undMax, int curMax) external payable returns (int dUnd, int dCur) {
return Factory(factory).burnPut_{value: msg.value}(_msgSender(), underlying, currency, priceFloor, priceCap, int(balanceOf(_msgSender())), undMax, curMax);
}
function attributes() public view returns (address _underlying, address _currency, uint _priceFloor, uint _priceCap) {
return (underlying, currency, priceFloor, priceCap);
}
function priceValue() public view returns (uint priceUnderlying, uint valueReserve) {
return Factory(factory).priceValue1(address(this));
}
}