Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 9 from a total of 9 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Approve | 12967241 | 1665 days ago | IN | 0 ETH | 0.00147787 | ||||
| Approve | 12958146 | 1666 days ago | IN | 0 ETH | 0.00122715 | ||||
| Approve | 12956021 | 1667 days ago | IN | 0 ETH | 0.00132532 | ||||
| Approve | 12955797 | 1667 days ago | IN | 0 ETH | 0.0013744 | ||||
| Approve | 12949117 | 1668 days ago | IN | 0 ETH | 0.00161983 | ||||
| Approve | 12946273 | 1668 days ago | IN | 0 ETH | 0.00163021 | ||||
| Approve | 12923380 | 1672 days ago | IN | 0 ETH | 0.00122715 | ||||
| Approve | 12915838 | 1673 days ago | IN | 0 ETH | 0.00147258 | ||||
| Approve | 12914804 | 1673 days ago | IN | 0 ETH | 0.00142349 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| - | 12914773 | 1673 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0x6a8ac20846220c51000ca36ca689015fec1a1866
Contract Name:
BinaryOptionMastercopy
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.5.16;
// Internal references
import "./BinaryOption.sol";
contract BinaryOptionMastercopy is BinaryOption {
constructor() public {
// Freeze mastercopy on deployment so it can never be initialized with real arguments
initialized = true;
}
}pragma solidity ^0.5.16;
// Inheritance
import "synthetix-2.43.1/contracts/interfaces/IERC20.sol";
import "./interfaces/IBinaryOption.sol";
// Libraries
import "synthetix-2.43.1/contracts/SafeDecimalMath.sol";
// Internal references
import "./BinaryOptionMarket.sol";
contract BinaryOption is IERC20, IBinaryOption {
/* ========== LIBRARIES ========== */
using SafeMath for uint;
using SafeDecimalMath for uint;
/* ========== STATE VARIABLES ========== */
string public name;
string public symbol;
uint8 public constant decimals = 18;
BinaryOptionMarket public market;
mapping(address => uint) public balanceOf;
uint public totalSupply;
// The argument order is allowance[owner][spender]
mapping(address => mapping(address => uint)) public allowance;
// Enforce a 1 cent minimum amount
uint internal constant _MINIMUM_AMOUNT = 1e16;
/* ========== CONSTRUCTOR ========== */
bool public initialized = false;
function initialize(
string calldata _name,
string calldata _symbol
) external {
require(!initialized, "Binary Option Market already initialized");
initialized = true;
name = _name;
symbol = _symbol;
market = BinaryOptionMarket(msg.sender);
}
/* ========== MUTATIVE FUNCTIONS ========== */
function _requireMinimumAmount(uint amount) internal pure returns (uint) {
require(amount >= _MINIMUM_AMOUNT || amount == 0, "Balance < $0.01");
return amount;
}
function mint(address minter, uint amount) external onlyMarket {
_requireMinimumAmount(amount);
totalSupply = totalSupply.add(amount);
balanceOf[minter] = balanceOf[minter].add(amount); // Increment rather than assigning since a transfer may have occurred.
emit Transfer(address(0), minter, amount);
emit Issued(minter, amount);
}
// This must only be invoked after maturity.
function exercise(address claimant) external onlyMarket {
uint balance = balanceOf[claimant];
if (balance == 0) {
return;
}
balanceOf[claimant] = 0;
totalSupply = totalSupply.sub(balance);
emit Transfer(claimant, address(0), balance);
emit Burned(claimant, balance);
}
// This must only be invoked after the exercise window is complete.
// Note that any options which have not been exercised will linger.
function expire(address payable beneficiary) external onlyMarket {
selfdestruct(beneficiary);
}
/* ---------- ERC20 Functions ---------- */
function _transfer(
address _from,
address _to,
uint _value
) internal returns (bool success) {
market.requireUnpaused();
require(_to != address(0) && _to != address(this), "Invalid address");
uint fromBalance = balanceOf[_from];
require(_value <= fromBalance, "Insufficient balance");
balanceOf[_from] = fromBalance.sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(_from, _to, _value);
return true;
}
function transfer(address _to, uint _value) external returns (bool success) {
return _transfer(msg.sender, _to, _value);
}
function transferFrom(
address _from,
address _to,
uint _value
) external returns (bool success) {
uint fromAllowance = allowance[_from][msg.sender];
require(_value <= fromAllowance, "Insufficient allowance");
allowance[_from][msg.sender] = fromAllowance.sub(_value);
return _transfer(_from, _to, _value);
}
function approve(address _spender, uint _value) external returns (bool success) {
require(_spender != address(0));
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/* ========== MODIFIERS ========== */
modifier onlyMarket() {
require(msg.sender == address(market), "Only market allowed");
_;
}
/* ========== EVENTS ========== */
event Issued(address indexed account, uint value);
event Burned(address indexed account, uint value);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}pragma solidity >=0.4.24;
// https://docs.synthetix.io/contracts/source/interfaces/ierc20
interface IERC20 {
// ERC20 Optional Views
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
// Views
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
// Mutative functions
function transfer(address to, uint value) external returns (bool);
function approve(address spender, uint value) external returns (bool);
function transferFrom(
address from,
address to,
uint value
) external returns (bool);
// Events
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}pragma solidity >=0.4.24;
import "../interfaces/IBinaryOptionMarket.sol";
import "synthetix-2.43.1/contracts/interfaces/IERC20.sol";
interface IBinaryOption {
/* ========== VIEWS / VARIABLES ========== */
function market() external view returns (IBinaryOptionMarket);
function balanceOf(address account) external view returns (uint);
function totalSupply() external view returns (uint);
}pragma solidity ^0.5.16;
// Libraries
import "openzeppelin-solidity-2.3.0/contracts/math/SafeMath.sol";
// https://docs.synthetix.io/contracts/source/libraries/safedecimalmath
library SafeDecimalMath {
using SafeMath for uint;
/* Number of decimal places in the representations. */
uint8 public constant decimals = 18;
uint8 public constant highPrecisionDecimals = 27;
/* The number representing 1.0. */
uint public constant UNIT = 10**uint(decimals);
/* The number representing 1.0 for higher fidelity numbers. */
uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals);
uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals);
/**
* @return Provides an interface to UNIT.
*/
function unit() external pure returns (uint) {
return UNIT;
}
/**
* @return Provides an interface to PRECISE_UNIT.
*/
function preciseUnit() external pure returns (uint) {
return PRECISE_UNIT;
}
/**
* @return The result of multiplying x and y, interpreting the operands as fixed-point
* decimals.
*
* @dev A unit factor is divided out after the product of x and y is evaluated,
* so that product must be less than 2**256. As this is an integer division,
* the internal division always rounds down. This helps save on gas. Rounding
* is more expensive on gas.
*/
function multiplyDecimal(uint x, uint y) internal pure returns (uint) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
return x.mul(y) / UNIT;
}
/**
* @return The result of safely multiplying x and y, interpreting the operands
* as fixed-point decimals of the specified precision unit.
*
* @dev The operands should be in the form of a the specified unit factor which will be
* divided out after the product of x and y is evaluated, so that product must be
* less than 2**256.
*
* Unlike multiplyDecimal, this function rounds the result to the nearest increment.
* Rounding is useful when you need to retain fidelity for small decimal numbers
* (eg. small fractions or percentages).
*/
function _multiplyDecimalRound(
uint x,
uint y,
uint precisionUnit
) private pure returns (uint) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
uint quotientTimesTen = x.mul(y) / (precisionUnit / 10);
if (quotientTimesTen % 10 >= 5) {
quotientTimesTen += 10;
}
return quotientTimesTen / 10;
}
/**
* @return The result of safely multiplying x and y, interpreting the operands
* as fixed-point decimals of a precise unit.
*
* @dev The operands should be in the precise unit factor which will be
* divided out after the product of x and y is evaluated, so that product must be
* less than 2**256.
*
* Unlike multiplyDecimal, this function rounds the result to the nearest increment.
* Rounding is useful when you need to retain fidelity for small decimal numbers
* (eg. small fractions or percentages).
*/
function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
return _multiplyDecimalRound(x, y, PRECISE_UNIT);
}
/**
* @return The result of safely multiplying x and y, interpreting the operands
* as fixed-point decimals of a standard unit.
*
* @dev The operands should be in the standard unit factor which will be
* divided out after the product of x and y is evaluated, so that product must be
* less than 2**256.
*
* Unlike multiplyDecimal, this function rounds the result to the nearest increment.
* Rounding is useful when you need to retain fidelity for small decimal numbers
* (eg. small fractions or percentages).
*/
function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) {
return _multiplyDecimalRound(x, y, UNIT);
}
/**
* @return The result of safely dividing x and y. The return value is a high
* precision decimal.
*
* @dev y is divided after the product of x and the standard precision unit
* is evaluated, so the product of x and UNIT must be less than 2**256. As
* this is an integer division, the result is always rounded down.
* This helps save on gas. Rounding is more expensive on gas.
*/
function divideDecimal(uint x, uint y) internal pure returns (uint) {
/* Reintroduce the UNIT factor that will be divided out by y. */
return x.mul(UNIT).div(y);
}
/**
* @return The result of safely dividing x and y. The return value is as a rounded
* decimal in the precision unit specified in the parameter.
*
* @dev y is divided after the product of x and the specified precision unit
* is evaluated, so the product of x and the specified precision unit must
* be less than 2**256. The result is rounded to the nearest increment.
*/
function _divideDecimalRound(
uint x,
uint y,
uint precisionUnit
) private pure returns (uint) {
uint resultTimesTen = x.mul(precisionUnit * 10).div(y);
if (resultTimesTen % 10 >= 5) {
resultTimesTen += 10;
}
return resultTimesTen / 10;
}
/**
* @return The result of safely dividing x and y. The return value is as a rounded
* standard precision decimal.
*
* @dev y is divided after the product of x and the standard precision unit
* is evaluated, so the product of x and the standard precision unit must
* be less than 2**256. The result is rounded to the nearest increment.
*/
function divideDecimalRound(uint x, uint y) internal pure returns (uint) {
return _divideDecimalRound(x, y, UNIT);
}
/**
* @return The result of safely dividing x and y. The return value is as a rounded
* high precision decimal.
*
* @dev y is divided after the product of x and the high precision unit
* is evaluated, so the product of x and the high precision unit must
* be less than 2**256. The result is rounded to the nearest increment.
*/
function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
return _divideDecimalRound(x, y, PRECISE_UNIT);
}
/**
* @dev Convert a standard decimal representation to a high precision one.
*/
function decimalToPreciseDecimal(uint i) internal pure returns (uint) {
return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
}
/**
* @dev Convert a high precision decimal to a standard decimal representation.
*/
function preciseDecimalToDecimal(uint i) internal pure returns (uint) {
uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10);
if (quotientTimesTen % 10 >= 5) {
quotientTimesTen += 10;
}
return quotientTimesTen / 10;
}
}pragma solidity ^0.5.16;
// Inheritance
import "synthetix-2.43.1/contracts/MinimalProxyFactory.sol";
import "./OwnedWithInit.sol";
import "./interfaces/IBinaryOptionMarket.sol";
import "./interfaces/IOracleInstance.sol";
// Libraries
import "synthetix-2.43.1/contracts/SafeDecimalMath.sol";
// Internal references
import "./BinaryOptionMarketManager.sol";
import "./BinaryOption.sol";
import "synthetix-2.43.1/contracts/interfaces/IExchangeRates.sol";
import "synthetix-2.43.1/contracts/interfaces/IERC20.sol";
import "synthetix-2.43.1/contracts/interfaces/IAddressResolver.sol";
contract BinaryOptionMarket is MinimalProxyFactory, OwnedWithInit, IBinaryOptionMarket {
/* ========== LIBRARIES ========== */
using SafeMath for uint;
using SafeDecimalMath for uint;
/* ========== TYPES ========== */
struct Options {
BinaryOption long;
BinaryOption short;
}
struct Times {
uint maturity;
uint expiry;
}
struct OracleDetails {
bytes32 key;
uint strikePrice;
uint finalPrice;
bool customMarket;
address iOracleInstanceAddress;
}
/* ========== STATE VARIABLES ========== */
Options public options;
Times public times;
OracleDetails public oracleDetails;
BinaryOptionMarketManager.Fees public fees;
IAddressResolver public resolver;
IOracleInstance public iOracleInstance;
bool public customMarket;
// `deposited` tracks the sum of all deposits minus the withheld fees.
// This must explicitly be kept, in case tokens are transferred to the contract directly.
uint public deposited;
uint public accumulatedFees;
uint public initialMint;
address public creator;
bool public resolved;
uint internal _feeMultiplier;
/* ---------- Address Resolver Configuration ---------- */
bytes32 internal constant CONTRACT_EXRATES = "ExchangeRates";
bytes32 internal constant CONTRACT_SYNTHSUSD = "SynthsUSD";
/* ========== CONSTRUCTOR ========== */
bool public initialized = false;
function initialize(
address _owner,
address _binaryOptionMastercopy,
IAddressResolver _resolver,
address _creator,
bytes32 _oracleKey,
uint _strikePrice,
uint[2] calldata _times, // [maturity, expiry]
uint _deposit, // sUSD deposit
uint[2] calldata _fees, // [poolFee, creatorFee]
bool _customMarket,
address _iOracleInstanceAddress
) external {
require(!initialized, "Binary Option Market already initialized");
initialized = true;
initOwner(_owner);
resolver = _resolver;
creator = _creator;
oracleDetails = OracleDetails(_oracleKey, _strikePrice, 0, _customMarket, _iOracleInstanceAddress);
customMarket = _customMarket;
iOracleInstance = IOracleInstance(_iOracleInstanceAddress);
times = Times(_times[0], _times[1]);
deposited = _deposit;
initialMint = _deposit;
(uint poolFee, uint creatorFee) = (_fees[0], _fees[1]);
fees = BinaryOptionMarketManager.Fees(poolFee, creatorFee);
_feeMultiplier = SafeDecimalMath.unit().sub(poolFee.add(creatorFee));
// Instantiate the options themselves
options.long = BinaryOption(_cloneAsMinimalProxy(_binaryOptionMastercopy, "Could not create a Binary Option"));
options.short = BinaryOption(_cloneAsMinimalProxy(_binaryOptionMastercopy, "Could not create a Binary Option"));
// abi.encodePacked("sLONG: ", _oracleKey)
// consider naming the option: sLongBTC>50@2021.12.31
options.long.initialize("Binary Option Long", "sLONG");
options.short.initialize("Binary Option Short", "sSHORT");
_mint(creator, initialMint);
// Note: the ERC20 base contract does not have a constructor, so we do not have to worry
// about initializing its state separately
}
/* ---------- External Contracts ---------- */
function _exchangeRates() internal view returns (IExchangeRates) {
return IExchangeRates(resolver.requireAndGetAddress(CONTRACT_EXRATES, "ExchangeRates contract not found"));
}
function _sUSD() internal view returns (IERC20) {
return IERC20(resolver.requireAndGetAddress(CONTRACT_SYNTHSUSD, "SynthsUSD contract not found"));
}
function _manager() internal view returns (BinaryOptionMarketManager) {
return BinaryOptionMarketManager(owner);
}
/* ---------- Phases ---------- */
function _matured() internal view returns (bool) {
return times.maturity < block.timestamp;
}
function _expired() internal view returns (bool) {
return resolved && (times.expiry < block.timestamp || deposited == 0);
}
function phase() external view returns (Phase) {
if (!_matured()) {
return Phase.Trading;
}
if (!_expired()) {
return Phase.Maturity;
}
return Phase.Expiry;
}
/* ---------- Market Resolution ---------- */
function _oraclePriceAndTimestamp() internal view returns (uint price, uint updatedAt) {
return _exchangeRates().rateAndUpdatedTime(oracleDetails.key);
}
function oraclePriceAndTimestamp() external view returns (uint price, uint updatedAt) {
return _oraclePriceAndTimestamp();
}
function _isFreshPriceUpdateTime(uint timestamp) internal view returns (bool) {
(uint maxOraclePriceAge, , ) = _manager().durations();
return (times.maturity.sub(maxOraclePriceAge)) <= timestamp;
}
function canResolve() public view returns (bool) {
if (customMarket) {
return !resolved && _matured() && iOracleInstance.resolvable();
} else {
(, uint updatedAt) = _oraclePriceAndTimestamp();
return !resolved && _matured() && _isFreshPriceUpdateTime(updatedAt);
}
}
function _result() internal view returns (Side) {
if (customMarket) {
return iOracleInstance.getOutcome() ? Side.Long : Side.Short;
} else {
uint price;
if (resolved) {
price = oracleDetails.finalPrice;
} else {
(price, ) = _oraclePriceAndTimestamp();
}
return oracleDetails.strikePrice <= price ? Side.Long : Side.Short;
}
}
function result() external view returns (Side) {
return _result();
}
/* ---------- Option Balances and Mints ---------- */
function _balancesOf(address account) internal view returns (uint long, uint short) {
return (options.long.balanceOf(account), options.short.balanceOf(account));
}
function balancesOf(address account) external view returns (uint long, uint short) {
return _balancesOf(account);
}
function totalSupplies() external view returns (uint long, uint short) {
return (options.long.totalSupply(), options.short.totalSupply());
}
/* ---------- Utilities ---------- */
function _incrementDeposited(uint value) internal returns (uint _deposited) {
_deposited = deposited.add(value);
deposited = _deposited;
_manager().incrementTotalDeposited(value);
}
function _decrementDeposited(uint value) internal returns (uint _deposited) {
_deposited = deposited.sub(value);
deposited = _deposited;
_manager().decrementTotalDeposited(value);
}
function _requireManagerNotPaused() internal view {
require(!_manager().paused(), "This action cannot be performed while the contract is paused");
}
function requireUnpaused() external view {
_requireManagerNotPaused();
}
/* ========== MUTATIVE FUNCTIONS ========== */
/* ---------- Minting ---------- */
function mint(uint value) external duringMinting {
if (value == 0) {
return;
}
uint valueAfterFees = value.multiplyDecimalRound(_feeMultiplier);
uint deductedFees = value.sub(valueAfterFees);
accumulatedFees = accumulatedFees.add(deductedFees);
_mint(msg.sender, valueAfterFees);
_incrementDeposited(value);
_manager().transferSusdTo(msg.sender, address(this), value);
}
function _mint(address minter, uint amount) internal {
options.long.mint(minter, amount);
options.short.mint(minter, amount);
emit Mint(Side.Long, minter, amount);
emit Mint(Side.Short, minter, amount);
}
/* ---------- Custom oracle configuration ---------- */
function setIOracleInstance(address _address) external onlyOwner {}
/* ---------- Market Resolution ---------- */
function resolve() external onlyOwner afterMaturity managerNotPaused {
require(canResolve(), "Can not resolve market");
(uint price, uint updatedAt) = _oraclePriceAndTimestamp();
if (!customMarket) {
oracleDetails.finalPrice = price;
}
resolved = true;
// Now remit any collected fees.
// Since the constructor enforces that creatorFee + poolFee < 1, the balance
// in the contract will be sufficient to cover these transfers.
IERC20 sUSD = _sUSD();
uint totalFeesRatio = fees.poolFee.add(fees.creatorFee);
uint poolFeesRatio = fees.poolFee.divideDecimalRound(totalFeesRatio);
uint poolFees = poolFeesRatio.multiplyDecimalRound(accumulatedFees);
uint creatorFees = accumulatedFees.sub(poolFees);
_decrementDeposited(creatorFees.add(poolFees));
sUSD.transfer(_manager().feeAddress(), poolFees);
sUSD.transfer(creator, creatorFees);
emit MarketResolved(_result(), price, updatedAt, deposited, poolFees, creatorFees);
}
/* ---------- Claiming and Exercising Options ---------- */
function exerciseOptions() external afterMaturity returns (uint) {
// The market must be resolved if it has not been.
// the first one to exercise pays the gas fees. Might be worth splitting it up.
if (!resolved) {
_manager().resolveMarket(address(this));
}
// If the account holds no options, revert.
(uint longBalance, uint shortBalance) = _balancesOf(msg.sender);
require(longBalance != 0 || shortBalance != 0, "Nothing to exercise");
// Each option only needs to be exercised if the account holds any of it.
if (longBalance != 0) {
options.long.exercise(msg.sender);
}
if (shortBalance != 0) {
options.short.exercise(msg.sender);
}
// Only pay out the side that won.
uint payout = (_result() == Side.Long) ? longBalance : shortBalance;
emit OptionsExercised(msg.sender, payout);
if (payout != 0) {
_decrementDeposited(payout);
_sUSD().transfer(msg.sender, payout);
}
return payout;
}
/* ---------- Market Expiry ---------- */
function _selfDestruct(address payable beneficiary) internal {
uint _deposited = deposited;
if (_deposited != 0) {
_decrementDeposited(_deposited);
}
// Transfer the balance rather than the deposit value in case there are any synths left over
// from direct transfers.
IERC20 sUSD = _sUSD();
uint balance = sUSD.balanceOf(address(this));
if (balance != 0) {
sUSD.transfer(beneficiary, balance);
}
// Destroy the option tokens before destroying the market itself.
options.long.expire(beneficiary);
options.short.expire(beneficiary);
selfdestruct(beneficiary);
}
function expire(address payable beneficiary) external onlyOwner {
require(_expired(), "Unexpired options remaining");
_selfDestruct(beneficiary);
}
/* ========== MODIFIERS ========== */
modifier duringMinting() {
require(!_matured(), "Minting inactive");
_;
}
modifier afterMaturity() {
require(_matured(), "Not yet mature");
_;
}
modifier managerNotPaused() {
_requireManagerNotPaused();
_;
}
/* ========== EVENTS ========== */
event Mint(Side side, address indexed account, uint value);
event MarketResolved(
Side result,
uint oraclePrice,
uint oracleTimestamp,
uint deposited,
uint poolFees,
uint creatorFees
);
event OptionsExercised(address indexed account, uint value);
}pragma solidity >=0.4.24;
import "../interfaces/IBinaryOptionMarketManager.sol";
import "../interfaces/IBinaryOption.sol";
interface IBinaryOptionMarket {
/* ========== TYPES ========== */
enum Phase {Trading, Maturity, Expiry}
enum Side {Long, Short}
/* ========== VIEWS / VARIABLES ========== */
function options() external view returns (IBinaryOption long, IBinaryOption short);
function times()
external
view
returns (
uint maturity,
uint destructino
);
function oracleDetails()
external
view
returns (
bytes32 key,
uint strikePrice,
uint finalPrice
);
function fees()
external
view
returns (
uint poolFee,
uint creatorFee
);
function deposited() external view returns (uint);
function accumulatedFees() external view returns (uint);
function creator() external view returns (address);
function resolved() external view returns (bool);
function phase() external view returns (Phase);
function oraclePriceAndTimestamp() external view returns (uint price, uint updatedAt);
function canResolve() external view returns (bool);
function result() external view returns (Side);
function balancesOf(address account) external view returns (uint long, uint short);
function totalSupplies() external view returns (uint long, uint short);
/* ========== MUTATIVE FUNCTIONS ========== */
function mint(uint value) external;
function exerciseOptions() external returns (uint);
}pragma solidity >=0.4.24;
import "../interfaces/IBinaryOptionMarket.sol";
interface IBinaryOptionMarketManager {
/* ========== VIEWS / VARIABLES ========== */
function fees() external view returns (uint poolFee, uint creatorFee);
function durations()
external
view
returns (
uint maxOraclePriceAge,
uint expiryDuration,
uint maxTimeToMaturity
);
function capitalRequirement() external view returns (uint);
function marketCreationEnabled() external view returns (bool);
function totalDeposited() external view returns (uint);
function numActiveMarkets() external view returns (uint);
function activeMarkets(uint index, uint pageSize) external view returns (address[] memory);
function numMaturedMarkets() external view returns (uint);
function maturedMarkets(uint index, uint pageSize) external view returns (address[] memory);
/* ========== MUTATIVE FUNCTIONS ========== */
function createMarket(
bytes32 oracleKey,
uint strikePrice,
uint maturity,
uint initialMint, // initial sUSD to mint options for,
bool customMarket,
address customOracle
) external returns (IBinaryOptionMarket);
function resolveMarket(address market) external;
function expireMarkets(address[] calldata market) external;
function transferSusdTo(
address sender,
address receiver,
uint amount
) external;
}pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}pragma solidity ^0.5.16;
// https://docs.synthetix.io/contracts/source/contracts/minimalproxyfactory
contract MinimalProxyFactory {
function _cloneAsMinimalProxy(address _base, string memory _revertMsg) internal returns (address clone) {
bytes memory createData = _generateMinimalProxyCreateData(_base);
assembly {
clone := create(
0, // no value
add(createData, 0x20), // data
55 // data is always 55 bytes (10 constructor + 45 code)
)
}
// If CREATE fails for some reason, address(0) is returned
require(clone != address(0), _revertMsg);
}
function _generateMinimalProxyCreateData(address _base) internal pure returns (bytes memory) {
return
abi.encodePacked(
//---- constructor -----
bytes10(0x3d602d80600a3d3981f3),
//---- proxy code -----
bytes10(0x363d3d373d3d3d363d73),
_base,
bytes15(0x5af43d82803e903d91602b57fd5bf3)
);
}
}pragma solidity ^0.5.16;
contract OwnedWithInit {
address public owner;
address public nominatedOwner;
constructor() public {}
function initOwner(address _owner) internal {
require(owner == address(0), "Init can only be called when owner is 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}pragma solidity >=0.4.24;
import "../interfaces/IBinaryOptionMarket.sol";
interface IOracleInstance {
/* ========== VIEWS / VARIABLES ========== */
function getOutcome() external view returns (bool);
function resolvable() external view returns (bool);
function targetName() external view returns (string memory);
function targetOutcome() external view returns (string memory);
function eventName() external view returns (string memory);
/* ========== MUTATIVE FUNCTIONS ========== */
}pragma solidity ^0.5.16;
// Inheritance
import "./interfaces/IBinaryOptionMarketManager.sol";
import "synthetix-2.43.1/contracts/Owned.sol";
import "synthetix-2.43.1/contracts/Pausable.sol";
// Libraries
import "synthetix-2.43.1/contracts/AddressSetLib.sol";
import "synthetix-2.43.1/contracts/SafeDecimalMath.sol";
// Internal references
import "./BinaryOptionMarketFactory.sol";
import "./BinaryOptionMarket.sol";
import "./BinaryOption.sol";
import "./interfaces/IBinaryOptionMarket.sol";
import "synthetix-2.43.1/contracts/interfaces/IExchangeRates.sol";
import "synthetix-2.43.1/contracts/interfaces/IERC20.sol";
import "synthetix-2.43.1/contracts/interfaces/IAddressResolver.sol";
contract BinaryOptionMarketManager is Owned, Pausable, IBinaryOptionMarketManager {
/* ========== LIBRARIES ========== */
using SafeMath for uint;
using AddressSetLib for AddressSetLib.AddressSet;
/* ========== TYPES ========== */
struct Fees {
uint poolFee;
uint creatorFee;
}
struct Durations {
uint maxOraclePriceAge;
uint expiryDuration;
uint maxTimeToMaturity;
}
/* ========== STATE VARIABLES ========== */
address public feeAddress;
Fees public fees;
Durations public durations;
uint public capitalRequirement;
bool public marketCreationEnabled = true;
bool public customMarketCreationEnabled = false;
uint public totalDeposited;
AddressSetLib.AddressSet internal _activeMarkets;
AddressSetLib.AddressSet internal _maturedMarkets;
BinaryOptionMarketManager internal _migratingManager;
IAddressResolver public resolver;
address public binaryOptionMarketFactory;
/* ---------- Address Resolver Configuration ---------- */
bytes32 internal constant CONTRACT_SYNTHSUSD = "SynthsUSD";
bytes32 internal constant CONTRACT_EXRATES = "ExchangeRates";
/* ========== CONSTRUCTOR ========== */
constructor(
address _owner,
IAddressResolver _resolver,
uint _maxOraclePriceAge,
uint _expiryDuration,
uint _maxTimeToMaturity,
uint _creatorCapitalRequirement,
uint _poolFee,
uint _creatorFee,
address _feeAddress
) public Owned(_owner) Pausable() {
resolver = _resolver;
// Temporarily change the owner so that the setters don't revert.
owner = msg.sender;
setFeeAddress(_feeAddress);
setExpiryDuration(_expiryDuration);
setMaxOraclePriceAge(_maxOraclePriceAge);
setMaxTimeToMaturity(_maxTimeToMaturity);
setCreatorCapitalRequirement(_creatorCapitalRequirement);
setPoolFee(_poolFee);
setCreatorFee(_creatorFee);
owner = _owner;
}
/* ========== SETTERS ========== */
function setBinaryOptionsMarketFactory(address _binaryOptionMarketFactory) external onlyOwner {
binaryOptionMarketFactory = _binaryOptionMarketFactory;
}
function setFeeAddress(address _feeAddress) public onlyOwner {
feeAddress = _feeAddress;
}
/* ========== VIEWS ========== */
/* ---------- Related Contracts ---------- */
function _sUSD() internal view returns (IERC20) {
return IERC20(resolver.requireAndGetAddress(CONTRACT_SYNTHSUSD, "Synth sUSD contract not found"));
}
function _exchangeRates() internal view returns (IExchangeRates) {
return IExchangeRates(resolver.requireAndGetAddress(CONTRACT_EXRATES, "ExchangeRates contract not found"));
}
/* ---------- Market Information ---------- */
function _isKnownMarket(address candidate) internal view returns (bool) {
return _activeMarkets.contains(candidate) || _maturedMarkets.contains(candidate);
}
function numActiveMarkets() external view returns (uint) {
return _activeMarkets.elements.length;
}
function activeMarkets(uint index, uint pageSize) external view returns (address[] memory) {
return _activeMarkets.getPage(index, pageSize);
}
function numMaturedMarkets() external view returns (uint) {
return _maturedMarkets.elements.length;
}
function maturedMarkets(uint index, uint pageSize) external view returns (address[] memory) {
return _maturedMarkets.getPage(index, pageSize);
}
function _isValidKey(bytes32 oracleKey) internal view returns (bool) {
IExchangeRates exchangeRates = _exchangeRates();
// If it has a rate, then it's possibly a valid key
if (exchangeRates.rateForCurrency(oracleKey) != 0) {
// But not sUSD
if (oracleKey == "sUSD") {
return false;
}
// and not inverse rates
(uint entryPoint, , , , ) = exchangeRates.inversePricing(oracleKey);
if (entryPoint != 0) {
return false;
}
return true;
}
return false;
}
/* ========== MUTATIVE FUNCTIONS ========== */
/* ---------- Setters ---------- */
function setMaxOraclePriceAge(uint _maxOraclePriceAge) public onlyOwner {
durations.maxOraclePriceAge = _maxOraclePriceAge;
emit MaxOraclePriceAgeUpdated(_maxOraclePriceAge);
}
function setExpiryDuration(uint _expiryDuration) public onlyOwner {
durations.expiryDuration = _expiryDuration;
emit ExpiryDurationUpdated(_expiryDuration);
}
function setMaxTimeToMaturity(uint _maxTimeToMaturity) public onlyOwner {
durations.maxTimeToMaturity = _maxTimeToMaturity;
emit MaxTimeToMaturityUpdated(_maxTimeToMaturity);
}
function setPoolFee(uint _poolFee) public onlyOwner {
uint totalFee = _poolFee + fees.creatorFee;
require(totalFee < SafeDecimalMath.unit(), "Total fee must be less than 100%.");
require(0 < totalFee, "Total fee must be nonzero.");
fees.poolFee = _poolFee;
emit PoolFeeUpdated(_poolFee);
}
function setCreatorFee(uint _creatorFee) public onlyOwner {
uint totalFee = _creatorFee + fees.poolFee;
require(totalFee < SafeDecimalMath.unit(), "Total fee must be less than 100%.");
require(0 < totalFee, "Total fee must be nonzero.");
fees.creatorFee = _creatorFee;
emit CreatorFeeUpdated(_creatorFee);
}
function setCreatorCapitalRequirement(uint _creatorCapitalRequirement) public onlyOwner {
capitalRequirement = _creatorCapitalRequirement;
emit CreatorCapitalRequirementUpdated(_creatorCapitalRequirement);
}
/* ---------- Deposit Management ---------- */
function incrementTotalDeposited(uint delta) external onlyActiveMarkets notPaused {
totalDeposited = totalDeposited.add(delta);
}
function decrementTotalDeposited(uint delta) external onlyKnownMarkets notPaused {
// NOTE: As individual market debt is not tracked here, the underlying markets
// need to be careful never to subtract more debt than they added.
// This can't be enforced without additional state/communication overhead.
totalDeposited = totalDeposited.sub(delta);
}
/* ---------- Market Lifecycle ---------- */
function createMarket(
bytes32 oracleKey,
uint strikePrice,
uint maturity,
uint initialMint, // initial sUSD to mint options for,
bool customMarket,
address customOracle
)
external
notPaused
returns (
IBinaryOptionMarket // no support for returning BinaryOptionMarket polymorphically given the interface
)
{
require(marketCreationEnabled, "Market creation is disabled");
if (!customMarket) {
require(_isValidKey(oracleKey), "Invalid key");
} else {
if (!customMarketCreationEnabled) {
require(owner == msg.sender, "Only owner can create custom markets");
}
require(address(0) != customOracle, "Invalid custom oracle");
}
require(maturity <= block.timestamp + durations.maxTimeToMaturity, "Maturity too far in the future");
uint expiry = maturity.add(durations.expiryDuration);
require(block.timestamp < maturity, "Maturity has to be in the future");
// We also require maturity < expiry. But there is no need to check this.
// Fees being in range are checked in the setters.
// The market itself validates the capital and skew requirements.
require(capitalRequirement <= initialMint, "Insufficient capital");
BinaryOptionMarket market =
BinaryOptionMarketFactory(binaryOptionMarketFactory).createMarket(
msg.sender,
resolver,
oracleKey,
strikePrice,
[maturity, expiry],
initialMint,
[fees.poolFee, fees.creatorFee],
customMarket,
customOracle
);
_activeMarkets.add(address(market));
// The debt can't be incremented in the new market's constructor because until construction is complete,
// the manager doesn't know its address in order to grant it permission.
totalDeposited = totalDeposited.add(initialMint);
_sUSD().transferFrom(msg.sender, address(market), initialMint);
(BinaryOption long, BinaryOption short) = market.options();
emit MarketCreated(
address(market),
msg.sender,
oracleKey,
strikePrice,
maturity,
expiry,
address(long),
address(short),
customMarket,
customOracle
);
return market;
}
function transferSusdTo(
address sender,
address receiver,
uint amount
) external {
//only to be called by markets themselves
require(_isKnownMarket(address(msg.sender)), "Market unknown.");
_sUSD().transferFrom(sender, receiver, amount);
}
function resolveMarket(address market) external {
require(_activeMarkets.contains(market), "Not an active market");
BinaryOptionMarket(market).resolve();
_activeMarkets.remove(market);
_maturedMarkets.add(market);
}
function expireMarkets(address[] calldata markets) external notPaused onlyOwner {
for (uint i = 0; i < markets.length; i++) {
address market = markets[i];
require(_isKnownMarket(address(market)), "Market unknown.");
// The market itself handles decrementing the total deposits.
BinaryOptionMarket(market).expire(msg.sender);
// Note that we required that the market is known, which guarantees
// its index is defined and that the list of markets is not empty.
_maturedMarkets.remove(market);
emit MarketExpired(market);
}
}
function setMarketCreationEnabled(bool enabled) public onlyOwner {
if (enabled != marketCreationEnabled) {
marketCreationEnabled = enabled;
emit MarketCreationEnabledUpdated(enabled);
}
}
function setCustomMarketCreationEnabled(bool enabled) public onlyOwner {
customMarketCreationEnabled = enabled;
}
function setMigratingManager(BinaryOptionMarketManager manager) public onlyOwner {
_migratingManager = manager;
}
function migrateMarkets(
BinaryOptionMarketManager receivingManager,
bool active,
BinaryOptionMarket[] calldata marketsToMigrate
) external onlyOwner {
require(address(receivingManager) != address(this), "Can't migrate to self");
uint _numMarkets = marketsToMigrate.length;
if (_numMarkets == 0) {
return;
}
AddressSetLib.AddressSet storage markets = active ? _activeMarkets : _maturedMarkets;
uint runningDepositTotal;
for (uint i; i < _numMarkets; i++) {
BinaryOptionMarket market = marketsToMigrate[i];
require(_isKnownMarket(address(market)), "Market unknown.");
// Remove it from our list and deposit total.
markets.remove(address(market));
runningDepositTotal = runningDepositTotal.add(market.deposited());
// Prepare to transfer ownership to the new manager.
market.nominateNewOwner(address(receivingManager));
}
// Deduct the total deposits of the migrated markets.
totalDeposited = totalDeposited.sub(runningDepositTotal);
emit MarketsMigrated(receivingManager, marketsToMigrate);
// Now actually transfer the markets over to the new manager.
receivingManager.receiveMarkets(active, marketsToMigrate);
}
function receiveMarkets(bool active, BinaryOptionMarket[] calldata marketsToReceive) external {
require(msg.sender == address(_migratingManager), "Only permitted for migrating manager.");
uint _numMarkets = marketsToReceive.length;
if (_numMarkets == 0) {
return;
}
AddressSetLib.AddressSet storage markets = active ? _activeMarkets : _maturedMarkets;
uint runningDepositTotal;
for (uint i; i < _numMarkets; i++) {
BinaryOptionMarket market = marketsToReceive[i];
require(!_isKnownMarket(address(market)), "Market already known.");
market.acceptOwnership();
markets.add(address(market));
// Update the market with the new manager address,
runningDepositTotal = runningDepositTotal.add(market.deposited());
}
totalDeposited = totalDeposited.add(runningDepositTotal);
emit MarketsReceived(_migratingManager, marketsToReceive);
}
/* ========== MODIFIERS ========== */
modifier onlyActiveMarkets() {
require(_activeMarkets.contains(msg.sender), "Permitted only for active markets.");
_;
}
modifier onlyKnownMarkets() {
require(_isKnownMarket(msg.sender), "Permitted only for known markets.");
_;
}
/* ========== EVENTS ========== */
event MarketCreated(
address market,
address indexed creator,
bytes32 indexed oracleKey,
uint strikePrice,
uint maturityDate,
uint expiryDate,
address long,
address short,
bool customMarket,
address customOracle
);
event MarketExpired(address market);
event MarketsMigrated(BinaryOptionMarketManager receivingManager, BinaryOptionMarket[] markets);
event MarketsReceived(BinaryOptionMarketManager migratingManager, BinaryOptionMarket[] markets);
event MarketCreationEnabledUpdated(bool enabled);
event MaxOraclePriceAgeUpdated(uint duration);
event ExpiryDurationUpdated(uint duration);
event MaxTimeToMaturityUpdated(uint duration);
event CreatorCapitalRequirementUpdated(uint value);
event PoolFeeUpdated(uint fee);
event CreatorFeeUpdated(uint fee);
}pragma solidity >=0.4.24;
// https://docs.synthetix.io/contracts/source/interfaces/iexchangerates
interface IExchangeRates {
// Structs
struct RateAndUpdatedTime {
uint216 rate;
uint40 time;
}
struct InversePricing {
uint entryPoint;
uint upperLimit;
uint lowerLimit;
bool frozenAtUpperLimit;
bool frozenAtLowerLimit;
}
// Views
function aggregators(bytes32 currencyKey) external view returns (address);
function aggregatorWarningFlags() external view returns (address);
function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool);
function canFreezeRate(bytes32 currencyKey) external view returns (bool);
function currentRoundForRate(bytes32 currencyKey) external view returns (uint);
function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory);
function effectiveValue(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
) external view returns (uint value);
function effectiveValueAndRates(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey
)
external
view
returns (
uint value,
uint sourceRate,
uint destinationRate
);
function effectiveValueAtRound(
bytes32 sourceCurrencyKey,
uint sourceAmount,
bytes32 destinationCurrencyKey,
uint roundIdForSrc,
uint roundIdForDest
) external view returns (uint value);
function getCurrentRoundId(bytes32 currencyKey) external view returns (uint);
function getLastRoundIdBeforeElapsedSecs(
bytes32 currencyKey,
uint startingRoundId,
uint startingTimestamp,
uint timediff
) external view returns (uint);
function inversePricing(bytes32 currencyKey)
external
view
returns (
uint entryPoint,
uint upperLimit,
uint lowerLimit,
bool frozenAtUpperLimit,
bool frozenAtLowerLimit
);
function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256);
function oracle() external view returns (address);
function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time);
function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time);
function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid);
function rateForCurrency(bytes32 currencyKey) external view returns (uint);
function rateIsFlagged(bytes32 currencyKey) external view returns (bool);
function rateIsFrozen(bytes32 currencyKey) external view returns (bool);
function rateIsInvalid(bytes32 currencyKey) external view returns (bool);
function rateIsStale(bytes32 currencyKey) external view returns (bool);
function rateStalePeriod() external view returns (uint);
function ratesAndUpdatedTimeForCurrencyLastNRounds(bytes32 currencyKey, uint numRounds)
external
view
returns (uint[] memory rates, uint[] memory times);
function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys)
external
view
returns (uint[] memory rates, bool anyRateInvalid);
function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory);
// Mutative functions
function freezeRate(bytes32 currencyKey) external;
}pragma solidity >=0.4.24;
// https://docs.synthetix.io/contracts/source/interfaces/iaddressresolver
interface IAddressResolver {
function getAddress(bytes32 name) external view returns (address);
function getSynth(bytes32 key) external view returns (address);
function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address);
}pragma solidity ^0.5.16;
// https://docs.synthetix.io/contracts/source/contracts/owned
contract Owned {
address public owner;
address public nominatedOwner;
constructor(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}pragma solidity ^0.5.16;
// Inheritance
import "./Owned.sol";
// https://docs.synthetix.io/contracts/source/contracts/pausable
contract Pausable is Owned {
uint public lastPauseTime;
bool public paused;
constructor() internal {
// This contract is abstract, and thus cannot be instantiated directly
require(owner != address(0), "Owner must be set");
// Paused will be false, and lastPauseTime will be 0 upon initialisation
}
/**
* @notice Change the paused state of the contract
* @dev Only the contract owner may call this.
*/
function setPaused(bool _paused) external onlyOwner {
// Ensure we're actually changing the state before we do anything
if (_paused == paused) {
return;
}
// Set our paused state.
paused = _paused;
// If applicable, set the last pause time.
if (paused) {
lastPauseTime = now;
}
// Let everyone know that our pause state has changed.
emit PauseChanged(paused);
}
event PauseChanged(bool isPaused);
modifier notPaused {
require(!paused, "This action cannot be performed while the contract is paused");
_;
}
}pragma solidity ^0.5.16;
// https://docs.synthetix.io/contracts/source/libraries/addresssetlib/
library AddressSetLib {
struct AddressSet {
address[] elements;
mapping(address => uint) indices;
}
function contains(AddressSet storage set, address candidate) internal view returns (bool) {
if (set.elements.length == 0) {
return false;
}
uint index = set.indices[candidate];
return index != 0 || set.elements[0] == candidate;
}
function getPage(
AddressSet storage set,
uint index,
uint pageSize
) internal view returns (address[] memory) {
// NOTE: This implementation should be converted to slice operators if the compiler is updated to v0.6.0+
uint endIndex = index + pageSize; // The check below that endIndex <= index handles overflow.
// If the page extends past the end of the list, truncate it.
if (endIndex > set.elements.length) {
endIndex = set.elements.length;
}
if (endIndex <= index) {
return new address[](0);
}
uint n = endIndex - index; // We already checked for negative overflow.
address[] memory page = new address[](n);
for (uint i; i < n; i++) {
page[i] = set.elements[i + index];
}
return page;
}
function add(AddressSet storage set, address element) internal {
// Adding to a set is an idempotent operation.
if (!contains(set, element)) {
set.indices[element] = set.elements.length;
set.elements.push(element);
}
}
function remove(AddressSet storage set, address element) internal {
require(contains(set, element), "Element not in set.");
// Replace the removed element with the last element of the list.
uint index = set.indices[element];
uint lastIndex = set.elements.length - 1; // We required that element is in the list, so it is not empty.
if (index != lastIndex) {
// No need to shift the last element if it is the one we want to delete.
address shiftedElement = set.elements[lastIndex];
set.elements[index] = shiftedElement;
set.indices[shiftedElement] = index;
}
set.elements.pop();
delete set.indices[element];
}
}pragma solidity ^0.5.16;
// Inheritance
import "synthetix-2.43.1/contracts/MinimalProxyFactory.sol";
import "synthetix-2.43.1/contracts/Owned.sol";
// Internal references
import "./BinaryOptionMarket.sol";
import "synthetix-2.43.1/contracts/interfaces/IAddressResolver.sol";
contract BinaryOptionMarketFactory is MinimalProxyFactory, Owned {
/* ========== STATE VARIABLES ========== */
address public binaryOptionMarketManager;
address public binaryOptionMarketMastercopy;
address public binaryOptionMastercopy;
/* ========== CONSTRUCTOR ========== */
constructor(address _owner) public MinimalProxyFactory() Owned(_owner) {}
/* ========== MUTATIVE FUNCTIONS ========== */
function createMarket(
address creator,
IAddressResolver _resolver,
bytes32 oracleKey,
uint strikePrice,
uint[2] calldata times, // [maturity, expiry]
uint initialMint,
uint[2] calldata fees, // [poolFee, creatorFee]
bool customMarket,
address customOracle
) external returns (BinaryOptionMarket) {
require(binaryOptionMarketManager == msg.sender, "Only permitted by the manager.");
BinaryOptionMarket bom =
BinaryOptionMarket(
_cloneAsMinimalProxy(binaryOptionMarketMastercopy, "Could not create a Binary Option Market")
);
bom.initialize(
binaryOptionMarketManager,
binaryOptionMastercopy,
_resolver,
creator,
oracleKey,
strikePrice,
times,
initialMint,
fees,
customMarket,
customOracle
);
return bom;
}
/* ========== SETTERS ========== */
function setBinaryOptionMarketManager(address _binaryOptionMarketManager) external onlyOwner {
binaryOptionMarketManager = _binaryOptionMarketManager;
emit BinaryOptionMarketManagerChanged(_binaryOptionMarketManager);
}
function setBinaryOptionMarketMastercopy(address _binaryOptionMarketMastercopy) external onlyOwner {
binaryOptionMarketMastercopy = _binaryOptionMarketMastercopy;
emit BinaryOptionMarketMastercopyChanged(_binaryOptionMarketMastercopy);
}
function setBinaryOptionMastercopy(address _binaryOptionMastercopy) external onlyOwner {
binaryOptionMastercopy = _binaryOptionMastercopy;
emit BinaryOptionMastercopyChanged(_binaryOptionMastercopy);
}
event BinaryOptionMarketManagerChanged(address _binaryOptionMarketManager);
event BinaryOptionMarketMastercopyChanged(address _binaryOptionMarketMastercopy);
event BinaryOptionMastercopyChanged(address _binaryOptionMastercopy);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Issued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"claimant","type":"address"}],"name":"exercise","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"beneficiary","type":"address"}],"name":"expire","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"market","outputs":[{"internalType":"contract BinaryOptionMarket","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.